9 /* #include <binhash.h>
16 /* /* private fields... */
20 /* BINHASH *binhash_create(size)
23 /* BINHASH_INFO *binhash_enter(table, key, key_len, value)
29 /* char *binhash_find(table, key, key_len)
34 /* BINHASH_INFO *binhash_locate(table, key, key_len)
39 /* void binhash_delete(table, key, key_len, free_fn)
43 /* void (*free_fn)(char *);
45 /* void binhash_free(table, free_fn)
47 /* void (*free_fn)(char *);
49 /* void binhash_walk(table, action, ptr)
51 /* void (*action)(BINHASH_INFO *info, char *ptr);
54 /* BINHASH_INFO **binhash_list(table)
57 /* This module maintains one or more hash tables. Each table entry
58 /* consists of a unique binary-valued lookup key and a generic
59 /* character-pointer value.
60 /* The tables are automatically resized when they fill up. When the
61 /* values to be remembered are not character pointers, proper casts
62 /* should be used or the code will not be portable.
64 /* binhash_create() creates a table of the specified size and returns a
65 /* pointer to the result. The lookup keys are saved with strdup().
67 /* binhash_enter() stores a (key, value) pair into the specified table
68 /* and returns a pointer to the resulting entry. The code does not
69 /* check if an entry with that key already exists: use binhash_locate()
70 /* for updating an existing entry. The key is copied; the value is not.
72 /* binhash_find() returns the value that was stored under the given key,
73 /* or a null pointer if it was not found. In order to distinguish
74 /* a null value from a non-existent value, use binhash_locate().
76 /* binhash_locate() returns a pointer to the entry that was stored
77 /* for the given key, or a null pointer if it was not found.
79 /* binhash_delete() removes one entry that was stored under the given key.
80 /* If the free_fn argument is not a null pointer, the corresponding
81 /* function is called with as argument the value that was stored under
84 /* binhash_free() destroys a hash table, including contents. If the free_fn
85 /* argument is not a null pointer, the corresponding function is called
86 /* for each table entry, with as argument the value that was stored
89 /* binhash_walk() invokes the action function for each table entry, with
90 /* a pointer to the entry as its argument. The ptr argument is passed
91 /* on to the action function.
93 /* binhash_list() returns a null-terminated list of pointers to
94 /* all elements in the named table. The list should be passed to
97 /* A callback function should not modify the hash table that is
98 /* specified to its caller.
100 /* The following conditions are reported and cause the program to
101 /* terminate immediately: memory allocation failure; an attempt
102 /* to delete a non-existent entry.
104 /* mymalloc(3) memory management wrapper
108 /* The Secure Mailer license must be distributed with this software.
111 /* IBM T.J. Watson Research
113 /* Yorktown Heights, NY 10598, USA
118 #include <sys_defs.h>
123 #include "mymalloc.h"
127 /* binhash_hash - hash a string */
129 static unsigned binhash_hash(const char *key
, int len
, unsigned size
)
135 * From the "Dragon" book by Aho, Sethi and Ullman.
139 h
= (h
<< 4U) + *key
++;
140 if ((g
= (h
& 0xf0000000)) != 0) {
148 /* binhash_link - insert element into table */
150 #define binhash_link(table, elm) { \
151 BINHASH_INFO **_h = table->data + binhash_hash(elm->key, elm->key_len, table->size);\
153 if ((elm->next = *_h) != 0) \
159 /* binhash_size - allocate and initialize hash table */
161 static void binhash_size(BINHASH
*table
, unsigned size
)
167 table
->data
= h
= (BINHASH_INFO
**) mymalloc(size
* sizeof(BINHASH_INFO
*));
175 /* binhash_create - create initial hash table */
177 BINHASH
*binhash_create(int size
)
181 table
= (BINHASH
*) mymalloc(sizeof(BINHASH
));
182 binhash_size(table
, size
< 13 ? 13 : size
);
186 /* binhash_grow - extend existing table */
188 static void binhash_grow(BINHASH
*table
)
192 unsigned old_size
= table
->size
;
193 BINHASH_INFO
**h
= table
->data
;
194 BINHASH_INFO
**old_entries
= h
;
196 binhash_size(table
, 2 * old_size
);
198 while (old_size
-- > 0) {
199 for (ht
= *h
++; ht
; ht
= next
) {
201 binhash_link(table
, ht
);
204 myfree((char *) old_entries
);
207 /* binhash_enter - enter (key, value) pair */
209 BINHASH_INFO
*binhash_enter(BINHASH
*table
, const char *key
, int key_len
, char *value
)
213 if (table
->used
>= table
->size
)
215 ht
= (BINHASH_INFO
*) mymalloc(sizeof(BINHASH_INFO
));
216 ht
->key
= mymemdup(key
, key_len
);
217 ht
->key_len
= key_len
;
219 binhash_link(table
, ht
);
223 /* binhash_find - lookup value */
225 char *binhash_find(BINHASH
*table
, const char *key
, int key_len
)
229 #define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0)
232 for (ht
= table
->data
[binhash_hash(key
, key_len
, table
->size
)]; ht
; ht
= ht
->next
)
233 if (key_len
== ht
->key_len
&& KEY_EQ(key
, ht
->key
, key_len
))
238 /* binhash_locate - lookup entry */
240 BINHASH_INFO
*binhash_locate(BINHASH
*table
, const char *key
, int key_len
)
244 #define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0)
247 for (ht
= table
->data
[binhash_hash(key
, key_len
, table
->size
)]; ht
; ht
= ht
->next
)
248 if (key_len
== ht
->key_len
&& KEY_EQ(key
, ht
->key
, key_len
))
253 /* binhash_delete - delete one entry */
255 void binhash_delete(BINHASH
*table
, const char *key
, int key_len
, void (*free_fn
) (char *))
259 BINHASH_INFO
**h
= table
->data
+ binhash_hash(key
, key_len
, table
->size
);
261 #define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0)
263 for (ht
= *h
; ht
; ht
= ht
->next
) {
264 if (key_len
== ht
->key_len
&& KEY_EQ(key
, ht
->key
, key_len
)) {
266 ht
->next
->prev
= ht
->prev
;
268 ht
->prev
->next
= ht
->next
;
274 (*free_fn
) (ht
->value
);
279 msg_panic("binhash_delete: unknown_key: \"%s\"", key
);
283 /* binhash_free - destroy hash table */
285 void binhash_free(BINHASH
*table
, void (*free_fn
) (char *))
288 unsigned i
= table
->size
;
291 BINHASH_INFO
**h
= table
->data
;
294 for (ht
= *h
++; ht
; ht
= next
) {
298 (*free_fn
) (ht
->value
);
302 myfree((char *) table
->data
);
304 myfree((char *) table
);
308 /* binhash_walk - iterate over hash table */
310 void binhash_walk(BINHASH
*table
, void (*action
) (BINHASH_INFO
*, char *),
313 unsigned i
= table
->size
;
314 BINHASH_INFO
**h
= table
->data
;
318 for (ht
= *h
++; ht
; ht
= ht
->next
)
323 /* binhash_list - list all table members */
325 BINHASH_INFO
**binhash_list(table
)
329 BINHASH_INFO
*member
;
334 list
= (BINHASH_INFO
**) mymalloc(sizeof(*list
) * (table
->used
+ 1));
335 for (i
= 0; i
< table
->size
; i
++)
336 for (member
= table
->data
[i
]; member
!= 0; member
= member
->next
)
337 list
[count
++] = member
;
339 list
= (BINHASH_INFO
**) mymalloc(sizeof(*list
));