Unified usage of the 'inline' attribute for functions
[wmaker-crm.git] / WINGs / hashtable.c
blobaec4f5a271dee5313acd25c2e610194f41fbfa7e
1 #include <config.h>
3 #include <sys/types.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <stdio.h>
8 #include "WUtil.h"
10 #define INITIAL_CAPACITY 23
13 typedef struct HashItem {
14 const void *key;
15 const void *data;
17 struct HashItem *next; /* collided item list */
18 } HashItem;
20 typedef struct W_HashTable {
21 WMHashTableCallbacks callbacks;
23 unsigned itemCount;
24 unsigned size; /* table size */
26 HashItem **table;
27 } HashTable;
29 #define HASH(table, key) (((table)->callbacks.hash ? \
30 (*(table)->callbacks.hash)(key) : hashPtr(key)) % (table)->size)
32 #define DUPKEY(table, key) ((table)->callbacks.retainKey ? \
33 (*(table)->callbacks.retainKey)(key) : (key))
35 #define RELKEY(table, key) if ((table)->callbacks.releaseKey) \
36 (*(table)->callbacks.releaseKey)(key)
38 static inline unsigned hashString(const char *key)
40 unsigned ret = 0;
41 unsigned ctr = 0;
43 while (*key) {
44 ret ^= *(char *)key++ << ctr;
45 ctr = (ctr + 1) % sizeof(char *);
48 return ret;
51 static inline unsigned hashPtr(const void *key)
53 return ((size_t) key / sizeof(char *));
56 static void rellocateItem(WMHashTable * table, HashItem * item)
58 unsigned h;
60 h = HASH(table, item->key);
62 item->next = table->table[h];
63 table->table[h] = item;
66 static void rebuildTable(WMHashTable * table)
68 HashItem *next;
69 HashItem **oldArray;
70 int i;
71 int oldSize;
72 int newSize;
74 oldArray = table->table;
75 oldSize = table->size;
77 newSize = table->size * 2;
79 table->table = wmalloc(sizeof(char *) * newSize);
80 table->size = newSize;
82 for (i = 0; i < oldSize; i++) {
83 while (oldArray[i] != NULL) {
84 next = oldArray[i]->next;
85 rellocateItem(table, oldArray[i]);
86 oldArray[i] = next;
89 wfree(oldArray);
92 WMHashTable *WMCreateHashTable(WMHashTableCallbacks callbacks)
94 HashTable *table;
96 table = wmalloc(sizeof(HashTable));
98 table->callbacks = callbacks;
100 table->size = INITIAL_CAPACITY;
102 table->table = wmalloc(sizeof(HashItem *) * table->size);
104 return table;
107 void WMResetHashTable(WMHashTable * table)
109 HashItem *item, *tmp;
110 int i;
112 for (i = 0; i < table->size; i++) {
113 item = table->table[i];
114 while (item) {
115 tmp = item->next;
116 RELKEY(table, item->key);
117 wfree(item);
118 item = tmp;
122 table->itemCount = 0;
124 if (table->size > INITIAL_CAPACITY) {
125 wfree(table->table);
126 table->size = INITIAL_CAPACITY;
127 table->table = wmalloc(sizeof(HashItem *) * table->size);
128 } else {
129 memset(table->table, 0, sizeof(HashItem *) * table->size);
133 void WMFreeHashTable(WMHashTable * table)
135 HashItem *item, *tmp;
136 int i;
138 for (i = 0; i < table->size; i++) {
139 item = table->table[i];
140 while (item) {
141 tmp = item->next;
142 RELKEY(table, item->key);
143 wfree(item);
144 item = tmp;
147 wfree(table->table);
148 wfree(table);
151 unsigned WMCountHashTable(WMHashTable * table)
153 return table->itemCount;
156 void *WMHashGet(WMHashTable * table, const void *key)
158 unsigned h;
159 HashItem *item;
161 h = HASH(table, key);
162 item = table->table[h];
164 if (table->callbacks.keyIsEqual) {
165 while (item) {
166 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
167 break;
169 item = item->next;
171 } else {
172 while (item) {
173 if (key == item->key) {
174 break;
176 item = item->next;
179 if (item)
180 return (void *)item->data;
181 else
182 return NULL;
185 Bool WMHashGetItemAndKey(WMHashTable * table, const void *key, void **retItem, void **retKey)
187 unsigned h;
188 HashItem *item;
190 h = HASH(table, key);
191 item = table->table[h];
193 if (table->callbacks.keyIsEqual) {
194 while (item) {
195 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
196 break;
198 item = item->next;
200 } else {
201 while (item) {
202 if (key == item->key) {
203 break;
205 item = item->next;
208 if (item) {
209 if (retKey)
210 *retKey = (void *)item->key;
211 if (retItem)
212 *retItem = (void *)item->data;
213 return True;
214 } else {
215 return False;
219 void *WMHashInsert(WMHashTable * table, const void *key, const void *data)
221 unsigned h;
222 HashItem *item;
223 int replacing = 0;
225 h = HASH(table, key);
226 /* look for the entry */
227 item = table->table[h];
228 if (table->callbacks.keyIsEqual) {
229 while (item) {
230 if ((*table->callbacks.keyIsEqual) (key, item->key)) {
231 replacing = 1;
232 break;
234 item = item->next;
236 } else {
237 while (item) {
238 if (key == item->key) {
239 replacing = 1;
240 break;
242 item = item->next;
246 if (replacing) {
247 const void *old;
249 old = item->data;
250 item->data = data;
251 RELKEY(table, item->key);
252 item->key = DUPKEY(table, key);
254 return (void *)old;
255 } else {
256 HashItem *nitem;
258 nitem = wmalloc(sizeof(HashItem));
259 nitem->key = DUPKEY(table, key);
260 nitem->data = data;
261 nitem->next = table->table[h];
262 table->table[h] = nitem;
264 table->itemCount++;
267 /* OPTIMIZE: put this in an idle handler. */
268 if (table->itemCount > table->size) {
269 #ifdef DEBUG0
270 printf("rebuilding hash table...\n");
271 #endif
272 rebuildTable(table);
273 #ifdef DEBUG0
274 printf("finished rebuild.\n");
275 #endif
278 return NULL;
281 static HashItem *deleteFromList(HashTable * table, HashItem * item, const void *key)
283 HashItem *next;
285 if (item == NULL)
286 return NULL;
288 if ((table->callbacks.keyIsEqual && (*table->callbacks.keyIsEqual) (key, item->key))
289 || (!table->callbacks.keyIsEqual && key == item->key)) {
291 next = item->next;
292 RELKEY(table, item->key);
293 wfree(item);
295 table->itemCount--;
297 return next;
300 item->next = deleteFromList(table, item->next, key);
302 return item;
305 void WMHashRemove(WMHashTable * table, const void *key)
307 unsigned h;
309 h = HASH(table, key);
311 table->table[h] = deleteFromList(table, table->table[h], key);
314 WMHashEnumerator WMEnumerateHashTable(WMHashTable * table)
316 WMHashEnumerator enumerator;
318 enumerator.table = table;
319 enumerator.index = 0;
320 enumerator.nextItem = table->table[0];
322 return enumerator;
325 void *WMNextHashEnumeratorItem(WMHashEnumerator * enumerator)
327 const void *data = NULL;
329 /* this assumes the table doesn't change between
330 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
332 if (enumerator->nextItem == NULL) {
333 HashTable *table = enumerator->table;
334 while (++enumerator->index < table->size) {
335 if (table->table[enumerator->index] != NULL) {
336 enumerator->nextItem = table->table[enumerator->index];
337 break;
342 if (enumerator->nextItem) {
343 data = ((HashItem *) enumerator->nextItem)->data;
344 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
347 return (void *)data;
350 void *WMNextHashEnumeratorKey(WMHashEnumerator * enumerator)
352 const void *key = NULL;
354 /* this assumes the table doesn't change between
355 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
357 if (enumerator->nextItem == NULL) {
358 HashTable *table = enumerator->table;
359 while (++enumerator->index < table->size) {
360 if (table->table[enumerator->index] != NULL) {
361 enumerator->nextItem = table->table[enumerator->index];
362 break;
367 if (enumerator->nextItem) {
368 key = ((HashItem *) enumerator->nextItem)->key;
369 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
372 return (void *)key;
375 Bool WMNextHashEnumeratorItemAndKey(WMHashEnumerator * enumerator, void **item, void **key)
377 /* this assumes the table doesn't change between
378 * WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
380 if (enumerator->nextItem == NULL) {
381 HashTable *table = enumerator->table;
382 while (++enumerator->index < table->size) {
383 if (table->table[enumerator->index] != NULL) {
384 enumerator->nextItem = table->table[enumerator->index];
385 break;
390 if (enumerator->nextItem) {
391 if (item)
392 *item = (void *)((HashItem *) enumerator->nextItem)->data;
393 if (key)
394 *key = (void *)((HashItem *) enumerator->nextItem)->key;
395 enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
397 return True;
400 return False;
403 static Bool compareStrings(const char *key1, const char *key2)
405 return strcmp(key1, key2) == 0;
408 typedef unsigned (*hashFunc) (const void *);
409 typedef Bool(*isEqualFunc) (const void *, const void *);
410 typedef void *(*retainFunc) (const void *);
411 typedef void (*releaseFunc) (const void *);
413 const WMHashTableCallbacks WMIntHashCallbacks = {
414 NULL,
415 NULL,
416 NULL,
417 NULL
420 const WMHashTableCallbacks WMStringHashCallbacks = {
421 (hashFunc) hashString,
422 (isEqualFunc) compareStrings,
423 (retainFunc) wstrdup,
424 (releaseFunc) wfree
427 const WMHashTableCallbacks WMStringPointerHashCallbacks = {
428 (hashFunc) hashString,
429 (isEqualFunc) compareStrings,
430 NULL,
431 NULL