replaced free() with wfree() everywhere
[wmaker-crm.git] / WINGs / hashtable.c
blob239b518a448d2f732e4d60a54d5a21f15fe1e10c
3 #include <sys/types.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <stdio.h>
8 #include "WUtil.h"
13 #define INITIAL_CAPACITY 23
16 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
17 # define INLINE inline
18 #else
19 # define INLINE
20 #endif
23 typedef struct HashItem {
24 void *key;
25 void *data;
27 struct HashItem *next; /* collided item list */
28 } HashItem;
31 typedef struct W_HashTable {
32 WMHashTableCallbacks callbacks;
34 unsigned itemCount;
35 unsigned size; /* table size */
37 HashItem **table;
38 } HashTable;
43 #define HASH(table, key) (((table)->callbacks.hash ? \
44 (*(table)->callbacks.hash)(key) : hashPtr(key)) % (table)->size)
46 #define DUPKEY(table, key) ((table)->callbacks.retainKey ? \
47 (*(table)->callbacks.retainKey)(key) : (key))
49 #define RELKEY(table, key) if ((table)->callbacks.releaseKey) \
50 (*(table)->callbacks.releaseKey)(key)
55 static INLINE unsigned
56 hashString(const char *key)
58 unsigned ret = 0;
59 unsigned ctr = 0;
61 while (*key) {
62 ret ^= *(char*)key++ << ctr;
63 ctr = (ctr + 1) % sizeof (char *);
66 return ret;
71 static INLINE unsigned
72 hashPtr(const void *key)
74 return ((size_t)key / sizeof(char*));
80 static void
81 rellocateItem(WMHashTable *table, HashItem *item)
83 unsigned h;
85 h = HASH(table, item->key);
87 item->next = table->table[h];
88 table->table[h] = item;
92 static void
93 rebuildTable(WMHashTable *table)
95 HashItem *next;
96 HashItem **oldArray;
97 int i;
98 int oldSize;
99 int newSize;
101 oldArray = table->table;
102 oldSize = table->size;
104 newSize = table->size*2;
106 table->table = wmalloc(sizeof(char*)*newSize);
107 memset(table->table, 0, sizeof(char*)*newSize);
108 table->size = newSize;
110 for (i = 0; i < oldSize; i++) {
111 while (oldArray[i]!=NULL) {
112 next = oldArray[i]->next;
113 rellocateItem(table, oldArray[i]);
114 oldArray[i] = next;
117 wfree(oldArray);
122 WMHashTable*
123 WMCreateHashTable(WMHashTableCallbacks callbacks)
125 HashTable *table;
127 table = wmalloc(sizeof(HashTable));
128 memset(table, 0, sizeof(HashTable));
130 table->callbacks = callbacks;
132 table->size = INITIAL_CAPACITY;
134 table->table = wmalloc(sizeof(HashItem*)*table->size);
135 memset(table->table, 0, sizeof(HashItem*)*table->size);
137 return table;
141 void
142 WMResetHashTable(WMHashTable *table)
144 HashItem *item, *tmp;
145 int i;
147 for (i = 0; i < table->size; i++) {
148 item = table->table[i];
149 while (item) {
150 tmp = item->next;
151 RELKEY(table, item);
152 wfree(item);
153 item = tmp;
157 table->itemCount = 0;
159 if (table->size > INITIAL_CAPACITY) {
160 wfree(table->table);
161 table->size = INITIAL_CAPACITY;
162 table->table = wmalloc(sizeof(HashItem*)*table->size);
164 memset(table->table, 0, sizeof(HashItem*)*table->size);
168 void
169 WMFreeHashTable(WMHashTable *table)
171 HashItem *item, *tmp;
172 int i;
174 for (i = 0; i < table->size; i++) {
175 item = table->table[i];
176 while (item) {
177 tmp = item->next;
178 RELKEY(table, item->key);
179 wfree(item);
180 item = tmp;
183 wfree(table->table);
184 wfree(table);
189 void*
190 WMHashGet(WMHashTable *table, const void *key)
192 unsigned h;
193 HashItem *item;
195 h = HASH(table, key);
196 item = table->table[h];
198 if (table->callbacks.keyIsEqual) {
199 while (item) {
200 if ((*table->callbacks.keyIsEqual)(key, item->key)) {
201 break;
203 item = item->next;
205 } else {
206 while (item) {
207 if (key == item->key) {
208 break;
210 item = item->next;
213 if (item)
214 return item->data;
215 else
216 return NULL;
221 void*
222 WMHashInsert(WMHashTable *table, void *key, void *data)
224 unsigned h;
225 HashItem *item;
226 int replacing = 0;
228 h = HASH(table, key);
229 /* look for the entry */
230 item = table->table[h];
231 if (table->callbacks.keyIsEqual) {
232 while (item) {
233 if ((*table->callbacks.keyIsEqual)(key, item->key)) {
234 replacing = 1;
235 break;
237 item = item->next;
239 } else {
240 while (item) {
241 if (key == item->key) {
242 replacing = 1;
243 break;
245 item = item->next;
249 if (replacing) {
250 void *old;
252 old = item->data;
253 item->data = data;
254 RELKEY(table, item->key);
255 item->key = DUPKEY(table, key);
257 return old;
258 } else {
259 HashItem *nitem;
261 nitem = wmalloc(sizeof(HashItem));
262 nitem->key = DUPKEY(table, key);
263 nitem->data = data;
264 nitem->next = table->table[h];
265 table->table[h] = nitem;
267 table->itemCount++;
270 /* OPTIMIZE: put this in an idle handler.*/
271 if (table->itemCount > table->size) {
272 #ifdef DEBUG0
273 printf("rebuilding hash table...\n");
274 #endif
275 rebuildTable(table);
276 #ifdef DEBUG0
277 printf("finished rebuild.\n");
278 #endif
281 return NULL;
285 static HashItem*
286 deleteFromList(HashTable *table, HashItem *item, const void *key)
288 HashItem *next;
290 if (item==NULL)
291 return NULL;
293 if ((table->callbacks.keyIsEqual
294 && (*table->callbacks.keyIsEqual)(key, item->key))
295 || (!table->callbacks.keyIsEqual && key==item->key)) {
297 next = item->next;
298 RELKEY(table, item->key);
299 wfree(item);
301 table->itemCount--;
303 return next;
306 item->next = deleteFromList(table, item->next, key);
308 return item;
312 void
313 WMHashRemove(WMHashTable *table, const void *key)
315 unsigned h;
317 h = HASH(table, key);
319 table->table[h] = deleteFromList(table, table->table[h], key);
323 WMHashEnumerator
324 WMEnumerateHashTable(WMHashTable *table)
326 WMHashEnumerator enumerator;
328 enumerator.table = table;
329 enumerator.index = 0;
330 enumerator.nextItem = table->table[0];
332 return enumerator;
337 void*
338 WMNextHashEnumeratorItem(WMHashEnumerator *enumerator)
340 void *data = NULL;
342 /* this assumes the table doesn't change between
343 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
345 if (enumerator->nextItem==NULL) {
346 HashTable *table = enumerator->table;
347 while (++enumerator->index < table->size) {
348 if (table->table[enumerator->index]!=NULL) {
349 enumerator->nextItem = table->table[enumerator->index];
350 break;
355 if (enumerator->nextItem) {
356 data = ((HashItem*)enumerator->nextItem)->data;
357 enumerator->nextItem = ((HashItem*)enumerator->nextItem)->next;
360 return data;
364 unsigned
365 WMCountHashTable(WMHashTable *table)
367 return table->itemCount;
371 static Bool
372 compareStrings(const char *key1, const char *key2)
374 return strcmp(key1, key2)==0;
378 typedef unsigned (*hashFunc)(const void*);
379 typedef Bool (*isEqualFunc)(const void*, const void*);
380 typedef void* (*retainFunc)(const void*);
381 typedef void (*releaseFunc)(const void*);
384 const WMHashTableCallbacks WMIntHashCallbacks = {
385 NULL,
386 NULL,
387 NULL,
388 NULL
391 const WMHashTableCallbacks WMStringHashCallbacks = {
392 (hashFunc)hashString,
393 (isEqualFunc)compareStrings,
394 (retainFunc)wstrdup,
395 (releaseFunc)free
400 const WMHashTableCallbacks WMStringPointerHashCallbacks = {
401 (hashFunc)hashString,
402 (isEqualFunc)compareStrings,
403 NULL,
404 NULL