preliminary code for property list manipulation
[wmaker-crm.git] / WINGs / hashtable.c
blob2c67ebdbad9b1b387b9e05c434d0973368a937df
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);
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;
227 void*
228 WMHashInsert(WMHashTable *table, const void *key, const void *data)
230 unsigned h;
231 HashItem *item;
232 int replacing = 0;
234 h = HASH(table, key);
235 /* look for the entry */
236 item = table->table[h];
237 if (table->callbacks.keyIsEqual) {
238 while (item) {
239 if ((*table->callbacks.keyIsEqual)(key, item->key)) {
240 replacing = 1;
241 break;
243 item = item->next;
245 } else {
246 while (item) {
247 if (key == item->key) {
248 replacing = 1;
249 break;
251 item = item->next;
255 if (replacing) {
256 const void *old;
258 old = item->data;
259 item->data = data;
260 RELKEY(table, item->key);
261 item->key = DUPKEY(table, key);
263 return (void*)old;
264 } else {
265 HashItem *nitem;
267 nitem = wmalloc(sizeof(HashItem));
268 nitem->key = DUPKEY(table, key);
269 nitem->data = data;
270 nitem->next = table->table[h];
271 table->table[h] = nitem;
273 table->itemCount++;
276 /* OPTIMIZE: put this in an idle handler.*/
277 if (table->itemCount > table->size) {
278 #ifdef DEBUG0
279 printf("rebuilding hash table...\n");
280 #endif
281 rebuildTable(table);
282 #ifdef DEBUG0
283 printf("finished rebuild.\n");
284 #endif
287 return NULL;
291 static HashItem*
292 deleteFromList(HashTable *table, HashItem *item, const void *key)
294 HashItem *next;
296 if (item==NULL)
297 return NULL;
299 if ((table->callbacks.keyIsEqual
300 && (*table->callbacks.keyIsEqual)(key, item->key))
301 || (!table->callbacks.keyIsEqual && key==item->key)) {
303 next = item->next;
304 RELKEY(table, item->key);
305 wfree(item);
307 table->itemCount--;
309 return next;
312 item->next = deleteFromList(table, item->next, key);
314 return item;
318 void
319 WMHashRemove(WMHashTable *table, const void *key)
321 unsigned h;
323 h = HASH(table, key);
325 table->table[h] = deleteFromList(table, table->table[h], key);
329 WMHashEnumerator
330 WMEnumerateHashTable(WMHashTable *table)
332 WMHashEnumerator enumerator;
334 enumerator.table = table;
335 enumerator.index = 0;
336 enumerator.nextItem = table->table[0];
338 return enumerator;
343 void*
344 WMNextHashEnumeratorItem(WMHashEnumerator *enumerator)
346 const void *data = NULL;
348 /* this assumes the table doesn't change between
349 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
351 if (enumerator->nextItem==NULL) {
352 HashTable *table = enumerator->table;
353 while (++enumerator->index < table->size) {
354 if (table->table[enumerator->index]!=NULL) {
355 enumerator->nextItem = table->table[enumerator->index];
356 break;
361 if (enumerator->nextItem) {
362 data = ((HashItem*)enumerator->nextItem)->data;
363 enumerator->nextItem = ((HashItem*)enumerator->nextItem)->next;
366 return (void*)data;
370 void*
371 WMNextHashEnumeratorKey(WMHashEnumerator *enumerator)
373 const void *key = NULL;
375 /* this assumes the table doesn't change between
376 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
378 if (enumerator->nextItem==NULL) {
379 HashTable *table = enumerator->table;
380 while (++enumerator->index < table->size) {
381 if (table->table[enumerator->index]!=NULL) {
382 enumerator->nextItem = table->table[enumerator->index];
383 break;
388 if (enumerator->nextItem) {
389 key = ((HashItem*)enumerator->nextItem)->key;
390 enumerator->nextItem = ((HashItem*)enumerator->nextItem)->next;
393 return (void*)key;
397 Bool
398 WMNextHashEnumeratorItemAndKey(WMHashEnumerator *enumerator,
399 void **item, void **key)
401 const void *data = NULL;
403 /* this assumes the table doesn't change between
404 * WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
406 if (enumerator->nextItem==NULL) {
407 HashTable *table = enumerator->table;
408 while (++enumerator->index < table->size) {
409 if (table->table[enumerator->index]!=NULL) {
410 enumerator->nextItem = table->table[enumerator->index];
411 break;
416 if (enumerator->nextItem) {
417 *item = (void*)((HashItem*)enumerator->nextItem)->data;
418 *key = (void*)((HashItem*)enumerator->nextItem)->key;
419 enumerator->nextItem = ((HashItem*)enumerator->nextItem)->next;
421 return True;
424 return False;
428 static Bool
429 compareStrings(const char *key1, const char *key2)
431 return strcmp(key1, key2)==0;
435 typedef unsigned (*hashFunc)(const void*);
436 typedef Bool (*isEqualFunc)(const void*, const void*);
437 typedef void* (*retainFunc)(const void*);
438 typedef void (*releaseFunc)(const void*);
441 const WMHashTableCallbacks WMIntHashCallbacks = {
442 NULL,
443 NULL,
444 NULL,
445 NULL
448 const WMHashTableCallbacks WMStringHashCallbacks = {
449 (hashFunc)hashString,
450 (isEqualFunc)compareStrings,
451 (retainFunc)wstrdup,
452 (releaseFunc)wfree
457 const WMHashTableCallbacks WMStringPointerHashCallbacks = {
458 (hashFunc)hashString,
459 (isEqualFunc)compareStrings,
460 NULL,
461 NULL