~ubuntu-branches/ubuntu/trusty/postfix/trusty-proposed

« back to all changes in this revision

Viewing changes to src/util/binhash.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-02-27 09:33:07 UTC
  • Revision ID: james.westby@ubuntu.com-20050227093307-cn789t27ibnlh6tf
Tags: upstream-2.1.5
ImportĀ upstreamĀ versionĀ 2.1.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
/*              char    *key;
 
12
/*              int     key_len;
 
13
/*              char    *value;
 
14
/*              /* private fields... */
 
15
/* .in -4
 
16
/*      } BINHASH_INFO;
 
17
/*
 
18
/*      BINHASH *binhash_create(size)
 
19
/*      int     size;
 
20
/*
 
21
/*      BINHASH_INFO *binhash_enter(table, key, key_len, value)
 
22
/*      BINHASH *table;
 
23
/*      const char *key;
 
24
/*      int     key_len;
 
25
/*      char    *value;
 
26
/*
 
27
/*      char    *binhash_find(table, key, key_len)
 
28
/*      BINHASH *table;
 
29
/*      const char *key;
 
30
/*      int     key_len;
 
31
/*
 
32
/*      BINHASH_INFO *binhash_locate(table, key, key_len)
 
33
/*      BINHASH *table;
 
34
/*      const char *key;
 
35
/*      int     key_len;
 
36
/*
 
37
/*      void    binhash_delete(table, key, key_len, free_fn)
 
38
/*      BINHASH *table;
 
39
/*      const char *key;
 
40
/*      int     key_len;
 
41
/*      void    (*free_fn)(char *);
 
42
/*
 
43
/*      void    binhash_free(table, free_fn)
 
44
/*      BINHASH *table;
 
45
/*      void    (*free_fn)(char *);
 
46
/*
 
47
/*      void    binhash_walk(table, action, ptr)
 
48
/*      BINHASH *table;
 
49
/*      void    (*action)(BINHASH_INFO *info, char *ptr);
 
50
/*      char    *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 strdup().
 
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 unsigned binhash_hash(const char *key, int len, unsigned size)
 
128
{
 
129
    unsigned long h = 0;
 
130
    unsigned long g;
 
131
 
 
132
    /*
 
133
     * From the "Dragon" book by Aho, Sethi and Ullman.
 
134
     */
 
135
 
 
136
    while (len-- > 0) {
 
137
        h = (h << 4) + *key++;
 
138
        if ((g = (h & 0xf0000000)) != 0) {
 
139
            h ^= (g >> 24);
 
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, unsigned 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(int 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
    unsigned 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((char *) old_entries);
 
203
}
 
204
 
 
205
/* binhash_enter - enter (key, value) pair */
 
206
 
 
207
BINHASH_INFO *binhash_enter(BINHASH *table, const char *key, int key_len, char *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
char   *binhash_find(BINHASH *table, const char *key, int key_len)
 
224
{
 
225
    BINHASH_INFO *ht;
 
226
 
 
227
#define KEY_EQ(x,y,l) (x[0] == 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 char *key, int key_len)
 
239
{
 
240
    BINHASH_INFO *ht;
 
241
 
 
242
#define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0)
 
243
 
 
244
    if (table != 0)
 
245
        for (ht = table->data[binhash_hash(key, key_len, table->size)]; ht; ht = ht->next)
 
246
            if (key_len == ht->key_len && KEY_EQ(key, ht->key, key_len))
 
247
                return (ht);
 
248
    return (0);
 
249
}
 
250
 
 
251
/* binhash_delete - delete one entry */
 
252
 
 
253
void    binhash_delete(BINHASH *table, const char *key, int key_len, void (*free_fn) (char *))
 
254
{
 
255
    if (table != 0) {
 
256
        BINHASH_INFO *ht;
 
257
        BINHASH_INFO **h = table->data + binhash_hash(key, key_len, table->size);
 
258
 
 
259
#define KEY_EQ(x,y,l) (x[0] == y[0] && memcmp(x,y,l) == 0)
 
260
 
 
261
        for (ht = *h; ht; ht = ht->next) {
 
262
            if (key_len == ht->key_len && KEY_EQ(key, ht->key, key_len)) {
 
263
                if (ht->next)
 
264
                    ht->next->prev = ht->prev;
 
265
                if (ht->prev)
 
266
                    ht->prev->next = ht->next;
 
267
                else
 
268
                    *h = ht->next;
 
269
                table->used--;
 
270
                myfree(ht->key);
 
271
                if (free_fn)
 
272
                    (*free_fn) (ht->value);
 
273
                myfree((char *) ht);
 
274
                return;
 
275
            }
 
276
        }
 
277
        msg_panic("binhash_delete: unknown_key: \"%s\"", key);
 
278
    }
 
279
}
 
280
 
 
281
/* binhash_free - destroy hash table */
 
282
 
 
283
void    binhash_free(BINHASH *table, void (*free_fn) (char *))
 
284
{
 
285
    if (table != 0) {
 
286
        unsigned i = table->size;
 
287
        BINHASH_INFO *ht;
 
288
        BINHASH_INFO *next;
 
289
        BINHASH_INFO **h = table->data;
 
290
 
 
291
        while (i-- > 0) {
 
292
            for (ht = *h++; ht; ht = next) {
 
293
                next = ht->next;
 
294
                myfree(ht->key);
 
295
                if (free_fn)
 
296
                    (*free_fn) (ht->value);
 
297
                myfree((char *) ht);
 
298
            }
 
299
        }
 
300
        myfree((char *) table->data);
 
301
        table->data = 0;
 
302
        myfree((char *) table);
 
303
    }
 
304
}
 
305
 
 
306
/* binhash_walk - iterate over hash table */
 
307
 
 
308
void    binhash_walk(BINHASH *table, void (*action) (BINHASH_INFO *, char *),
 
309
                             char *ptr) {
 
310
    if (table != 0) {
 
311
        unsigned i = table->size;
 
312
        BINHASH_INFO **h = table->data;
 
313
        BINHASH_INFO *ht;
 
314
 
 
315
        while (i-- > 0)
 
316
            for (ht = *h++; ht; ht = ht->next)
 
317
                (*action) (ht, ptr);
 
318
    }
 
319
}
 
320
 
 
321
/* binhash_list - list all table members */
 
322
 
 
323
BINHASH_INFO **binhash_list(table)
 
324
BINHASH *table;
 
325
{
 
326
    BINHASH_INFO **list;
 
327
    BINHASH_INFO *member;
 
328
    int     count = 0;
 
329
    int     i;
 
330
 
 
331
    if (table != 0) {
 
332
        list = (BINHASH_INFO **) mymalloc(sizeof(*list) * (table->used + 1));
 
333
        for (i = 0; i < table->size; i++)
 
334
            for (member = table->data[i]; member != 0; member = member->next)
 
335
                list[count++] = member;
 
336
    } else {
 
337
        list = (BINHASH_INFO **) mymalloc(sizeof(*list));
 
338
    }
 
339
    list[count] = 0;
 
340
    return (list);
 
341
}