Coding style cleanup in dock.c
[wmaker-crm.git] / WINGs / hashtable.c
blob27e71e430aac7641aeb227b0daf7a06d3eea7928
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));
102 table->callbacks = callbacks;
104 table->size = INITIAL_CAPACITY;
106 table->table = wmalloc(sizeof(HashItem *) * table->size);
108 return table;
111 void WMResetHashTable(WMHashTable * table)
113 HashItem *item, *tmp;
114 int i;
116 for (i = 0; i < table->size; i++) {
117 item = table->table[i];
118 while (item) {
119 tmp = item->next;
120 RELKEY(table, item->key);
121 wfree(item);
122 item = tmp;
126 table->itemCount = 0;
128 if (table->size > INITIAL_CAPACITY) {
129 wfree(table->table);
130 table->size = INITIAL_CAPACITY;
131 table->table = wmalloc(sizeof(HashItem *) * table->size);
132 } else {
133 memset(table->table, 0, sizeof(HashItem *) * table->size);
137 void WMFreeHashTable(WMHashTable * table)
139 HashItem *item, *tmp;
140 int i;
142 for (i = 0; i < table->size; i++) {
143 item = table->table[i];
144 while (item) {
145 tmp = item->next;
146 RELKEY(table, item->key);
147 wfree(item);
148 item = tmp;
151 wfree(table->table);
152 wfree(table);
155 unsigned WMCountHashTable(WMHashTable * table)
157 return table->itemCount;
160 void *WMHashGet(WMHashTable * table, const void *key)
162 unsigned h;
163 HashItem *item;
165 h = HASH(table, key);
166 item = table->table[h];
168 if (table->callbacks.keyIsEqual) {
169 while (item) {
170 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
171 break;
173 item = item->next;
175 } else {
176 while (item) {
177 if (key == item->key) {
178 break;
180 item = item->next;
183 if (item)
184 return (void *)item->data;
185 else
186 return NULL;
189 Bool WMHashGetItemAndKey(WMHashTable * table, const void *key, void **retItem, void **retKey)
191 unsigned h;
192 HashItem *item;
194 h = HASH(table, key);
195 item = table->table[h];
197 if (table->callbacks.keyIsEqual) {
198 while (item) {
199 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
200 break;
202 item = item->next;
204 } else {
205 while (item) {
206 if (key == item->key) {
207 break;
209 item = item->next;
212 if (item) {
213 if (retKey)
214 *retKey = (void *)item->key;
215 if (retItem)
216 *retItem = (void *)item->data;
217 return True;
218 } else {
219 return False;
223 void *WMHashInsert(WMHashTable * table, const void *key, const void *data)
225 unsigned h;
226 HashItem *item;
227 int replacing = 0;
229 h = HASH(table, key);
230 /* look for the entry */
231 item = table->table[h];
232 if (table->callbacks.keyIsEqual) {
233 while (item) {
234 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
235 replacing = 1;
236 break;
238 item = item->next;
240 } else {
241 while (item) {
242 if (key == item->key) {
243 replacing = 1;
244 break;
246 item = item->next;
250 if (replacing) {
251 const void *old;
253 old = item->data;
254 item->data = data;
255 RELKEY(table, item->key);
256 item->key = DUPKEY(table, key);
258 return (void *)old;
259 } else {
260 HashItem *nitem;
262 nitem = wmalloc(sizeof(HashItem));
263 nitem->key = DUPKEY(table, key);
264 nitem->data = data;
265 nitem->next = table->table[h];
266 table->table[h] = nitem;
268 table->itemCount++;
271 /* OPTIMIZE: put this in an idle handler. */
272 if (table->itemCount > table->size) {
273 #ifdef DEBUG0
274 printf("rebuilding hash table...\n");
275 #endif
276 rebuildTable(table);
277 #ifdef DEBUG0
278 printf("finished rebuild.\n");
279 #endif
282 return NULL;
285 static HashItem *deleteFromList(HashTable * table, HashItem * item, const void *key)
287 HashItem *next;
289 if (item == NULL)
290 return NULL;
292 if ((table->callbacks.keyIsEqual && (*table->callbacks.keyIsEqual) (key, item->key))
293 || (!table->callbacks.keyIsEqual && key == item->key)) {
295 next = item->next;
296 RELKEY(table, item->key);
297 wfree(item);
299 table->itemCount--;
301 return next;
304 item->next = deleteFromList(table, item->next, key);
306 return item;
309 void WMHashRemove(WMHashTable * table, const void *key)
311 unsigned h;
313 h = HASH(table, key);
315 table->table[h] = deleteFromList(table, table->table[h], key);
318 WMHashEnumerator WMEnumerateHashTable(WMHashTable * table)
320 WMHashEnumerator enumerator;
322 enumerator.table = table;
323 enumerator.index = 0;
324 enumerator.nextItem = table->table[0];
326 return enumerator;
329 void *WMNextHashEnumeratorItem(WMHashEnumerator * enumerator)
331 const void *data = NULL;
333 /* this assumes the table doesn't change between
334 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
336 if (enumerator->nextItem == NULL) {
337 HashTable *table = enumerator->table;
338 while (++enumerator->index < table->size) {
339 if (table->table[enumerator->index] != NULL) {
340 enumerator->nextItem = table->table[enumerator->index];
341 break;
346 if (enumerator->nextItem) {
347 data = ((HashItem *) enumerator->nextItem)->data;
348 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
351 return (void *)data;
354 void *WMNextHashEnumeratorKey(WMHashEnumerator * enumerator)
356 const void *key = NULL;
358 /* this assumes the table doesn't change between
359 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
361 if (enumerator->nextItem == NULL) {
362 HashTable *table = enumerator->table;
363 while (++enumerator->index < table->size) {
364 if (table->table[enumerator->index] != NULL) {
365 enumerator->nextItem = table->table[enumerator->index];
366 break;
371 if (enumerator->nextItem) {
372 key = ((HashItem *) enumerator->nextItem)->key;
373 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
376 return (void *)key;
379 Bool WMNextHashEnumeratorItemAndKey(WMHashEnumerator * enumerator, void **item, void **key)
381 /* this assumes the table doesn't change between
382 * WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
384 if (enumerator->nextItem == NULL) {
385 HashTable *table = enumerator->table;
386 while (++enumerator->index < table->size) {
387 if (table->table[enumerator->index] != NULL) {
388 enumerator->nextItem = table->table[enumerator->index];
389 break;
394 if (enumerator->nextItem) {
395 if (item)
396 *item = (void *)((HashItem *) enumerator->nextItem)->data;
397 if (key)
398 *key = (void *)((HashItem *) enumerator->nextItem)->key;
399 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
401 return True;
404 return False;
407 static Bool compareStrings(const char *key1, const char *key2)
409 return strcmp(key1, key2) == 0;
412 typedef unsigned (*hashFunc) (const void *);
413 typedef Bool(*isEqualFunc) (const void *, const void *);
414 typedef void *(*retainFunc) (const void *);
415 typedef void (*releaseFunc) (const void *);
417 const WMHashTableCallbacks WMIntHashCallbacks = {
418 NULL,
419 NULL,
420 NULL,
421 NULL
424 const WMHashTableCallbacks WMStringHashCallbacks = {
425 (hashFunc) hashString,
426 (isEqualFunc) compareStrings,
427 (retainFunc) wstrdup,
428 (releaseFunc) wfree
431 const WMHashTableCallbacks WMStringPointerHashCallbacks = {
432 (hashFunc) hashString,
433 (isEqualFunc) compareStrings,
434 NULL,
435 NULL