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 void *param
)
40 const char *key
= param
;
46 ctr
= (ctr
+ 1) % sizeof(char *);
52 static inline unsigned hashPtr(const void *key
)
54 return ((size_t) key
/ sizeof(char *));
57 static void rellocateItem(WMHashTable
* table
, HashItem
* item
)
61 h
= HASH(table
, item
->key
);
63 item
->next
= table
->table
[h
];
64 table
->table
[h
] = item
;
67 static void rebuildTable(WMHashTable
* table
)
75 oldArray
= table
->table
;
76 oldSize
= table
->size
;
78 newSize
= table
->size
* 2;
80 table
->table
= wmalloc(sizeof(char *) * newSize
);
81 table
->size
= newSize
;
83 for (i
= 0; i
< oldSize
; i
++) {
84 while (oldArray
[i
] != NULL
) {
85 next
= oldArray
[i
]->next
;
86 rellocateItem(table
, oldArray
[i
]);
93 WMHashTable
*WMCreateHashTable(const WMHashTableCallbacks callbacks
)
97 table
= wmalloc(sizeof(HashTable
));
99 table
->callbacks
= callbacks
;
101 table
->size
= INITIAL_CAPACITY
;
103 table
->table
= wmalloc(sizeof(HashItem
*) * table
->size
);
108 void WMResetHashTable(WMHashTable
* table
)
110 HashItem
*item
, *tmp
;
113 for (i
= 0; i
< table
->size
; i
++) {
114 item
= table
->table
[i
];
117 RELKEY(table
, item
->key
);
123 table
->itemCount
= 0;
125 if (table
->size
> INITIAL_CAPACITY
) {
127 table
->size
= INITIAL_CAPACITY
;
128 table
->table
= wmalloc(sizeof(HashItem
*) * table
->size
);
130 memset(table
->table
, 0, sizeof(HashItem
*) * table
->size
);
134 void WMFreeHashTable(WMHashTable
* table
)
136 HashItem
*item
, *tmp
;
139 for (i
= 0; i
< table
->size
; i
++) {
140 item
= table
->table
[i
];
143 RELKEY(table
, item
->key
);
152 unsigned WMCountHashTable(WMHashTable
* table
)
154 return table
->itemCount
;
157 static HashItem
*hashGetItem(WMHashTable
*table
, const void *key
)
162 h
= HASH(table
, key
);
163 item
= table
->table
[h
];
165 if (table
->callbacks
.keyIsEqual
) {
167 if ((*table
->callbacks
.keyIsEqual
) (key
, item
->key
)) {
174 if (key
== item
->key
) {
183 void *WMHashGet(WMHashTable
* table
, const void *key
)
187 item
= hashGetItem(table
, key
);
190 return (void *)item
->data
;
193 Bool
WMHashGetItemAndKey(WMHashTable
* table
, const void *key
, void **retItem
, void **retKey
)
197 item
= hashGetItem(table
, key
);
202 *retKey
= (void *)item
->key
;
204 *retItem
= (void *)item
->data
;
208 void *WMHashInsert(WMHashTable
* table
, const void *key
, const void *data
)
214 h
= HASH(table
, key
);
215 /* look for the entry */
216 item
= table
->table
[h
];
217 if (table
->callbacks
.keyIsEqual
) {
219 if ((*table
->callbacks
.keyIsEqual
) (key
, item
->key
)) {
227 if (key
== item
->key
) {
240 RELKEY(table
, item
->key
);
241 item
->key
= DUPKEY(table
, key
);
247 nitem
= wmalloc(sizeof(HashItem
));
248 nitem
->key
= DUPKEY(table
, key
);
250 nitem
->next
= table
->table
[h
];
251 table
->table
[h
] = nitem
;
256 /* OPTIMIZE: put this in an idle handler. */
257 if (table
->itemCount
> table
->size
) {
259 printf("rebuilding hash table...\n");
263 printf("finished rebuild.\n");
270 static HashItem
*deleteFromList(HashTable
* table
, HashItem
* item
, const void *key
)
277 if ((table
->callbacks
.keyIsEqual
&& (*table
->callbacks
.keyIsEqual
) (key
, item
->key
))
278 || (!table
->callbacks
.keyIsEqual
&& key
== item
->key
)) {
281 RELKEY(table
, item
->key
);
289 item
->next
= deleteFromList(table
, item
->next
, key
);
294 void WMHashRemove(WMHashTable
* table
, const void *key
)
298 h
= HASH(table
, key
);
300 table
->table
[h
] = deleteFromList(table
, table
->table
[h
], key
);
303 WMHashEnumerator
WMEnumerateHashTable(WMHashTable
* table
)
305 WMHashEnumerator enumerator
;
307 enumerator
.table
= table
;
308 enumerator
.index
= 0;
309 enumerator
.nextItem
= table
->table
[0];
314 void *WMNextHashEnumeratorItem(WMHashEnumerator
* enumerator
)
316 const void *data
= NULL
;
318 /* this assumes the table doesn't change between
319 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
321 if (enumerator
->nextItem
== NULL
) {
322 HashTable
*table
= enumerator
->table
;
323 while (++enumerator
->index
< table
->size
) {
324 if (table
->table
[enumerator
->index
] != NULL
) {
325 enumerator
->nextItem
= table
->table
[enumerator
->index
];
331 if (enumerator
->nextItem
) {
332 data
= ((HashItem
*) enumerator
->nextItem
)->data
;
333 enumerator
->nextItem
= ((HashItem
*) enumerator
->nextItem
)->next
;
339 void *WMNextHashEnumeratorKey(WMHashEnumerator
* enumerator
)
341 const void *key
= NULL
;
343 /* this assumes the table doesn't change between
344 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
346 if (enumerator
->nextItem
== NULL
) {
347 HashTable
*table
= enumerator
->table
;
348 while (++enumerator
->index
< table
->size
) {
349 if (table
->table
[enumerator
->index
] != NULL
) {
350 enumerator
->nextItem
= table
->table
[enumerator
->index
];
356 if (enumerator
->nextItem
) {
357 key
= ((HashItem
*) enumerator
->nextItem
)->key
;
358 enumerator
->nextItem
= ((HashItem
*) enumerator
->nextItem
)->next
;
364 Bool
WMNextHashEnumeratorItemAndKey(WMHashEnumerator
* enumerator
, void **item
, void **key
)
366 /* this assumes the table doesn't change between
367 * WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
369 if (enumerator
->nextItem
== NULL
) {
370 HashTable
*table
= enumerator
->table
;
371 while (++enumerator
->index
< table
->size
) {
372 if (table
->table
[enumerator
->index
] != NULL
) {
373 enumerator
->nextItem
= table
->table
[enumerator
->index
];
379 if (enumerator
->nextItem
) {
381 *item
= (void *)((HashItem
*) enumerator
->nextItem
)->data
;
383 *key
= (void *)((HashItem
*) enumerator
->nextItem
)->key
;
384 enumerator
->nextItem
= ((HashItem
*) enumerator
->nextItem
)->next
;
392 static Bool
compareStrings(const void *param1
, const void *param2
)
394 const char *key1
= param1
;
395 const char *key2
= param2
;
397 return strcmp(key1
, key2
) == 0;
400 typedef void *(*retainFunc
) (const void *);
401 typedef void (*releaseFunc
) (const void *);
403 const WMHashTableCallbacks WMIntHashCallbacks
= {
410 const WMHashTableCallbacks WMStringHashCallbacks
= {
413 (retainFunc
) wstrdup
,
417 const WMHashTableCallbacks WMStringPointerHashCallbacks
= {