changed indentation to use spaces only
[wmaker-crm.git] / WINGs / hashtable.c
blobc348f23a28f921f0ac6cbde1ba81a6ee141bcfc1
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 const void *key;
25 const 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->key);
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);
188 unsigned
189 WMCountHashTable(WMHashTable *table)
191 return table->itemCount;
195 void*
196 WMHashGet(WMHashTable *table, const void *key)
198 unsigned h;
199 HashItem *item;
201 h = HASH(table, key);
202 item = table->table[h];
204 if (table->callbacks.keyIsEqual) {
205 while (item) {
206 if ((*table->callbacks.keyIsEqual)(key, item->key)) {
207 break;
209 item = item->next;
211 } else {
212 while (item) {
213 if (key == item->key) {
214 break;
216 item = item->next;
219 if (item)
220 return (void*)item->data;
221 else
222 return NULL;
226 Bool
227 WMHashGetItemAndKey(WMHashTable *table, const void *key,
228 void **retItem, void **retKey)
230 unsigned h;
231 HashItem *item;
233 h = HASH(table, key);
234 item = table->table[h];
236 if (table->callbacks.keyIsEqual) {
237 while (item) {
238 if ((*table->callbacks.keyIsEqual)(key, item->key)) {
239 break;
241 item = item->next;
243 } else {
244 while (item) {
245 if (key == item->key) {
246 break;
248 item = item->next;
251 if (item) {
252 if (retKey)
253 *retKey = (void*)item->key;
254 if (retItem)
255 *retItem = (void*)item->data;
256 return True;
257 } else {
258 return False;
264 void*
265 WMHashInsert(WMHashTable *table, const void *key, const void *data)
267 unsigned h;
268 HashItem *item;
269 int replacing = 0;
271 h = HASH(table, key);
272 /* look for the entry */
273 item = table->table[h];
274 if (table->callbacks.keyIsEqual) {
275 while (item) {
276 if ((*table->callbacks.keyIsEqual)(key, item->key)) {
277 replacing = 1;
278 break;
280 item = item->next;
282 } else {
283 while (item) {
284 if (key == item->key) {
285 replacing = 1;
286 break;
288 item = item->next;
292 if (replacing) {
293 const void *old;
295 old = item->data;
296 item->data = data;
297 RELKEY(table, item->key);
298 item->key = DUPKEY(table, key);
300 return (void*)old;
301 } else {
302 HashItem *nitem;
304 nitem = wmalloc(sizeof(HashItem));
305 nitem->key = DUPKEY(table, key);
306 nitem->data = data;
307 nitem->next = table->table[h];
308 table->table[h] = nitem;
310 table->itemCount++;
313 /* OPTIMIZE: put this in an idle handler.*/
314 if (table->itemCount > table->size) {
315 #ifdef DEBUG0
316 printf("rebuilding hash table...\n");
317 #endif
318 rebuildTable(table);
319 #ifdef DEBUG0
320 printf("finished rebuild.\n");
321 #endif
324 return NULL;
328 static HashItem*
329 deleteFromList(HashTable *table, HashItem *item, const void *key)
331 HashItem *next;
333 if (item==NULL)
334 return NULL;
336 if ((table->callbacks.keyIsEqual
337 && (*table->callbacks.keyIsEqual)(key, item->key))
338 || (!table->callbacks.keyIsEqual && key==item->key)) {
340 next = item->next;
341 RELKEY(table, item->key);
342 wfree(item);
344 table->itemCount--;
346 return next;
349 item->next = deleteFromList(table, item->next, key);
351 return item;
355 void
356 WMHashRemove(WMHashTable *table, const void *key)
358 unsigned h;
360 h = HASH(table, key);
362 table->table[h] = deleteFromList(table, table->table[h], key);
366 WMHashEnumerator
367 WMEnumerateHashTable(WMHashTable *table)
369 WMHashEnumerator enumerator;
371 enumerator.table = table;
372 enumerator.index = 0;
373 enumerator.nextItem = table->table[0];
375 return enumerator;
380 void*
381 WMNextHashEnumeratorItem(WMHashEnumerator *enumerator)
383 const void *data = NULL;
385 /* this assumes the table doesn't change between
386 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
388 if (enumerator->nextItem==NULL) {
389 HashTable *table = enumerator->table;
390 while (++enumerator->index < table->size) {
391 if (table->table[enumerator->index]!=NULL) {
392 enumerator->nextItem = table->table[enumerator->index];
393 break;
398 if (enumerator->nextItem) {
399 data = ((HashItem*)enumerator->nextItem)->data;
400 enumerator->nextItem = ((HashItem*)enumerator->nextItem)->next;
403 return (void*)data;
407 void*
408 WMNextHashEnumeratorKey(WMHashEnumerator *enumerator)
410 const void *key = NULL;
412 /* this assumes the table doesn't change between
413 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
415 if (enumerator->nextItem==NULL) {
416 HashTable *table = enumerator->table;
417 while (++enumerator->index < table->size) {
418 if (table->table[enumerator->index]!=NULL) {
419 enumerator->nextItem = table->table[enumerator->index];
420 break;
425 if (enumerator->nextItem) {
426 key = ((HashItem*)enumerator->nextItem)->key;
427 enumerator->nextItem = ((HashItem*)enumerator->nextItem)->next;
430 return (void*)key;
434 Bool
435 WMNextHashEnumeratorItemAndKey(WMHashEnumerator *enumerator,
436 void **item, void **key)
438 /* this assumes the table doesn't change between
439 * WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
441 if (enumerator->nextItem==NULL) {
442 HashTable *table = enumerator->table;
443 while (++enumerator->index < table->size) {
444 if (table->table[enumerator->index]!=NULL) {
445 enumerator->nextItem = table->table[enumerator->index];
446 break;
451 if (enumerator->nextItem) {
452 if (item)
453 *item = (void*)((HashItem*)enumerator->nextItem)->data;
454 if (key)
455 *key = (void*)((HashItem*)enumerator->nextItem)->key;
456 enumerator->nextItem = ((HashItem*)enumerator->nextItem)->next;
458 return True;
461 return False;
465 static Bool
466 compareStrings(const char *key1, const char *key2)
468 return strcmp(key1, key2)==0;
472 typedef unsigned (*hashFunc)(const void*);
473 typedef Bool (*isEqualFunc)(const void*, const void*);
474 typedef void* (*retainFunc)(const void*);
475 typedef void (*releaseFunc)(const void*);
478 const WMHashTableCallbacks WMIntHashCallbacks = {
479 NULL,
480 NULL,
481 NULL,
482 NULL
485 const WMHashTableCallbacks WMStringHashCallbacks = {
486 (hashFunc)hashString,
487 (isEqualFunc)compareStrings,
488 (retainFunc)wstrdup,
489 (releaseFunc)wfree
494 const WMHashTableCallbacks WMStringPointerHashCallbacks = {
495 (hashFunc)hashString,
496 (isEqualFunc)compareStrings,
497 NULL,
498 NULL