Small update on wmgenmenu list of apps
[wmaker-crm.git] / WINGs / hashtable.c
blob9822c4ee841f84cfd1f75f5de0039cbbf057c011
2 #include <sys/types.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdio.h>
7 #include "WUtil.h"
9 #define INITIAL_CAPACITY 23
11 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
12 # define INLINE inline
13 #else
14 # define INLINE
15 #endif
17 typedef struct HashItem {
18 const void *key;
19 const void *data;
21 struct HashItem *next; /* collided item list */
22 } HashItem;
24 typedef struct W_HashTable {
25 WMHashTableCallbacks callbacks;
27 unsigned itemCount;
28 unsigned size; /* table size */
30 HashItem **table;
31 } HashTable;
33 #define HASH(table, key) (((table)->callbacks.hash ? \
34 (*(table)->callbacks.hash)(key) : hashPtr(key)) % (table)->size)
36 #define DUPKEY(table, key) ((table)->callbacks.retainKey ? \
37 (*(table)->callbacks.retainKey)(key) : (key))
39 #define RELKEY(table, key) if ((table)->callbacks.releaseKey) \
40 (*(table)->callbacks.releaseKey)(key)
42 static INLINE unsigned hashString(const char *key)
44 unsigned ret = 0;
45 unsigned ctr = 0;
47 while (*key) {
48 ret ^= *(char *)key++ << ctr;
49 ctr = (ctr + 1) % sizeof(char *);
52 return ret;
55 static INLINE unsigned hashPtr(const void *key)
57 return ((size_t) key / sizeof(char *));
60 static void rellocateItem(WMHashTable * table, HashItem * item)
62 unsigned h;
64 h = HASH(table, item->key);
66 item->next = table->table[h];
67 table->table[h] = item;
70 static void rebuildTable(WMHashTable * table)
72 HashItem *next;
73 HashItem **oldArray;
74 int i;
75 int oldSize;
76 int newSize;
78 oldArray = table->table;
79 oldSize = table->size;
81 newSize = table->size * 2;
83 table->table = wmalloc(sizeof(char *) * newSize);
84 table->size = newSize;
86 for (i = 0; i < oldSize; i++) {
87 while (oldArray[i] != NULL) {
88 next = oldArray[i]->next;
89 rellocateItem(table, oldArray[i]);
90 oldArray[i] = next;
93 wfree(oldArray);
96 WMHashTable *WMCreateHashTable(WMHashTableCallbacks callbacks)
98 HashTable *table;
100 table = wmalloc(sizeof(HashTable));
101 memset(table, 0, sizeof(HashTable));
103 table->callbacks = callbacks;
105 table->size = INITIAL_CAPACITY;
107 table->table = wmalloc(sizeof(HashItem *) * table->size);
108 memset(table->table, 0, sizeof(HashItem *) * table->size);
110 return table;
113 void WMResetHashTable(WMHashTable * table)
115 HashItem *item, *tmp;
116 int i;
118 for (i = 0; i < table->size; i++) {
119 item = table->table[i];
120 while (item) {
121 tmp = item->next;
122 RELKEY(table, item->key);
123 wfree(item);
124 item = tmp;
128 table->itemCount = 0;
130 if (table->size > INITIAL_CAPACITY) {
131 wfree(table->table);
132 table->size = INITIAL_CAPACITY;
133 table->table = wmalloc(sizeof(HashItem *) * table->size);
135 memset(table->table, 0, sizeof(HashItem *) * table->size);
138 void WMFreeHashTable(WMHashTable * table)
140 HashItem *item, *tmp;
141 int i;
143 for (i = 0; i < table->size; i++) {
144 item = table->table[i];
145 while (item) {
146 tmp = item->next;
147 RELKEY(table, item->key);
148 wfree(item);
149 item = tmp;
152 wfree(table->table);
153 wfree(table);
156 unsigned WMCountHashTable(WMHashTable * table)
158 return table->itemCount;
161 void *WMHashGet(WMHashTable * table, const void *key)
163 unsigned h;
164 HashItem *item;
166 h = HASH(table, key);
167 item = table->table[h];
169 if (table->callbacks.keyIsEqual) {
170 while (item) {
171 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
172 break;
174 item = item->next;
176 } else {
177 while (item) {
178 if (key == item->key) {
179 break;
181 item = item->next;
184 if (item)
185 return (void *)item->data;
186 else
187 return NULL;
190 Bool WMHashGetItemAndKey(WMHashTable * table, const void *key, void **retItem, void **retKey)
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 if (retKey)
215 *retKey = (void *)item->key;
216 if (retItem)
217 *retItem = (void *)item->data;
218 return True;
219 } else {
220 return False;
224 void *WMHashInsert(WMHashTable * table, const void *key, const void *data)
226 unsigned h;
227 HashItem *item;
228 int replacing = 0;
230 h = HASH(table, key);
231 /* look for the entry */
232 item = table->table[h];
233 if (table->callbacks.keyIsEqual) {
234 while (item) {
235 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
236 replacing = 1;
237 break;
239 item = item->next;
241 } else {
242 while (item) {
243 if (key == item->key) {
244 replacing = 1;
245 break;
247 item = item->next;
251 if (replacing) {
252 const void *old;
254 old = item->data;
255 item->data = data;
256 RELKEY(table, item->key);
257 item->key = DUPKEY(table, key);
259 return (void *)old;
260 } else {
261 HashItem *nitem;
263 nitem = wmalloc(sizeof(HashItem));
264 nitem->key = DUPKEY(table, key);
265 nitem->data = data;
266 nitem->next = table->table[h];
267 table->table[h] = nitem;
269 table->itemCount++;
272 /* OPTIMIZE: put this in an idle handler. */
273 if (table->itemCount > table->size) {
274 #ifdef DEBUG0
275 printf("rebuilding hash table...\n");
276 #endif
277 rebuildTable(table);
278 #ifdef DEBUG0
279 printf("finished rebuild.\n");
280 #endif
283 return NULL;
286 static HashItem *deleteFromList(HashTable * table, HashItem * item, const void *key)
288 HashItem *next;
290 if (item == NULL)
291 return NULL;
293 if ((table->callbacks.keyIsEqual && (*table->callbacks.keyIsEqual) (key, item->key))
294 || (!table->callbacks.keyIsEqual && key == item->key)) {
296 next = item->next;
297 RELKEY(table, item->key);
298 wfree(item);
300 table->itemCount--;
302 return next;
305 item->next = deleteFromList(table, item->next, key);
307 return item;
310 void WMHashRemove(WMHashTable * table, const void *key)
312 unsigned h;
314 h = HASH(table, key);
316 table->table[h] = deleteFromList(table, table->table[h], key);
319 WMHashEnumerator WMEnumerateHashTable(WMHashTable * table)
321 WMHashEnumerator enumerator;
323 enumerator.table = table;
324 enumerator.index = 0;
325 enumerator.nextItem = table->table[0];
327 return enumerator;
330 void *WMNextHashEnumeratorItem(WMHashEnumerator * enumerator)
332 const void *data = NULL;
334 /* this assumes the table doesn't change between
335 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
337 if (enumerator->nextItem == NULL) {
338 HashTable *table = enumerator->table;
339 while (++enumerator->index < table->size) {
340 if (table->table[enumerator->index] != NULL) {
341 enumerator->nextItem = table->table[enumerator->index];
342 break;
347 if (enumerator->nextItem) {
348 data = ((HashItem *) enumerator->nextItem)->data;
349 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
352 return (void *)data;
355 void *WMNextHashEnumeratorKey(WMHashEnumerator * enumerator)
357 const void *key = NULL;
359 /* this assumes the table doesn't change between
360 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
362 if (enumerator->nextItem == NULL) {
363 HashTable *table = enumerator->table;
364 while (++enumerator->index < table->size) {
365 if (table->table[enumerator->index] != NULL) {
366 enumerator->nextItem = table->table[enumerator->index];
367 break;
372 if (enumerator->nextItem) {
373 key = ((HashItem *) enumerator->nextItem)->key;
374 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
377 return (void *)key;
380 Bool WMNextHashEnumeratorItemAndKey(WMHashEnumerator * enumerator, void **item, void **key)
382 /* this assumes the table doesn't change between
383 * WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
385 if (enumerator->nextItem == NULL) {
386 HashTable *table = enumerator->table;
387 while (++enumerator->index < table->size) {
388 if (table->table[enumerator->index] != NULL) {
389 enumerator->nextItem = table->table[enumerator->index];
390 break;
395 if (enumerator->nextItem) {
396 if (item)
397 *item = (void *)((HashItem *) enumerator->nextItem)->data;
398 if (key)
399 *key = (void *)((HashItem *) enumerator->nextItem)->key;
400 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
402 return True;
405 return False;
408 static Bool compareStrings(const char *key1, const char *key2)
410 return strcmp(key1, key2) == 0;
413 typedef unsigned (*hashFunc) (const void *);
414 typedef Bool(*isEqualFunc) (const void *, const void *);
415 typedef void *(*retainFunc) (const void *);
416 typedef void (*releaseFunc) (const void *);
418 const WMHashTableCallbacks WMIntHashCallbacks = {
419 NULL,
420 NULL,
421 NULL,
422 NULL
425 const WMHashTableCallbacks WMStringHashCallbacks = {
426 (hashFunc) hashString,
427 (isEqualFunc) compareStrings,
428 (retainFunc) wstrdup,
429 (releaseFunc) wfree
432 const WMHashTableCallbacks WMStringPointerHashCallbacks = {
433 (hashFunc) hashString,
434 (isEqualFunc) compareStrings,
435 NULL,
436 NULL