13 #define INITIAL_CAPACITY 23
16 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
17 # define INLINE inline
23 typedef struct HashItem
{
27 struct HashItem
*next
; /* collided item list */
31 typedef struct W_HashTable
{
32 WMHashTableCallbacks callbacks
;
35 unsigned size
; /* table size */
43 #define HASH(table, key) (((table)->callbacks.hash ? \
44 (*(table)->callbacks.hash)(key) : hashPtr(key)) % (table)->size)
46 #define DUPKEY(table, key) ((table)->callbacks.retainKey ? \
47 (*(table)->callbacks.retainKey)(key) : (key))
49 #define RELKEY(table, key) if ((table)->callbacks.releaseKey) \
50 (*(table)->callbacks.releaseKey)(key)
55 static INLINE
unsigned
56 hashString(const char *key
)
62 ret
^= *(char*)key
++ << ctr
;
63 ctr
= (ctr
+ 1) % sizeof (char *);
71 static INLINE
unsigned
72 hashPtr(const void *key
)
74 return ((size_t)key
/ sizeof(char*));
81 rellocateItem(WMHashTable
*table
, HashItem
*item
)
85 h
= HASH(table
, item
->key
);
87 item
->next
= table
->table
[h
];
88 table
->table
[h
] = item
;
93 rebuildTable(WMHashTable
*table
)
101 oldArray
= table
->table
;
102 oldSize
= table
->size
;
104 newSize
= table
->size
*2;
106 table
->table
= wmalloc(sizeof(char*)*newSize
);
107 memset(table
->table
, 0, sizeof(char*)*newSize
);
108 table
->size
= newSize
;
110 for (i
= 0; i
< oldSize
; i
++) {
111 while (oldArray
[i
]!=NULL
) {
112 next
= oldArray
[i
]->next
;
113 rellocateItem(table
, oldArray
[i
]);
123 WMCreateHashTable(WMHashTableCallbacks callbacks
)
127 table
= wmalloc(sizeof(HashTable
));
128 memset(table
, 0, sizeof(HashTable
));
130 table
->callbacks
= callbacks
;
132 table
->size
= INITIAL_CAPACITY
;
134 table
->table
= wmalloc(sizeof(HashItem
*)*table
->size
);
135 memset(table
->table
, 0, sizeof(HashItem
*)*table
->size
);
142 WMResetHashTable(WMHashTable
*table
)
144 HashItem
*item
, *tmp
;
147 for (i
= 0; i
< table
->size
; i
++) {
148 item
= table
->table
[i
];
151 RELKEY(table
, item
->key
);
157 table
->itemCount
= 0;
159 if (table
->size
> INITIAL_CAPACITY
) {
161 table
->size
= INITIAL_CAPACITY
;
162 table
->table
= wmalloc(sizeof(HashItem
*)*table
->size
);
164 memset(table
->table
, 0, sizeof(HashItem
*)*table
->size
);
169 WMFreeHashTable(WMHashTable
*table
)
171 HashItem
*item
, *tmp
;
174 for (i
= 0; i
< table
->size
; i
++) {
175 item
= table
->table
[i
];
178 RELKEY(table
, item
->key
);
189 WMCountHashTable(WMHashTable
*table
)
191 return table
->itemCount
;
196 WMHashGet(WMHashTable
*table
, const void *key
)
201 h
= HASH(table
, key
);
202 item
= table
->table
[h
];
204 if (table
->callbacks
.keyIsEqual
) {
206 if ((*table
->callbacks
.keyIsEqual
)(key
, item
->key
)) {
213 if (key
== item
->key
) {
220 return (void*)item
->data
;
227 WMHashGetItemAndKey(WMHashTable
*table
, const void *key
,
228 void **retItem
, void **retKey
)
233 h
= HASH(table
, key
);
234 item
= table
->table
[h
];
236 if (table
->callbacks
.keyIsEqual
) {
238 if ((*table
->callbacks
.keyIsEqual
)(key
, item
->key
)) {
245 if (key
== item
->key
) {
253 *retKey
= (void*)item
->key
;
255 *retItem
= (void*)item
->data
;
265 WMHashInsert(WMHashTable
*table
, const void *key
, const void *data
)
271 h
= HASH(table
, key
);
272 /* look for the entry */
273 item
= table
->table
[h
];
274 if (table
->callbacks
.keyIsEqual
) {
276 if ((*table
->callbacks
.keyIsEqual
)(key
, item
->key
)) {
284 if (key
== item
->key
) {
297 RELKEY(table
, item
->key
);
298 item
->key
= DUPKEY(table
, key
);
304 nitem
= wmalloc(sizeof(HashItem
));
305 nitem
->key
= DUPKEY(table
, key
);
307 nitem
->next
= table
->table
[h
];
308 table
->table
[h
] = nitem
;
313 /* OPTIMIZE: put this in an idle handler.*/
314 if (table
->itemCount
> table
->size
) {
316 printf("rebuilding hash table...\n");
320 printf("finished rebuild.\n");
329 deleteFromList(HashTable
*table
, HashItem
*item
, const void *key
)
336 if ((table
->callbacks
.keyIsEqual
337 && (*table
->callbacks
.keyIsEqual
)(key
, item
->key
))
338 || (!table
->callbacks
.keyIsEqual
&& key
==item
->key
)) {
341 RELKEY(table
, item
->key
);
349 item
->next
= deleteFromList(table
, item
->next
, key
);
356 WMHashRemove(WMHashTable
*table
, const void *key
)
360 h
= HASH(table
, key
);
362 table
->table
[h
] = deleteFromList(table
, table
->table
[h
], key
);
367 WMEnumerateHashTable(WMHashTable
*table
)
369 WMHashEnumerator enumerator
;
371 enumerator
.table
= table
;
372 enumerator
.index
= 0;
373 enumerator
.nextItem
= table
->table
[0];
381 WMNextHashEnumeratorItem(WMHashEnumerator
*enumerator
)
383 const void *data
= NULL
;
385 /* this assumes the table doesn't change between
386 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
388 if (enumerator
->nextItem
==NULL
) {
389 HashTable
*table
= enumerator
->table
;
390 while (++enumerator
->index
< table
->size
) {
391 if (table
->table
[enumerator
->index
]!=NULL
) {
392 enumerator
->nextItem
= table
->table
[enumerator
->index
];
398 if (enumerator
->nextItem
) {
399 data
= ((HashItem
*)enumerator
->nextItem
)->data
;
400 enumerator
->nextItem
= ((HashItem
*)enumerator
->nextItem
)->next
;
408 WMNextHashEnumeratorKey(WMHashEnumerator
*enumerator
)
410 const void *key
= NULL
;
412 /* this assumes the table doesn't change between
413 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
415 if (enumerator
->nextItem
==NULL
) {
416 HashTable
*table
= enumerator
->table
;
417 while (++enumerator
->index
< table
->size
) {
418 if (table
->table
[enumerator
->index
]!=NULL
) {
419 enumerator
->nextItem
= table
->table
[enumerator
->index
];
425 if (enumerator
->nextItem
) {
426 key
= ((HashItem
*)enumerator
->nextItem
)->key
;
427 enumerator
->nextItem
= ((HashItem
*)enumerator
->nextItem
)->next
;
435 WMNextHashEnumeratorItemAndKey(WMHashEnumerator
*enumerator
,
436 void **item
, void **key
)
438 /* this assumes the table doesn't change between
439 * WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
441 if (enumerator
->nextItem
==NULL
) {
442 HashTable
*table
= enumerator
->table
;
443 while (++enumerator
->index
< table
->size
) {
444 if (table
->table
[enumerator
->index
]!=NULL
) {
445 enumerator
->nextItem
= table
->table
[enumerator
->index
];
451 if (enumerator
->nextItem
) {
453 *item
= (void*)((HashItem
*)enumerator
->nextItem
)->data
;
455 *key
= (void*)((HashItem
*)enumerator
->nextItem
)->key
;
456 enumerator
->nextItem
= ((HashItem
*)enumerator
->nextItem
)->next
;
466 compareStrings(const char *key1
, const char *key2
)
468 return strcmp(key1
, key2
)==0;
472 typedef unsigned (*hashFunc
)(const void*);
473 typedef Bool (*isEqualFunc
)(const void*, const void*);
474 typedef void* (*retainFunc
)(const void*);
475 typedef void (*releaseFunc
)(const void*);
478 const WMHashTableCallbacks WMIntHashCallbacks
= {
485 const WMHashTableCallbacks WMStringHashCallbacks
= {
486 (hashFunc
)hashString
,
487 (isEqualFunc
)compareStrings
,
494 const WMHashTableCallbacks WMStringPointerHashCallbacks
= {
495 (hashFunc
)hashString
,
496 (isEqualFunc
)compareStrings
,