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
];
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
);
190 WMHashGet(WMHashTable
*table
, const void *key
)
195 h
= HASH(table
, key
);
196 item
= table
->table
[h
];
198 if (table
->callbacks
.keyIsEqual
) {
200 if ((*table
->callbacks
.keyIsEqual
)(key
, item
->key
)) {
207 if (key
== item
->key
) {
214 return (void*)item
->data
;
222 WMHashInsert(WMHashTable
*table
, const void *key
, const void *data
)
228 h
= HASH(table
, key
);
229 /* look for the entry */
230 item
= table
->table
[h
];
231 if (table
->callbacks
.keyIsEqual
) {
233 if ((*table
->callbacks
.keyIsEqual
)(key
, item
->key
)) {
241 if (key
== item
->key
) {
254 RELKEY(table
, item
->key
);
255 item
->key
= DUPKEY(table
, key
);
261 nitem
= wmalloc(sizeof(HashItem
));
262 nitem
->key
= DUPKEY(table
, key
);
264 nitem
->next
= table
->table
[h
];
265 table
->table
[h
] = nitem
;
270 /* OPTIMIZE: put this in an idle handler.*/
271 if (table
->itemCount
> table
->size
) {
273 printf("rebuilding hash table...\n");
277 printf("finished rebuild.\n");
286 deleteFromList(HashTable
*table
, HashItem
*item
, const void *key
)
293 if ((table
->callbacks
.keyIsEqual
294 && (*table
->callbacks
.keyIsEqual
)(key
, item
->key
))
295 || (!table
->callbacks
.keyIsEqual
&& key
==item
->key
)) {
298 RELKEY(table
, item
->key
);
306 item
->next
= deleteFromList(table
, item
->next
, key
);
313 WMHashRemove(WMHashTable
*table
, const void *key
)
317 h
= HASH(table
, key
);
319 table
->table
[h
] = deleteFromList(table
, table
->table
[h
], key
);
324 WMEnumerateHashTable(WMHashTable
*table
)
326 WMHashEnumerator enumerator
;
328 enumerator
.table
= table
;
329 enumerator
.index
= 0;
330 enumerator
.nextItem
= table
->table
[0];
338 WMNextHashEnumeratorItem(WMHashEnumerator
*enumerator
)
340 const void *data
= NULL
;
342 /* this assumes the table doesn't change between
343 * WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
345 if (enumerator
->nextItem
==NULL
) {
346 HashTable
*table
= enumerator
->table
;
347 while (++enumerator
->index
< table
->size
) {
348 if (table
->table
[enumerator
->index
]!=NULL
) {
349 enumerator
->nextItem
= table
->table
[enumerator
->index
];
355 if (enumerator
->nextItem
) {
356 data
= ((HashItem
*)enumerator
->nextItem
)->data
;
357 enumerator
->nextItem
= ((HashItem
*)enumerator
->nextItem
)->next
;
365 WMNextHashEnumeratorKey(WMHashEnumerator
*enumerator
)
367 const void *key
= NULL
;
369 /* this assumes the table doesn't change between
370 * WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
372 if (enumerator
->nextItem
==NULL
) {
373 HashTable
*table
= enumerator
->table
;
374 while (++enumerator
->index
< table
->size
) {
375 if (table
->table
[enumerator
->index
]!=NULL
) {
376 enumerator
->nextItem
= table
->table
[enumerator
->index
];
382 if (enumerator
->nextItem
) {
383 key
= ((HashItem
*)enumerator
->nextItem
)->key
;
384 enumerator
->nextItem
= ((HashItem
*)enumerator
->nextItem
)->next
;
392 WMCountHashTable(WMHashTable
*table
)
394 return table
->itemCount
;
399 compareStrings(const char *key1
, const char *key2
)
401 return strcmp(key1
, key2
)==0;
405 typedef unsigned (*hashFunc
)(const void*);
406 typedef Bool (*isEqualFunc
)(const void*, const void*);
407 typedef void* (*retainFunc
)(const void*);
408 typedef void (*releaseFunc
)(const void*);
411 const WMHashTableCallbacks WMIntHashCallbacks
= {
418 const WMHashTableCallbacks WMStringHashCallbacks
= {
419 (hashFunc
)hashString
,
420 (isEqualFunc
)compareStrings
,
427 const WMHashTableCallbacks WMStringPointerHashCallbacks
= {
428 (hashFunc
)hashString
,
429 (isEqualFunc
)compareStrings
,