#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);
}