]> mj.ucw.cz Git - libucw.git/blob - lib/hashtable.h
A couple of minor improvements to the generic hash tables:
[libucw.git] / lib / hashtable.h
1 /*
2  *      Sherlock Library -- Universal Hash Table
3  *
4  *      (c) 2002--2004 Martin Mares <mj@ucw.cz>
5  *      (c) 2002 Robert Spalek <robert@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 /*
12  *  This is not a normal header file, it's a generator of hash tables.
13  *  Each time you include it with parameters set in the corresponding
14  *  preprocessor macros, it generates a hash table with the parameters
15  *  given.
16  *
17  *  You need to specify:
18  *
19  *  HASH_NODE           data type where a node dwells (usually a struct).
20  *  HASH_PREFIX(x)      macro to add a name prefix (used on all global names
21  *                      defined by the hash table generator).
22  *
23  *  Then decide on type of keys:
24  *
25  *  HASH_KEY_ATOMIC=f   use node->f as a key of an atomic type (i.e.,
26  *                      a type which can be compared using `==')
27  *                      HASH_ATOMIC_TYPE (defaults to int).
28  *  | HASH_KEY_STRING=f use node->f as a string key, allocated
29  *                      separately from the rest of the node.
30  *  | HASH_KEY_ENDSTRING=f use node->f as a string key, allocated
31  *                      automatically at the end of the node struct
32  *                      (to be declared as "char f[1]" at the end).
33  *  | HASH_KEY_COMPLEX  use a multi-component key; as the name suggests,
34  *                      the passing of parameters is a bit complex then.
35  *                      The HASH_KEY_COMPLEX(x) macro should expand to
36  *                      `x k1, x k2, ... x kn' and you should also define:
37  *    HASH_KEY_DECL     declaration of function parameters in which key
38  *                      should be passed to all hash table operations.
39  *                      That is, `type1 k1, type2 k2, ... typen kn'.
40  *                      With complex keys, HASH_GIVE_HASHFN and HASH_GIVE_EQ
41  *                      are mandatory.
42  *
43  *  Then specify what operations you request (all names are automatically
44  *  prefixed by calling HASH_PREFIX):
45  *
46  *  <always defined>    init() -- initialize the hash table.
47  *  HASH_WANT_CLEANUP   cleanup() -- deallocate the hash table.
48  *  HASH_WANT_FIND      node *find(key) -- find first node with the specified
49  *                      key, return NULL if no such node exists.
50  *  HASH_WANT_FIND_NEXT node *find(node *start) -- find next node with the
51  *                      specified key, return NULL if no such node exists.
52  *  HASH_WANT_NEW       node *new(key) -- create new node with given key.
53  *                      Doesn't check whether it already exists.
54  *  HASH_WANT_LOOKUP    node *lookup(key) -- find node with given key,
55  *                      if it doesn't exist, create it. Defining
56  *                      HASH_GIVE_INIT_DATA is strongly recommended.
57  *  HASH_WANT_DELETE    int delete(key) -- delete and deallocate node
58  *                      with given key. Returns success.
59  *  HASH_WANT_REMOVE    remove(node *) -- delete and deallocate given node.
60  *
61  *  You can also supply several functions:
62  *
63  *  HASH_GIVE_HASHFN    unsigned int hash(key) -- calculate hash value of key.
64  *                      We have sensible default hash functions for strings
65  *                      and integers.
66  *  HASH_GIVE_EQ        int eq(key1, key2) -- return whether keys are equal.
67  *                      By default, we use == for atomic types and either
68  *                      strcmp or strcasecmp for strings.
69  *  HASH_GIVE_EXTRA_SIZE int extra_size(key) -- returns how many bytes after the
70  *                      node should be allocated for dynamic data. Default=0
71  *                      or length of the string with HASH_KEY_ENDSTRING.
72  *  HASH_GIVE_INIT_KEY  void init_key(node *,key) -- initialize key in a newly
73  *                      created node. Defaults: assignment for atomic keys
74  *                      and static strings, strcpy for end-allocated strings.
75  *  HASH_GIVE_INIT_DATA void init_data(node *) -- initialize data fields in a
76  *                      newly created node. Very useful for lookup operations.
77  *  HASH_GIVE_ALLOC     void *alloc(unsigned int size) -- allocate space for
78  *                      a node. Default is xmalloc() or pooled allocation, depending
79  *                      on HASH_USE_POOL and HASH_AUTO_POOL switches.
80  *                      void free(void *) -- the converse.
81  *
82  *  ... and a couple of extra parameters:
83  *
84  *  HASH_NOCASE         string comparisons should be case-insensitive.
85  *  HASH_DEFAULT_SIZE=n initially, use hash table of approx. `n' entries.
86  *  HASH_CONSERVE_SPACE use as little space as possible.
87  *  HASH_FN_BITS=n      The hash function gives only `n' significant bits.
88  *  HASH_ATOMIC_TYPE=t  Atomic values are of type `t' instead of int.
89  *  HASH_USE_POOL=pool  Allocate all nodes from given mempool. Note, however, that
90  *                      deallocation is not supported by mempools, so delete/remove
91  *                      will leak pool memory.
92  *  HASH_AUTO_POOL=size Create a pool of the given block size automatically.
93  *  HASH_TABLE_ALLOC    The hash table itself will be allocated and freed using
94  *                      the same allocation functions as the nodes instead of
95  *                      the default xmalloc().
96  *
97  *  You also get a iterator macro at no extra charge:
98  *
99  *  HASH_FOR_ALL(hash_prefix, variable)
100  *    {
101  *      // node *variable gets declared automatically
102  *      do_something_with_node(variable);
103  *      // use HASH_BREAK and HASH_CONTINUE instead of break and continue
104  *      // you must not alter contents of the hash table here
105  *    }
106  *  HASH_END_FOR;
107  *
108  *  Then include "lib/hashtable.h" and voila, you have a hash table
109  *  suiting all your needs (at least those which you've revealed :) ).
110  *
111  *  After including this file, all parameter macros are automatically
112  *  undef'd.
113  */
114
115 #ifndef _SHERLOCK_HASHFUNC_H
116 #include "lib/hashfunc.h"
117 #endif
118
119 #include <string.h>
120
121 /* Initial setup of parameters */
122
123 #if !defined(HASH_NODE) || !defined(HASH_PREFIX)
124 #error Some of the mandatory configuration macros are missing.
125 #endif
126
127 #if defined(HASH_KEY_ATOMIC) && !defined(HASH_CONSERVE_SPACE)
128 #define HASH_CONSERVE_SPACE
129 #endif
130
131 #define P(x) HASH_PREFIX(x)
132
133 /* Declare buckets and the hash table */
134
135 typedef HASH_NODE P(node);
136
137 typedef struct P(bucket) {
138   struct P(bucket) *next;
139 #ifndef HASH_CONSERVE_SPACE
140   uns hash;
141 #endif
142   P(node) n;
143 } P(bucket);
144
145 struct P(table) {
146   uns hash_size;
147   uns hash_count, hash_max, hash_min, hash_hard_max;
148   P(bucket) **ht;
149 } P(table);
150
151 #define T P(table)
152
153 /* Preset parameters */
154
155 #if defined(HASH_KEY_ATOMIC)
156
157 #define HASH_KEY(x) x HASH_KEY_ATOMIC
158
159 #ifndef HASH_ATOMIC_TYPE
160 #  define HASH_ATOMIC_TYPE int
161 #endif
162 #define HASH_KEY_DECL HASH_ATOMIC_TYPE HASH_KEY( )
163
164 #ifndef HASH_GIVE_HASHFN
165 #  define HASH_GIVE_HASHFN
166    static inline int P(hash) (HASH_ATOMIC_TYPE x)
167    { return hash_int(x); }
168 #endif
169
170 #ifndef HASH_GIVE_EQ
171 #  define HASH_GIVE_EQ
172    static inline int P(eq) (HASH_ATOMIC_TYPE x, HASH_ATOMIC_TYPE y)
173    { return x == y; }
174 #endif
175
176 #ifndef HASH_GIVE_INIT_KEY
177 #  define HASH_GIVE_INIT_KEY
178    static inline void P(init_key) (P(node) *n, HASH_ATOMIC_TYPE k)
179    { HASH_KEY(n->) = k; }
180 #endif
181
182 #elif defined(HASH_KEY_STRING) || defined(HASH_KEY_ENDSTRING)
183
184 #ifdef HASH_KEY_STRING
185 #  define HASH_KEY(x) x HASH_KEY_STRING
186 #  ifndef HASH_GIVE_INIT_KEY
187 #    define HASH_GIVE_INIT_KEY
188      static inline void P(init_key) (P(node) *n, char *k)
189      { HASH_KEY(n->) = k; }
190 #  endif
191 #else
192 #  define HASH_KEY(x) x HASH_KEY_ENDSTRING
193 #  define HASH_GIVE_EXTRA_SIZE
194    static inline int P(extra_size) (char *k)
195    { return strlen(k); }
196 #  ifndef HASH_GIVE_INIT_KEY
197 #    define HASH_GIVE_INIT_KEY
198      static inline void P(init_key) (P(node) *n, char *k)
199      { strcpy(HASH_KEY(n->), k); }
200 #  endif
201 #endif
202 #define HASH_KEY_DECL char *HASH_KEY( )
203
204 #ifndef HASH_GIVE_HASHFN
205 #define HASH_GIVE_HASHFN
206   static inline uns P(hash) (char *k)
207    {
208 #    ifdef HASH_NOCASE
209        return hash_string_nocase(k);
210 #    else
211        return hash_string(k);
212 #    endif
213    }
214 #endif
215
216 #ifndef HASH_GIVE_EQ
217 #  define HASH_GIVE_EQ
218    static inline int P(eq) (char *x, char *y)
219    {
220 #    ifdef HASH_NOCASE
221        return !strcasecmp(x,y);
222 #    else
223        return !strcmp(x,y);
224 #    endif
225    }
226 #endif
227
228 #elif defined(HASH_KEY_COMPLEX)
229
230 #define HASH_KEY(x) HASH_KEY_COMPLEX(x)
231
232 #else
233 #error You forgot to set the hash key type.
234 #endif
235
236 /* Defaults for missing parameters */
237
238 #ifndef HASH_GIVE_HASHFN
239 #error Unable to determine which hash function to use.
240 #endif
241
242 #ifndef HASH_GIVE_EQ
243 #error Unable to determine how to compare two keys.
244 #endif
245
246 #ifdef HASH_GIVE_EXTRA_SIZE
247 /* This trickery is needed to avoid `unused parameter' warnings */
248 #define HASH_EXTRA_SIZE P(extra_size)
249 #else
250 /*
251  *  Beware, C macros are expanded iteratively, not recursively,
252  *  hence we get only a _single_ argument, although the expansion
253  *  of HASH_KEY contains commas.
254  */
255 #define HASH_EXTRA_SIZE(x) 0
256 #endif
257
258 #ifndef HASH_GIVE_INIT_KEY
259 #error Unable to determine how to initialize keys.
260 #endif
261
262 #ifndef HASH_GIVE_INIT_DATA
263 static inline void P(init_data) (P(node) *n UNUSED)
264 {
265 }
266 #endif
267
268 #include <stdlib.h>
269
270 #ifdef HASH_GIVE_ALLOC
271 /* If the caller has requested to use his own allocation functions, do so */
272 static inline void P(init_alloc) (void) { }
273 static inline void P(cleanup_alloc) (void) { }
274
275 #elif defined(HASH_USE_POOL)
276 /* If the caller has requested to use his mempool, do so */
277 #include "lib/mempool.h"
278 static inline void * P(alloc) (unsigned int size) { return mp_alloc_fast(HASH_USE_POOL, size); }
279 static inline void P(free) (void *x UNUSED) { }
280 static inline void P(init_alloc) (void) { }
281 static inline void P(cleanup_alloc) (void) { }
282
283 #elif defined(HASH_AUTO_POOL)
284 /* Use our own pools */
285 #include "lib/mempool.h"
286 static struct mempool *P(pool);
287 static inline void * P(alloc) (unsigned int size) { return mp_alloc_fast(P(pool), size); }
288 static inline void P(free) (void *x UNUSED) { }
289 static inline void P(init_alloc) (void) { P(pool) = mp_new(HASH_AUTO_POOL); }
290 static inline void P(cleanup_alloc) (void) { mp_delete(P(pool)); }
291
292 #else
293 /* The default allocation method */
294 static inline void * P(alloc) (unsigned int size) { return xmalloc(size); }
295 static inline void P(free) (void *x) { xfree(x); }
296 static inline void P(init_alloc) (void) { }
297 static inline void P(cleanup_alloc) (void) { }
298
299 #endif
300
301 #ifdef HASH_TABLE_ALLOC
302 static inline void * P(table_alloc) (unsigned int size) { return P(alloc)(size); }
303 static inline void P(table_free) (void *x) { P(free)(x); }
304 #else
305 static inline void * P(table_alloc) (unsigned int size) { return xmalloc(size); }
306 static inline void P(table_free) (void *x) { xfree(x); }
307 #endif
308
309 #ifndef HASH_DEFAULT_SIZE
310 #define HASH_DEFAULT_SIZE 32
311 #endif
312
313 #ifndef HASH_FN_BITS
314 #define HASH_FN_BITS 32
315 #endif
316
317 /* Now the operations */
318
319 static void P(alloc_table) (void)
320 {
321   T.hash_size = nextprime(T.hash_size);
322   T.ht = P(table_alloc)(sizeof(void *) * T.hash_size);
323   bzero(T.ht, sizeof(void *) * T.hash_size);
324   if (2*T.hash_size < T.hash_hard_max)
325     T.hash_max = 2*T.hash_size;
326   else
327     T.hash_max = ~0U;
328   if (T.hash_size/2 > HASH_DEFAULT_SIZE)
329     T.hash_min = T.hash_size/4;
330   else
331     T.hash_min = 0;
332 }
333
334 static void P(init) (void)
335 {
336   T.hash_count = 0;
337   T.hash_size = HASH_DEFAULT_SIZE;
338 #if HASH_FN_BITS < 28
339   T.hash_hard_max = 1 << HASH_FN_BITS;
340 #else
341   T.hash_hard_max = 1 << 28;
342 #endif
343   P(alloc_table)();
344   P(init_alloc)();
345 }
346
347 #ifdef HASH_WANT_CLEANUP
348 static void P(cleanup) (void)
349 {
350 #ifndef HASH_USE_POOL
351   uns i;
352   P(bucket) *b, *bb;
353
354   for (i=0; i<T.hash_size; i++)
355     for (b=T.ht[i]; b; b=bb)
356       {
357         bb = b->next;
358         P(free)(b);
359       }
360 #endif
361   P(cleanup_alloc)();
362   P(table_free)(T.ht);
363 }
364 #endif
365
366 static inline uns P(bucket_hash) (P(bucket) *b)
367 {
368 #ifdef HASH_CONSERVE_SPACE
369   return P(hash)(HASH_KEY(b->n.));
370 #else
371   return b->hash;
372 #endif
373 }
374
375 static void P(rehash) (uns size)
376 {
377   P(bucket) *b, *nb;
378   P(bucket) **oldt = T.ht, **newt;
379   uns oldsize = T.hash_size;
380   uns i, h;
381
382   DBG("Rehashing %d->%d at count %d", oldsize, size, T.hash_count);
383   T.hash_size = size;
384   P(alloc_table)();
385   newt = T.ht;
386   for (i=0; i<oldsize; i++)
387     {
388       b = oldt[i];
389       while (b)
390         {
391           nb = b->next;
392           h = P(bucket_hash)(b) % T.hash_size;
393           b->next = newt[h];
394           newt[h] = b;
395           b = nb;
396         }
397     }
398   P(table_free)(oldt);
399 }
400
401 #ifdef HASH_WANT_FIND
402 static P(node) * P(find) (HASH_KEY_DECL)
403 {
404   uns h0 = P(hash) (HASH_KEY( ));
405   uns h = h0 % T.hash_size;
406   P(bucket) *b;
407
408   for (b=T.ht[h]; b; b=b->next)
409     {
410       if (
411 #ifndef HASH_CONSERVE_SPACE
412           b->hash == h0 &&
413 #endif
414           P(eq)(HASH_KEY( ), HASH_KEY(b->n.)))
415         return &b->n;
416     }
417   return NULL;
418 }
419 #endif
420
421 #ifdef HASH_WANT_FIND_NEXT
422 static P(node) * P(find_next) (P(node) *start)
423 {
424 #ifndef HASH_CONSERVE_SPACE
425   uns h0 = P(hash) (HASH_KEY(start->));
426 #endif
427   P(bucket) *b = SKIP_BACK(P(bucket), n, start);
428
429   for (b=b->next; b; b=b->next)
430     {
431       if (
432 #ifndef HASH_CONSERVE_SPACE
433           b->hash == h0 &&
434 #endif
435           P(eq)(HASH_KEY(start->), HASH_KEY(b->n.)))
436         return &b->n;
437     }
438   return NULL;
439 }
440 #endif
441
442 #ifdef HASH_WANT_NEW
443 static P(node) * P(new) (HASH_KEY_DECL)
444 {
445   uns h0, h;
446   P(bucket) *b;
447
448   h0 = P(hash) (HASH_KEY( ));
449   h = h0 % T.hash_size;
450   b = P(alloc) (sizeof(struct P(bucket)) + HASH_EXTRA_SIZE(HASH_KEY( )));
451   b->next = T.ht[h];
452   T.ht[h] = b;
453 #ifndef HASH_CONSERVE_SPACE
454   b->hash = h0;
455 #endif
456   P(init_key)(&b->n, HASH_KEY( ));
457   P(init_data)(&b->n);
458   if (T.hash_count++ >= T.hash_max)
459     P(rehash)(2*T.hash_size);
460   return &b->n;
461 }
462 #endif
463
464 #ifdef HASH_WANT_LOOKUP
465 static P(node) * P(lookup) (HASH_KEY_DECL)
466 {
467   uns h0 = P(hash) (HASH_KEY( ));
468   uns h = h0 % T.hash_size;
469   P(bucket) *b;
470
471   for (b=T.ht[h]; b; b=b->next)
472     {
473       if (
474 #ifndef HASH_CONSERVE_SPACE
475           b->hash == h0 &&
476 #endif
477           P(eq)(HASH_KEY( ), HASH_KEY(b->n.)))
478         return &b->n;
479     }
480
481   b = P(alloc) (sizeof(struct P(bucket)) + HASH_EXTRA_SIZE(HASH_KEY( )));
482   b->next = T.ht[h];
483   T.ht[h] = b;
484 #ifndef HASH_CONSERVE_SPACE
485   b->hash = h0;
486 #endif
487   P(init_key)(&b->n, HASH_KEY( ));
488   P(init_data)(&b->n);
489   if (T.hash_count++ >= T.hash_max)
490     P(rehash)(2*T.hash_size);
491   return &b->n;
492 }
493 #endif
494
495 #ifdef HASH_WANT_DELETE
496 static int P(delete) (HASH_KEY_DECL)
497 {
498   uns h0 = P(hash) (HASH_KEY( ));
499   uns h = h0 % T.hash_size;
500   P(bucket) *b, **bb;
501
502   for (bb=&T.ht[h]; b=*bb; bb=&b->next)
503     {
504       if (
505 #ifndef HASH_CONSERVE_SPACE
506           b->hash == h0 &&
507 #endif
508           P(eq)(HASH_KEY( ), HASH_KEY(b->n.)))
509         {
510           *bb = b->next;
511           P(free)(b);
512           if (--T.hash_count < T.hash_min)
513             P(rehash)(T.hash_size/2);
514           return 1;
515         }
516     }
517   return 0;
518 }
519 #endif
520
521 #ifdef HASH_WANT_REMOVE
522 static void P(remove) (P(node) *n)
523 {
524   P(bucket) *x = SKIP_BACK(struct P(bucket), n, n);
525   uns h0 = P(bucket_hash)(x);
526   uns h = h0 % T.hash_size;
527   P(bucket) *b, **bb;
528
529   for (bb=&T.ht[h]; (b=*bb) && b != x; bb=&b->next)
530     ;
531   ASSERT(b);
532   *bb = b->next;
533   P(free)(b);
534   if (--T.hash_count < T.hash_min)
535     P(rehash)(T.hash_size/2);
536 }
537 #endif
538
539 /* And the iterator */
540
541 #ifndef HASH_FOR_ALL
542
543 #define HASH_FOR_ALL(h_px, h_var)                                                       \
544 do {                                                                                    \
545   uns h_slot;                                                                           \
546   struct GLUE_(h_px,bucket) *h_buck;                                                    \
547   for (h_slot=0; h_slot < GLUE_(h_px,table).hash_size; h_slot++)                        \
548     for (h_buck = GLUE_(h_px,table).ht[h_slot]; h_buck; h_buck = h_buck->next)  \
549       {                                                                                 \
550         GLUE_(h_px,node) *h_var = &h_buck->n;
551 #define HASH_END_FOR } } while(0)
552 #define HASH_BREAK 
553 #define HASH_CONTINUE continue
554
555 #endif
556
557 /* Finally, undefine all the parameters */
558
559 #undef P
560 #undef T
561
562 #undef HASH_ATOMIC_TYPE
563 #undef HASH_CONSERVE_SPACE
564 #undef HASH_DEFAULT_SIZE
565 #undef HASH_EXTRA_SIZE
566 #undef HASH_FN_BITS
567 #undef HASH_GIVE_ALLOC
568 #undef HASH_GIVE_EQ
569 #undef HASH_GIVE_EXTRA_SIZE
570 #undef HASH_GIVE_HASHFN
571 #undef HASH_GIVE_INIT_DATA
572 #undef HASH_GIVE_INIT_KEY
573 #undef HASH_KEY
574 #undef HASH_KEY_ATOMIC
575 #undef HASH_KEY_COMPLEX
576 #undef HASH_KEY_DECL
577 #undef HASH_KEY_ENDSTRING
578 #undef HASH_KEY_STRING
579 #undef HASH_NOCASE
580 #undef HASH_NODE
581 #undef HASH_PREFIX
582 #undef HASH_USE_POOL
583 #undef HASH_AUTO_POOL
584 #undef HASH_WANT_CLEANUP
585 #undef HASH_WANT_DELETE
586 #undef HASH_WANT_FIND
587 #undef HASH_WANT_FIND_NEXT
588 #undef HASH_WANT_LOOKUP
589 #undef HASH_WANT_NEW
590 #undef HASH_WANT_REMOVE
591 #undef HASH_TABLE_ALLOC