hashmap.c

Go to the documentation of this file.
00001 /***************************************************************************/
00007 #include "hashmap.h"
00008 
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <assert.h>
00013 
00014 /* *************************************************************** structures */
00015 
00018 typedef struct
00019 {
00020     char* key;  
00021     void* data; 
00022 } hashmapEntry;
00023 
00026 struct sHashmap
00027 {
00028     hashmapEntry* array; 
00029     size_t size,         
00030            count;        
00031 };
00032 
00033 /* ******************************************************** private functions */
00034 
00037 static void rehash(hashmap* map);
00038 
00045 static int insert(hashmap* map, void* data, char* key);
00046 
00050 static hashmapEntry* find(const hashmap* map, const char* key);
00051 
00055 static int compare(const hashmapEntry* lhs, const hashmapEntry* rhs);
00056 
00059 static unsigned long hash1(const char* rawKey)
00060 {
00061     const unsigned char* s = (const unsigned char*) rawKey;
00062     unsigned long hash = 0;
00063     
00064     do
00065     {
00066         hash = *s + (hash << 6) + (hash << 16) - hash;
00067     }
00068     while (*++s);
00069     
00070     return hash;
00071 }
00072 
00075 static unsigned long hash2(const char* rawKey)
00076 {
00077     const unsigned char* s = (const unsigned char*) rawKey;
00078     unsigned long hash = 0;
00079     
00080     do
00081     {
00082         hash ^= (unsigned long) *s;
00083         hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
00084     }
00085     while (*++s);
00086     
00087     return hash;
00088 }
00089 
00090 static void rehash(hashmap* map)
00091 {
00092     size_t size;
00093     hashmapEntry* array = map->array;
00094     
00095     /* double the size of the array */
00096     size = ++map->size;
00097     map->size <<= 1;
00098     map->array = (hashmapEntry*) calloc(sizeof(hashmapEntry), map->size);
00099     --map->size;
00100     map->count = 0;
00101     
00102     /* re-insert all elements */
00103     do
00104     {
00105         --size;
00106         if (array[size].key)
00107             insert(map, array[size].data, array[size].key);
00108     }
00109     while (size);
00110     
00111     /* return unused memory */
00112     free(array);
00113 }
00114 
00115 static hashmapEntry* find(const hashmap* map, const char* key)
00116 {
00117     unsigned long index, step, initialIndex;
00118     hashmapEntry* freeEntry = 0;
00119     
00120     initialIndex = index = hash1(key) & map->size;
00121     
00122     /* first try */
00123     if (map->array[index].key)
00124     {
00125         if (!strcmp(map->array[index].key, key))
00126             return &map->array[index];
00127     }
00128     else if (!map->array[index].data)
00129     {
00130         return &map->array[index];
00131     }
00132     else
00133     {
00134         freeEntry = &map->array[index];
00135     }
00136     
00137     /* collision */
00138     step = (hash2(key) % map->size) + 1;
00139     
00140     do
00141     {
00142         index = (index + step) & map->size;
00143         
00144         if (map->array[index].key)
00145         {
00146             if (!strcmp(map->array[index].key, key))
00147                 return &map->array[index];
00148         }
00149         else if (!map->array[index].data)
00150         {
00151             return (freeEntry) ? freeEntry : &map->array[index];
00152         }
00153         else if (!freeEntry)
00154         {
00155             freeEntry = &map->array[index];
00156         }
00157     }
00158     while (index != initialIndex);
00159     
00160     return freeEntry;
00161 }
00162 
00163 static int insert(hashmap* map, void* data, char* key)
00164 {
00165     hashmapEntry* entry;
00166     
00167     if (map->size == map->count)
00168         rehash(map);
00169     
00170     do
00171     {
00172         entry = find(map, key);
00173         
00174         if (entry)
00175         {
00176             entry->data = data;
00177             
00178             if (entry->key)
00179             {
00180                 /* updated the entry */
00181                 free(key);
00182                 return HASHMAP_UPDATE;
00183             }
00184             else
00185             {
00186                 /* inserted the entry */
00187                 ++map->count;
00188                 entry->key = key;
00189                 return HASHMAP_INSERT;
00190             }
00191         }
00192         
00193         rehash(map);
00194     }
00195     while (1);
00196 }
00197 
00198 static int compare(const hashmapEntry* lhs, const hashmapEntry* rhs)
00199 {
00200     return (lhs->key)  ? (rhs->key) ? strcmp(lhs->key, rhs->key) : -1
00201                        : (rhs->key) ? 1 : 0;
00202 }
00203 
00204 /* ******************************************************* exported functions */
00205 
00206 hashmap* newHashmap(unsigned int hint)
00207 {
00208     hashmap* map = (hashmap*) malloc(sizeof(hashmap));
00209     
00210     if (hint < 4)
00211     {
00212         hint = 4;
00213     }
00214     else if (hint & (hint - 1))
00215     {
00216         unsigned int i = 1;
00217         
00218         do
00219         {
00220             hint |= (hint >> i);
00221             i <<= 1;
00222         }
00223         while (i <= (sizeof(hint) << 2));
00224         ++hint;
00225     }
00226     
00227     map->array = (hashmapEntry*) calloc(sizeof(hashmapEntry), hint);
00228     map->size = hint - 1;
00229     map->count = 0;
00230     
00231     return map;
00232 }
00233 
00234 void deleteHashmap(hashmap* map)
00235 {
00236     unsigned long index = 0;
00237     
00238     assert(map);
00239     
00240     do
00241     {
00242         if (map->array[index].key)
00243             free(map->array[index].key);
00244     }
00245     while (++index <= map->size);
00246 
00247     free(map->array);
00248     free(map);
00249 }
00250 
00251 int hashmapSet(hashmap* map, void* data, const char* key)
00252 {
00253     return (map && key && *key)  ? insert(map, data, strdup(key))
00254                                  : HASHMAP_ILLEGAL;
00255 }
00256 
00257 void* hashmapGet(const hashmap* map, const char* key)
00258 {
00259     hashmapEntry* entry;
00260     assert(map && key && *key);
00261     
00262     entry = find(map, key);
00263     
00264     if (entry && entry->key)
00265         return entry->data;
00266     
00267     return 0;
00268 }
00269 
00270 void* hashmapRemove(hashmap* map, const char* key)
00271 {
00272     void* res = 0;
00273     hashmapEntry* entry;
00274     
00275     assert(map && key && *key);
00276     
00277     entry = find(map, key);
00278     
00279     if (entry && entry->key)
00280     {
00281         --map->count;
00282         
00283         free(entry->key);
00284         entry->key = 0;
00285         res = entry->data;
00286         
00287         /* setting exist to one indicates that this entry was already in use */
00288         entry->data = (void*) 1;
00289     }
00290     
00291     return res;
00292 }
00293 
00294 void hashmapProcess(const hashmap* map, fHashmapProc proc)
00295 {
00296     hashmapEntry* array;
00297     size_t size;
00298     int i;
00299     
00300     assert(map);
00301     
00302     size = map->size + 1;
00303     array = (hashmapEntry*) malloc(sizeof(hashmapEntry) * size);
00304     
00305     memcpy(array, map->array, sizeof(hashmapEntry) * size);
00306     qsort(array, size, sizeof(hashmapEntry),
00307                 (int(*)(const void*, const void*)) compare);
00308     
00309     for (i = 0; i < map->count; ++i)
00310         proc(array[i].key, array[i].data);
00311     
00312     free(array);
00313 }
00314 

Generated on Fri Jun 5 15:31:57 2009 for DeadStrip Utility by  doxygen 1.5.8