#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hashmap.h"
static
int
hash(
int
h)
{
unsigned
int
x = h;
x ^= (x >> 20) ^ (x >> 12);
return
x ^ (x >> 7) ^ (x >> 4);
}
static
int
indexFor(
int
h,
int
length)
{
return
h & (length-1);
}
static
int
stringHashCode(
char
*pStr)
{
int
size =
strlen
(pStr);
if
(size == 0)
{
return
0;
}
else
{
int
i,h=0;
for
(i=0; i<size; i++)
{
h = 31 * h + *pStr;
pStr++;
}
return
h;
}
}
static
void
resize(HashMap
this
,
int
newCapacity)
{
int
oldCapacity =
this
->capacity;
Entry newTable =
malloc
(
sizeof
(
struct
_entry) * newCapacity);
int
i;
for
(i=0; i<newCapacity; i++)
{
(newTable + i)->next = NULL;
}
int
m,n;
for
(m=0; m<oldCapacity; m++)
{
Entry e = (
this
->table + m)->next;
if
(e!=NULL)
{
do
{
Entry next = e->next;
n = indexFor(e->hash,newCapacity);
e->next = (newTable + n)->next;
(newTable + n)->next = e;
e = next;
}
while
(e!=NULL);
}
}
this
->table = newTable;
this
->capacity = newCapacity;
this
->threshold = (
int
)(newCapacity *
this
->factor);
}
static
void
addEntry(HashMap
this
,
void
*k,
void
*v,
int
hashCode,
int
i)
{
Entry e =
this
->table + i;
do
{
if
(e->next == NULL)
{
Entry item =
malloc
(
sizeof
(
struct
_entry));
item->hash = hashCode;
item->key = k;
item->value = v;
item->next = NULL;
e->next = item;
break
;
}
}
while
((e = e->next) != NULL);
this
->size++;
if
(
this
->size >=
this
->threshold)
{
resize(
this
,2 *
this
->size);
}
}
void
*hashmap_init(
int
k_e,
int
v_e)
{
HashMap map =
malloc
(
sizeof
(
struct
_hashmap));
map->K_E = k_e;
map->V_E = v_e;
map->size = 0;
map->capacity = 16;
map->factor = 0.75f;
map->threshold = (
int
)(map->capacity * map->factor);
map->table =
malloc
(
sizeof
(
struct
_entry) * map->capacity);
int
i;
int
capacity = map->capacity;
for
(i=0; i<capacity; i++)
{
(map->table+i)->next = NULL;
}
return
map;
}
void
*hashmap_put(HashMap
this
,
void
*k,
void
*v)
{
int
hashCode;
if
(
this
->K_E == E_STRING)
{
hashCode = hash(stringHashCode(k));
}
else
if
(
this
->K_E == E_INT)
{
hashCode = hash(k);
}
else
{
hashCode = hash(k);
}
int
i = indexFor(hashCode,
this
->capacity);
Entry e;
if
(
this
->K_E == E_STRING ||
this
->K_E == E_INT)
{
for
(e =
this
->table + i,e=e->next; e!=NULL; e=e->next)
{
if
((e->hash == hashCode) && (e->key == k ||
strcmp
(e->key,k) == 0))
{
void
*oldValue = e->value;
e->value = v;
return
oldValue;
}
}
}
else
{
for
(e =
this
->table + i,e=e->next; e!=NULL; e=e->next)
{
if
((e->hash == hashCode) && e->key == k)
{
void
*oldValue = e->value;
e->value = v;
return
oldValue;
}
}
}
addEntry(
this
,k,v,hashCode,i);
return
NULL;
}
void
*hashmap_get(HashMap
this
,
void
*k)
{
int
hashCode;
if
(
this
->K_E == E_STRING)
{
hashCode = hash(stringHashCode(k));
}
else
if
(
this
->K_E == E_INT)
{
hashCode = hash(k);
}
else
{
hashCode = hash(k);
}
int
i = indexFor(hashCode,
this
->capacity);
Entry e;
if
(
this
->K_E == E_STRING ||
this
->K_E == E_INT)
{
for
(e=
this
->table + i,e=e->next; e!=NULL; e=e->next)
{
if
(e->hash == hashCode && (e->key == k ||
strcmp
(e->key,k) == 0))
{
return
e->value;
}
}
return
NULL;
}
else
{
for
(e=
this
->table + i,e=e->next; e!=NULL; e=e->next)
{
if
(e->hash == hashCode && e->key == k)
{
return
e->value;
}
}
return
NULL;
}
return
NULL;
}
void
*hashmap_remove(HashMap
this
,
void
*k)
{
int
hashCode;
if
(
this
->K_E == E_STRING)
{
hashCode = hash(stringHashCode(k));
}
else
if
(
this
->K_E == E_INT)
{
hashCode = hash(k);
}
else
{
hashCode = hash(k);
}
int
i = indexFor(hashCode,
this
->capacity);
Entry e;
Entry preE=NULL;
for
(e=
this
->table+i,preE=e,e=e->next; e!=NULL; preE=e,e=e->next)
{
if
(e->hash == hashCode && (e->key == k ||
strcmp
(e->key,k) == 0))
{
if
(e->next == NULL)
{
preE->next = NULL;
}
else
{
preE->next = e->next;
}
e->next = NULL;
this
->size--;
return
e->value;
}
}
return
NULL;
}
HashMapSet hashmap_keySet(HashMap
this
)
{
int
size =
this
->size;
if
(size == 0)
{
return
NULL;
}
else
{
HashMapSet set =
malloc
(
sizeof
(
struct
_hashmapset));
set->key = NULL;
set->next = NULL;
int
i;
Entry e;
HashMapSet preSet = set;
int
capacity =
this
->capacity;
for
(i=0; i<capacity; i++)
{
for
(e =
this
->table + i,e=e->next; e!=NULL; e=e->next)
{
if
(preSet->key == NULL)
{
preSet->key = e->key;
preSet->next = NULL;
}
else
{
HashMapSet item =
malloc
(
sizeof
(
struct
_hashmapset));
item->key = e->key;
item->next = NULL;
preSet->next = item;
preSet = item;
}
}
}
return
set;
}
}
void
hashmap_clear(HashMap
this
)
{
int
capacity =
this
->capacity;
int
i;
Entry e,item;
for
(i=0; i<capacity; i++)
{
for
(e =
this
->table + i,e=e->next; e!=NULL; item = e,e=e->next,
free
(item))
{
}
(
this
->table + i)->next = NULL;
}
this
->size = 0;
}
void
hashmap_free(HashMap
this
)
{
int
capacity =
this
->capacity;
Entry e,item;
int
i;
for
(i=0; i<capacity; i++)
{
for
(e=
this
->table + i, e=e->next; e!=NULL; item=e,e=e->next,
free
(item))
{
}
}
this
->capacity = 0;
this
->size = 0;
free
(
this
->table);
free
(
this
);
}