10 #define INITIAL_CAPACITY 23
13 typedef struct HashItem
{
17 struct HashItem
*next
; /* collided item list */
20 typedef struct W_HashTable
{
21 WMHashTableCallbacks callbacks
;
24 unsigned size
; /* table size */
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
)
44 ret
^= *(char *)key
++ << ctr
;
45 ctr
= (ctr
+ 1) % sizeof(char *);
51 static inline unsigned hashPtr(const void *key
)
53 return ((size_t) key
/ sizeof(char *));
56 static void rellocateItem(WMHashTable
* table
, HashItem
* item
)
60 h
= HASH(table
, item
->key
);
62 item
->next
= table
->table
[h
];
63 table
->table
[h
] = item
;
66 static void rebuildTable(WMHashTable
* table
)
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
]);
92 WMHashTable
*WMCreateHashTable(WMHashTableCallbacks callbacks
)
96 table
= wmalloc(sizeof(HashTable
));
98 table
->callbacks
= callbacks
;
100 table
->size
= INITIAL_CAPACITY
;
102 table
->table
= wmalloc(sizeof(HashItem
*) * table
->size
);
107 void WMResetHashTable(WMHashTable
* table
)
109 HashItem
*item
, *tmp
;
112 for (i
= 0; i
< table
->size
; i
++) {
113 item
= table
->table
[i
];
116 RELKEY(table
, item
->key
);
122 table
->itemCount
= 0;
124 if (table
->size
> INITIAL_CAPACITY
) {
126 table
->size
= INITIAL_CAPACITY
;
127 table
->table
= wmalloc(sizeof(HashItem
*) * table
->size
);
129 memset(table
->table
, 0, sizeof(HashItem
*) * table
->size
);
133 void WMFreeHashTable(WMHashTable
* table
)
135 HashItem
*item
, *tmp
;
138 for (i
= 0; i
< table
->size
; i
++) {
139 item
= table
->table
[i
];
142 RELKEY(table
, item
->key
);
151 unsigned WMCountHashTable(WMHashTable
* table
)
153 return table
->itemCount
;
156 void *WMHashGet(WMHashTable
* table
, const void *key
)
161 h
= HASH(table
, key
);
162 item
= table
->table
[h
];
164 if (table
->callbacks
.keyIsEqual
) {
166 if ((*table
->callbacks
.keyIsEqual
) (key
, item
->key
)) {
173 if (key
== item
->key
) {
180 return (void *)item
->data
;
185 Bool
WMHashGetItemAndKey(WMHashTable
* table
, const void *key
, void **retItem
, void **retKey
)
190 h
= HASH(table
, key
);
191 item
= table
->table
[h
];
193 if (table
->callbacks
.keyIsEqual
) {
195 if ((*table
->callbacks
.keyIsEqual
) (key
, item
->key
)) {
202 if (key
== item
->key
) {
210 *retKey
= (void *)item
->key
;
212 *retItem
= (void *)item
->data
;
219 void *WMHashInsert(WMHashTable
* table
, const void *key
, const void *data
)
225 h
= HASH(table
, key
);
226 /* look for the entry */
227 item
= table
->table
[h
];
228 if (table
->callbacks
.keyIsEqual
) {
230 if ((*table
->callbacks
.keyIsEqual
) (key
, item
->key
)) {
238 if (key
== item
->key
) {
251 RELKEY(table
, item
->key
);
252 item
->key
= DUPKEY(table
, key
);
258 nitem
= wmalloc(sizeof(HashItem
));
259 nitem
->key
= DUPKEY(table
, key
);
261 nitem
->next
= table
->table
[h
];
262 table
->table
[h
] = nitem
;
267 /* OPTIMIZE: put this in an idle handler. */
268 if (table
->itemCount
> table
->size
) {
270 printf("rebuilding hash table...\n");
274 printf("finished rebuild.\n");
281 static HashItem
*deleteFromList(HashTable
* table
, HashItem
* item
, const void *key
)
288 if ((table
->callbacks
.keyIsEqual
&& (*table
->callbacks
.keyIsEqual
) (key
, item
->key
))
289 || (!table
->callbacks
.keyIsEqual
&& key
== item
->key
)) {
292 RELKEY(table
, item
->key
);
300 item
->next
= deleteFromList(table
, item
->next
, key
);
305 void WMHashRemove(WMHashTable
* table
, const void *key
)
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];
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
];
342 if (enumerator
->nextItem
) {
343 data
= ((HashItem
*) enumerator
->nextItem
)->data
;
344 enumerator
->nextItem
= ((HashItem
*) enumerator
->nextItem
)->next
;
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
];
367 if (enumerator
->nextItem
) {
368 key
= ((HashItem
*) enumerator
->nextItem
)->key
;
369 enumerator
->nextItem
= ((HashItem
*) enumerator
->nextItem
)->next
;
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
];
390 if (enumerator
->nextItem
) {
392 *item
= (void *)((HashItem
*) enumerator
->nextItem
)->data
;
394 *key
= (void *)((HashItem
*) enumerator
->nextItem
)->key
;
395 enumerator
->nextItem
= ((HashItem
*) enumerator
->nextItem
)->next
;
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
= {
420 const WMHashTableCallbacks WMStringHashCallbacks
= {
421 (hashFunc
) hashString
,
422 (isEqualFunc
) compareStrings
,
423 (retainFunc
) wstrdup
,
427 const WMHashTableCallbacks WMStringPointerHashCallbacks
= {
428 (hashFunc
) hashString
,
429 (isEqualFunc
) compareStrings
,