00001
00007 #include "hashmap.h"
00008
00009 #include <stdio.h>
00010 #include <string.h>
00011 #include <stdlib.h>
00012 #include <assert.h>
00013
00014
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
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
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
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
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
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
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
00181 free(key);
00182 return HASHMAP_UPDATE;
00183 }
00184 else
00185 {
00186
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
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
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