Postfix3.3.1
binhash.c
[詳解]
1 /*++
2 /* NAME
3 /* binhash 3
4 /* SUMMARY
5 /* hash table manager
6 /* SYNOPSIS
7 /* #include <binhash.h>
8 /*
9 /* typedef struct {
10 /* .in +4
11 /* void *key;
12 /* ssize_t key_len;
13 /* void *value;
14 /* /* private fields... */
15 /* .in -4
16 /* } BINHASH_INFO;
17 /*
18 /* BINHASH *binhash_create(size)
19 /* ssize_t size;
20 /*
21 /* BINHASH_INFO *binhash_enter(table, key, key_len, value)
22 /* BINHASH *table;
23 /* const void *key;
24 /* ssize_t key_len;
25 /* void *value;
26 /*
27 /* char *binhash_find(table, key, key_len)
28 /* BINHASH *table;
29 /* const void *key;
30 /* ssize_t key_len;
31 /*
32 /* BINHASH_INFO *binhash_locate(table, key, key_len)
33 /* BINHASH *table;
34 /* const void *key;
35 /* ssize_t key_len;
36 /*
37 /* void binhash_delete(table, key, key_len, free_fn)
38 /* BINHASH *table;
39 /* const void *key;
40 /* ssize_t key_len;
41 /* void (*free_fn)(void *);
42 /*
43 /* void binhash_free(table, free_fn)
44 /* BINHASH *table;
45 /* void (*free_fn)(void *);
46 /*
47 /* void binhash_walk(table, action, ptr)
48 /* BINHASH *table;
49 /* void (*action)(BINHASH_INFO *info, void *ptr);
50 /* void *ptr;
51 /*
52 /* BINHASH_INFO **binhash_list(table)
53 /* BINHASH *table;
54 /* DESCRIPTION
55 /* This module maintains one or more hash tables. Each table entry
56 /* consists of a unique binary-valued lookup key and a generic
57 /* character-pointer value.
58 /* The tables are automatically resized when they fill up. When the
59 /* values to be remembered are not character pointers, proper casts
60 /* should be used or the code will not be portable.
61 /*
62 /* binhash_create() creates a table of the specified size and returns a
63 /* pointer to the result. The lookup keys are saved with mymemdup().
64 /*
65 /* binhash_enter() stores a (key, value) pair into the specified table
66 /* and returns a pointer to the resulting entry. The code does not
67 /* check if an entry with that key already exists: use binhash_locate()
68 /* for updating an existing entry. The key is copied; the value is not.
69 /*
70 /* binhash_find() returns the value that was stored under the given key,
71 /* or a null pointer if it was not found. In order to distinguish
72 /* a null value from a non-existent value, use binhash_locate().
73 /*
74 /* binhash_locate() returns a pointer to the entry that was stored
75 /* for the given key, or a null pointer if it was not found.
76 /*
77 /* binhash_delete() removes one entry that was stored under the given key.
78 /* If the free_fn argument is not a null pointer, the corresponding
79 /* function is called with as argument the value that was stored under
80 /* the key.
81 /*
82 /* binhash_free() destroys a hash table, including contents. If the free_fn
83 /* argument is not a null pointer, the corresponding function is called
84 /* for each table entry, with as argument the value that was stored
85 /* with the entry.
86 /*
87 /* binhash_walk() invokes the action function for each table entry, with
88 /* a pointer to the entry as its argument. The ptr argument is passed
89 /* on to the action function.
90 /*
91 /* binhash_list() returns a null-terminated list of pointers to
92 /* all elements in the named table. The list should be passed to
93 /* myfree().
94 /* RESTRICTIONS
95 /* A callback function should not modify the hash table that is
96 /* specified to its caller.
97 /* DIAGNOSTICS
98 /* The following conditions are reported and cause the program to
99 /* terminate immediately: memory allocation failure; an attempt
100 /* to delete a non-existent entry.
101 /* SEE ALSO
102 /* mymalloc(3) memory management wrapper
103 /* LICENSE
104 /* .ad
105 /* .fi
106 /* The Secure Mailer license must be distributed with this software.
107 /* AUTHOR(S)
108 /* Wietse Venema
109 /* IBM T.J. Watson Research
110 /* P.O. Box 704
111 /* Yorktown Heights, NY 10598, USA
112 /*--*/
113 
114 /* C library */
115 
116 #include <sys_defs.h>
117 #include <string.h>
118 
119 /* Local stuff */
120 
121 #include "mymalloc.h"
122 #include "msg.h"
123 #include "binhash.h"
124 
125 /* binhash_hash - hash a string */
126 
127 static size_t binhash_hash(const void *key, ssize_t len, size_t size)
128 {
129  size_t h = 0;
130  size_t g;
131 
132  /*
133  * From the "Dragon" book by Aho, Sethi and Ullman.
134  */
135 
136  while (len-- > 0) {
137  h = (h << 4U) + *(unsigned const char *) key++;
138  if ((g = (h & 0xf0000000)) != 0) {
139  h ^= (g >> 24U);
140  h ^= g;
141  }
142  }
143  return (h % size);
144 }
145 
146 /* binhash_link - insert element into table */
147 
148 #define binhash_link(table, elm) { \
149  BINHASH_INFO **_h = table->data + binhash_hash(elm->key, elm->key_len, table->size);\
150  elm->prev = 0; \
151  if ((elm->next = *_h) != 0) \
152  (*_h)->prev = elm; \
153  *_h = elm; \
154  table->used++; \
155 }
156 
157 /* binhash_size - allocate and initialize hash table */
158 
159 static void binhash_size(BINHASH *table, size_t size)
160 {
161  BINHASH_INFO **h;
162 
163  size |= 1;
164 
165  table->data = h = (BINHASH_INFO **) mymalloc(size * sizeof(BINHASH_INFO *));
166  table->size = size;
167  table->used = 0;
168 
169  while (size-- > 0)
170  *h++ = 0;
171 }
172 
173 /* binhash_create - create initial hash table */
174 
175 BINHASH *binhash_create(ssize_t size)
176 {
177  BINHASH *table;
178 
179  table = (BINHASH *) mymalloc(sizeof(BINHASH));
180  binhash_size(table, size < 13 ? 13 : size);
181  return (table);
182 }
183 
184 /* binhash_grow - extend existing table */
185 
186 static void binhash_grow(BINHASH *table)
187 {
188  BINHASH_INFO *ht;
189  BINHASH_INFO *next;
190  ssize_t old_size = table->size;
191  BINHASH_INFO **h = table->data;
192  BINHASH_INFO **old_entries = h;
193 
194  binhash_size(table, 2 * old_size);
195 
196  while (old_size-- > 0) {
197  for (ht = *h++; ht; ht = next) {
198  next = ht->next;
199  binhash_link(table, ht);
200  }
201  }
202  myfree((void *) old_entries);
203 }
204 
205 /* binhash_enter - enter (key, value) pair */
206 
207 BINHASH_INFO *binhash_enter(BINHASH *table, const void *key, ssize_t key_len, void *value)
208 {
209  BINHASH_INFO *ht;
210 
211  if (table->used >= table->size)
212  binhash_grow(table);
213  ht = (BINHASH_INFO *) mymalloc(sizeof(BINHASH_INFO));
214  ht->key = mymemdup(key, key_len);
215  ht->key_len = key_len;
216  ht->value = value;
217  binhash_link(table, ht);
218  return (ht);
219 }
220 
221 /* binhash_find - lookup value */
222 
223 void *binhash_find(BINHASH *table, const void *key, ssize_t key_len)
224 {
225  BINHASH_INFO *ht;
226 
227 #define KEY_EQ(x,y,l) (((unsigned char *) x)[0] == ((unsigned char *) y)[0] && memcmp(x,y,l) == 0)
228 
229  if (table != 0)
230  for (ht = table->data[binhash_hash(key, key_len, table->size)]; ht; ht = ht->next)
231  if (key_len == ht->key_len && KEY_EQ(key, ht->key, key_len))
232  return (ht->value);
233  return (0);
234 }
235 
236 /* binhash_locate - lookup entry */
237 
238 BINHASH_INFO *binhash_locate(BINHASH *table, const void *key, ssize_t key_len)
239 {
240  BINHASH_INFO *ht;
241 
242  if (table != 0)
243  for (ht = table->data[binhash_hash(key, key_len, table->size)]; ht; ht = ht->next)
244  if (key_len == ht->key_len && KEY_EQ(key, ht->key, key_len))
245  return (ht);
246  return (0);
247 }
248 
249 /* binhash_delete - delete one entry */
250 
251 void binhash_delete(BINHASH *table, const void *key, ssize_t key_len, void (*free_fn) (void *))
252 {
253  if (table != 0) {
254  BINHASH_INFO *ht;
255  BINHASH_INFO **h = table->data + binhash_hash(key, key_len, table->size);
256 
257  for (ht = *h; ht; ht = ht->next) {
258  if (key_len == ht->key_len && KEY_EQ(key, ht->key, key_len)) {
259  if (ht->next)
260  ht->next->prev = ht->prev;
261  if (ht->prev)
262  ht->prev->next = ht->next;
263  else
264  *h = ht->next;
265  table->used--;
266  myfree(ht->key);
267  if (free_fn)
268  (*free_fn) (ht->value);
269  myfree((void *) ht);
270  return;
271  }
272  }
273  msg_panic("binhash_delete: unknown_key: \"%s\"", (char *) key);
274  }
275 }
276 
277 /* binhash_free - destroy hash table */
278 
279 void binhash_free(BINHASH *table, void (*free_fn) (void *))
280 {
281  if (table != 0) {
282  ssize_t i = table->size;
283  BINHASH_INFO *ht;
284  BINHASH_INFO *next;
285  BINHASH_INFO **h = table->data;
286 
287  while (i-- > 0) {
288  for (ht = *h++; ht; ht = next) {
289  next = ht->next;
290  myfree(ht->key);
291  if (free_fn)
292  (*free_fn) (ht->value);
293  myfree((void *) ht);
294  }
295  }
296  myfree((void *) table->data);
297  table->data = 0;
298  myfree((void *) table);
299  }
300 }
301 
302 /* binhash_walk - iterate over hash table */
303 
304 void binhash_walk(BINHASH *table, void (*action) (BINHASH_INFO *, void *),
305  void *ptr) {
306  if (table != 0) {
307  ssize_t i = table->size;
308  BINHASH_INFO **h = table->data;
309  BINHASH_INFO *ht;
310 
311  while (i-- > 0)
312  for (ht = *h++; ht; ht = ht->next)
313  (*action) (ht, ptr);
314  }
315 }
316 
317 /* binhash_list - list all table members */
318 
320 BINHASH *table;
321 {
322  BINHASH_INFO **list;
323  BINHASH_INFO *member;
324  ssize_t count = 0;
325  ssize_t i;
326 
327  if (table != 0) {
328  list = (BINHASH_INFO **) mymalloc(sizeof(*list) * (table->used + 1));
329  for (i = 0; i < table->size; i++)
330  for (member = table->data[i]; member != 0; member = member->next)
331  list[count++] = member;
332  } else {
333  list = (BINHASH_INFO **) mymalloc(sizeof(*list));
334  }
335  list[count] = 0;
336  return (list);
337 }
void myfree(void *ptr)
Definition: mymalloc.c:207
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
BINHASH * binhash_create(ssize_t size)
Definition: binhash.c:175
void * value
Definition: binhash.h:19
BINHASH_INFO * binhash_enter(BINHASH *table, const void *key, ssize_t key_len, void *value)
Definition: binhash.c:207
BINHASH_INFO * binhash_locate(BINHASH *table, const void *key, ssize_t key_len)
Definition: binhash.c:238
void * key
Definition: binhash.h:17
#define KEY_EQ(x, y, l)
BINHASH_INFO ** binhash_list(BINHASH *table)
Definition: binhash.c:319
ssize_t used
Definition: binhash.h:28
void binhash_walk(BINHASH *table, void(*action)(BINHASH_INFO *, void *), void *ptr)
Definition: binhash.c:304
ssize_t size
Definition: binhash.h:27
BINHASH_INFO ** data
Definition: binhash.h:29
void binhash_free(BINHASH *table, void(*free_fn)(void *))
Definition: binhash.c:279
struct BINHASH_INFO * prev
Definition: binhash.h:21
#define binhash_link(table, elm)
Definition: binhash.c:148
char * mymemdup(const void *ptr, ssize_t len)
Definition: mymalloc.c:264
struct BINHASH_INFO * next
Definition: binhash.h:20
void * binhash_find(BINHASH *table, const void *key, ssize_t key_len)
Definition: binhash.c:223
void binhash_delete(BINHASH *table, const void *key, ssize_t key_len, void(*free_fn)(void *))
Definition: binhash.c:251
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
ssize_t key_len
Definition: binhash.h:18