source: trunk/src/objects/RpHash.c @ 4600

Last change on this file since 4600 was 1270, checked in by dkearney, 15 years ago

rappture object updates, stuff i'm playing around with. the code is not functional but it compiles, and i dont want to loose this state as i continue to play. the configure scripts and makefiles should still be working properly.

File size: 39.2 KB
Line 
1
2/*
3 * bltHash.c --
4 *
5 *
6 * This module implements an in-memory hash table for the BLT
7 * toolkit.  Built upon the Tcl hash table, it adds pool
8 * allocation 64-bit address handling, improved array hash
9 * function.
10 *
11 * Copyright 2001 Silicon Metrics Corporation.
12 *
13 * Permission to use, copy, modify, and distribute this software and
14 * its documentation for any purpose and without fee is hereby
15 * granted, provided that the above copyright notice appear in all
16 * copies and that both that the copyright notice and warranty
17 * disclaimer appear in supporting documentation, and that the names
18 * of Lucent Technologies any of their entities not be used in
19 * advertising or publicity pertaining to distribution of the software
20 * without specific, written prior permission.
21 *
22 * Silicon Metrics disclaims all warranties with regard to this
23 * software, including all implied warranties of merchantability and
24 * fitness.  In no event shall Lucent Technologies be liable for any
25 * special, indirect or consequential damages or any damages
26 * whatsoever resulting from loss of use, data or profits, whether in
27 * an action of contract, negligence or other tortuous action, arising
28 * out of or in connection with the use or performance of this
29 * software.
30 *
31 * Bob Jenkins, 1996.  hash.c.  Public Domain.
32 * Bob Jenkins, 1997.  lookup8.c.  Public Domain.
33 *
34 * Copyright (c) 1991-1993 The Regents of the University of California.
35 * Copyright (c) 1994 Sun Microsystems, Inc.
36 *
37 * See the file "license.terms" for information on usage and redistribution
38 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
39 *
40 * RCS: @(#) $Id: bltHash.c,v 1.10 2002/08/09 07:15:18 ghowlett Exp $
41 */
42
43#include <RpInt.h>
44
45#include <stdio.h>
46#include <string.h>
47/* The following header is required for LP64 compilation */
48#include <stdlib.h>
49
50#include "RpHash.h"
51
52/*
53 * When there are this many entries per bucket, on average, rebuild
54 * the hash table to make it larger.
55 */
56
57#define REBUILD_MULTIPLIER  3
58
59#if (SIZEOF_VOID_P == 8)
60#define RANDOM_INDEX        HashOneWord
61#define DOWNSHIFT_START     62
62#else
63
64/*
65 * The following macro takes a preliminary integer hash value and
66 * produces an index into a hash tables bucket list.  The idea is
67 * to make it so that preliminary values that are arbitrarily similar
68 * will end up in different buckets.  The hash function was taken
69 * from a random-number generator.
70 */
71#define RANDOM_INDEX(tablePtr, i) \
72    (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)
73#define DOWNSHIFT_START     28
74#endif
75
76/*
77 * Procedure prototypes for static procedures in this file:
78 */
79static Rp_Hash HashArray _ANSI_ARGS_((CONST void *key, size_t length));
80static Rp_HashEntry *ArrayFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
81    CONST void *key));
82static Rp_HashEntry *ArrayCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
83    CONST void *key, int *newPtr));
84static Rp_HashEntry *BogusFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
85    CONST void *key));
86static Rp_HashEntry *BogusCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
87    CONST void *key, int *newPtr));
88static Rp_Hash HashString _ANSI_ARGS_((CONST char *string));
89static void RebuildTable _ANSI_ARGS_((Rp_HashTable *tablePtr));
90static Rp_HashEntry *StringFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
91    CONST void *key));
92static Rp_HashEntry *StringCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
93    CONST void *key, int *newPtr));
94static Rp_HashEntry *OneWordFind _ANSI_ARGS_((Rp_HashTable *tablePtr,
95    CONST void *key));
96static Rp_HashEntry *OneWordCreate _ANSI_ARGS_((Rp_HashTable *tablePtr,
97    CONST void *key, int *newPtr));
98
99#if (SIZEOF_VOID_P == 8)
100static Rp_Hash HashOneWord _ANSI_ARGS_((Rp_HashTable *tablePtr,
101    CONST void *key));
102
103#endif /* SIZEOF_VOID_P == 8 */
104
105/*
106 *----------------------------------------------------------------------
107 *
108 * HashString --
109 *
110 *  Compute a one-word summary of a text string, which can be
111 *  used to generate a hash index.
112 *
113 * Results:
114 *  The return value is a one-word summary of the information in
115 *  string.
116 *
117 * Side effects:
118 *  None.
119 *
120 *----------------------------------------------------------------------
121 */
122static Rp_Hash
123HashString(register CONST char *string) /* String from which to
124                                         * compute hash value. */
125{
126    register Rp_Hash result;
127    register Rp_Hash c;
128
129    /*
130     * I tried a zillion different hash functions and asked many other
131     * people for advice.  Many people had their own favorite functions,
132     * all different, but no-one had much idea why they were good ones.
133     * I chose the one below (multiply by 9 and add new character)
134     * because of the following reasons:
135     *
136     * 1. Multiplying by 10 is perfect for keys that are decimal strings,
137     *    and multiplying by 9 is just about as good.
138     * 2. Times-9 is (shift-left-3) plus (old).  This means that each
139     *    character's bits hang around in the low-order bits of the
140     *    hash value for ever, plus they spread fairly rapidly up to
141     *    the high-order bits to fill out the hash value.  This seems
142     *    to work well both for decimal and non-decimal strings.
143     */
144
145    result = 0;
146    while ((c = *string++) != 0) {
147        result += (result << 3) + c;
148    }
149    return (Rp_Hash)result;
150}
151
152/*
153 *----------------------------------------------------------------------
154 *
155 * StringFind --
156 *
157 *      Given a hash table with string keys, and a string key, find
158 *      the entry with a matching key.
159 *
160 * Results:
161 *      The return value is a token for the matching entry in the
162 *      hash table, or NULL if there was no matching entry.
163 *
164 * Side effects:
165 *      None.
166 *
167 *----------------------------------------------------------------------
168 */
169static Rp_HashEntry *
170StringFind(
171    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
172    CONST void *key)        /* Key to use to find matching entry. */
173{
174    Rp_Hash hval;
175    register Rp_HashEntry *hPtr;
176    size_t hindex;
177
178    hval = HashString((char *)key);
179    hindex = hval & tablePtr->mask;
180
181    /*
182     * Search all of the entries in the appropriate bucket.
183     */
184
185    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
186        hPtr = hPtr->nextPtr) {
187        if (hPtr->hval == hval) {
188            register CONST char *p1, *p2;
189
190            for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
191                if (*p1 != *p2) {
192                    break;
193                }
194                if (*p1 == '\0') {
195                    return hPtr;
196                }
197            }
198        }
199    }
200    return NULL;
201}
202
203/*
204 *----------------------------------------------------------------------
205 *
206 * StringCreate --
207 *
208 *  Given a hash table with string keys, and a string key, find
209 *  the entry with a matching key.  If there is no matching entry,
210 *  then create a new entry that does match.
211 *
212 * Results:
213 *  The return value is a pointer to the matching entry.  If this
214 *  is a newly-created entry, then *newPtr will be set to a non-zero
215 *  value;  otherwise *newPtr will be set to 0.  If this is a new
216 *  entry the value stored in the entry will initially be 0.
217 *
218 * Side effects:
219 *  A new entry may be added to the hash table.
220 *
221 *----------------------------------------------------------------------
222 */
223static Rp_HashEntry *
224StringCreate(
225    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
226    CONST void *key,        /* Key to use to find or create matching
227                             * entry. */
228    int *newPtr)            /* Store info here telling whether a new
229                             * entry was created. */
230{
231    Rp_Hash hval;
232    Rp_HashEntry **bucketPtr;
233    register Rp_HashEntry *hPtr;
234    size_t size, hindex;
235
236    hval = HashString(key);
237    hindex = hval & tablePtr->mask;
238
239    /*
240     * Search all of the entries in this bucket.
241     */
242
243    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
244        hPtr = hPtr->nextPtr) {
245        if (hPtr->hval == hval) {
246            register CONST char *p1, *p2;
247
248            for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
249                if (*p1 != *p2) {
250                    break;
251                }
252                if (*p1 == '\0') {
253                    *newPtr = FALSE;
254                    return hPtr;
255                }
256            }
257        }
258    }
259
260    /*
261     * Entry not found.  Add a new one to the bucket.
262     */
263
264    *newPtr = TRUE;
265    size = sizeof(Rp_HashEntry) + strlen(key) - sizeof(Rp_HashKey) + 1;
266    if (tablePtr->hPool != NULL) {
267        hPtr = Rp_PoolAllocItem(tablePtr->hPool, size);
268    } else {
269        hPtr = Rp_Malloc(size);
270    }
271    bucketPtr = tablePtr->buckets + hindex;
272    hPtr->nextPtr = *bucketPtr;
273    hPtr->hval = hval;
274    hPtr->clientData = 0;
275    strcpy(hPtr->key.string, key);
276    *bucketPtr = hPtr;
277    tablePtr->numEntries++;
278
279    /*
280     * If the table has exceeded a decent size, rebuild it with many
281     * more buckets.
282     */
283
284    if (tablePtr->numEntries >= tablePtr->rebuildSize) {
285        RebuildTable(tablePtr);
286    }
287    return hPtr;
288}
289
290#if (SIZEOF_VOID_P == 8)
291/*
292 *----------------------------------------------------------------------
293 *
294 * HashOneWord --
295 *
296 *  Compute a one-word hash value of a 64-bit word, which then can
297 *  be used to generate a hash index.
298 *
299 *  From Knuth, it's a multiplicative hash.  Multiplies an unsigned
300 *  64-bit value with the golden ratio (sqrt(5) - 1) / 2.  The
301 *  downshift value is 64 - n, when n is the log2 of the size of
302 *  the hash table.
303 *
304 * Results:
305 *  The return value is a one-word summary of the information in
306 *  64 bit word.
307 *
308 * Side effects:
309 *  None.
310 *
311 *----------------------------------------------------------------------
312 */
313static Rp_Hash
314HashOneWord(
315    Rp_HashTable *tablePtr,
316    CONST void *key)
317{
318    uint64_t a0, a1;
319    uint64_t y0, y1;
320    uint64_t y2, y3;
321    uint64_t p1, p2;
322    uint64_t result;
323    /* Compute key * GOLDEN_RATIO in 128-bit arithmetic */
324    a0 = (uint64_t)key & 0x00000000FFFFFFFF;
325    a1 = (uint64_t)key >> 32;
326
327    y0 = a0 * 0x000000007f4a7c13;
328    y1 = a0 * 0x000000009e3779b9;
329    y2 = a1 * 0x000000007f4a7c13;
330    y3 = a1 * 0x000000009e3779b9;
331    y1 += y0 >> 32;     /* Can't carry */
332    y1 += y2;           /* Might carry */
333    if (y1 < y2) {
334        y3 += (1LL << 32);  /* Propagate */
335    }
336
337    /* 128-bit product: p1 = loword, p2 = hiword */
338    p1 = ((y1 & 0x00000000FFFFFFFF) << 32) + (y0 & 0x00000000FFFFFFFF);
339    p2 = y3 + (y1 >> 32);
340
341    /* Left shift the value downward by the size of the table */
342    if (tablePtr->downShift > 0) {
343        if (tablePtr->downShift < 64) {
344            result = ((p2 << (64 - tablePtr->downShift)) |
345                      (p1 >> (tablePtr->downShift & 63)));
346        } else {
347            result = p2 >> (tablePtr->downShift & 63);
348        }
349    } else {
350        result = p1;
351    }
352    /* Finally mask off the high bits */
353    return (Rp_Hash)(result & tablePtr->mask);
354}
355
356#endif /* SIZEOF_VOID_P == 8 */
357
358/*
359 *----------------------------------------------------------------------
360 *
361 * OneWordFind --
362 *
363 *  Given a hash table with one-word keys, and a one-word key,
364 *  find the entry with a matching key.
365 *
366 * Results:
367 *  The return value is a token for the matching entry in the
368 *  hash table, or NULL if there was no matching entry.
369 *
370 * Side effects:
371 *  None.
372 *
373 *----------------------------------------------------------------------
374 */
375static Rp_HashEntry *
376OneWordFind(
377    Rp_HashTable *tablePtr,     /* Table in which to lookup entry. */
378    register CONST void *key)   /* Key to use to find matching entry. */
379{
380    register Rp_HashEntry *hPtr;
381    size_t hindex;
382
383    hindex = RANDOM_INDEX(tablePtr, key);
384
385    /*
386     * Search all of the entries in the appropriate bucket.
387     */
388    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
389        hPtr = hPtr->nextPtr) {
390        if (hPtr->key.oneWordValue == key) {
391            return hPtr;
392        }
393    }
394    return NULL;
395}
396
397/*
398 *----------------------------------------------------------------------
399 *
400 * OneWordCreate --
401 *
402 *  Given a hash table with one-word keys, and a one-word key, find
403 *  the entry with a matching key.  If there is no matching entry,
404 *  then create a new entry that does match.
405 *
406 * Results:
407 *  The return value is a pointer to the matching entry.  If this
408 *  is a newly-created entry, then *newPtr will be set to a non-zero
409 *  value;  otherwise *newPtr will be set to 0.  If this is a new
410 *  entry the value stored in the entry will initially be 0.
411 *
412 * Side effects:
413 *  A new entry may be added to the hash table.
414 *
415 *----------------------------------------------------------------------
416 */
417static Rp_HashEntry *
418OneWordCreate(
419    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
420    CONST void *key,        /* Key to use to find or create matching
421                             * entry. */
422    int *newPtr)            /* Store info here telling whether a new
423                             * entry was created. */
424{
425    Rp_HashEntry **bucketPtr;
426    register Rp_HashEntry *hPtr;
427    size_t hindex;
428
429    hindex = RANDOM_INDEX(tablePtr, key);
430
431    /*
432     * Search all of the entries in this bucket.
433     */
434    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
435        hPtr = hPtr->nextPtr) {
436        if (hPtr->key.oneWordValue == key) {
437            *newPtr = FALSE;
438            return hPtr;
439        }
440    }
441
442    /*
443     * Entry not found.  Add a new one to the bucket.
444     */
445
446    *newPtr = TRUE;
447    if (tablePtr->hPool != NULL) {
448        hPtr = Rp_PoolAllocItem(tablePtr->hPool, sizeof(Rp_HashEntry));
449    } else {
450        hPtr = Rp_Malloc(sizeof(Rp_HashEntry));
451    }
452    bucketPtr = tablePtr->buckets + hindex;
453    hPtr->nextPtr = *bucketPtr;
454    hPtr->hval = (Rp_Hash)key;
455    hPtr->clientData = 0;
456    hPtr->key.oneWordValue = (void *)key;   /* CONST XXXX */
457    *bucketPtr = hPtr;
458    tablePtr->numEntries++;
459
460    /*
461     * If the table has exceeded a decent size, rebuild it with many
462     * more buckets.
463     */
464
465    if (tablePtr->numEntries >= tablePtr->rebuildSize) {
466        RebuildTable(tablePtr);
467    }
468    return hPtr;
469}
470
471
472#if (SIZEOF_VOID_P == 4)
473/*
474 * --------------------------------------------------------------------
475 *
476 * MIX32 --
477 *
478 *      Bob Jenkins, 1996.  Public Domain.
479 *
480 *  Mix 3 32/64-bit values reversibly.  For every delta with one or
481 *  two bit set, and the deltas of all three high bits or all
482 *  three low bits, whether the original value of a,b,c is almost
483 *  all zero or is uniformly distributed, If mix() is run
484 *  forward or backward, at least 32 bits in a,b,c have at least
485 *  1/4 probability of changing.  * If mix() is run forward, every
486 *  bit of c will change between 1/3 and 2/3 of the time.  (Well,
487 *  22/100 and 78/100 for some 2-bit deltas.)  mix() was built out
488 *  of 36 single-cycle latency instructions in a structure that
489 *  could supported 2x parallelism, like so:
490 *
491 *      a -= b;
492 *      a -= c; x = (c>>13);
493 *      b -= c; a ^= x;
494 *      b -= a; x = (a<<8);
495 *      c -= a; b ^= x;
496 *      c -= b; x = (b>>13);
497 *      ...
498 *
499 *   Unfortunately, superscalar Pentiums and Sparcs can't take
500 *   advantage of that parallelism.  They've also turned some of
501 *   those single-cycle latency instructions into multi-cycle
502 *   latency instructions.  Still, this is the fastest good hash I
503 *   could find.  There were about 2^^68 to choose from.  I only
504 *   looked at a billion or so.
505 *
506 * --------------------------------------------------------------------
507 */
508#define MIX32(a,b,c) \
509        a -= b, a -= c, a ^= (c >> 13), \
510        b -= c, b -= a, b ^= (a <<  8), \
511        c -= a, c -= b, c ^= (b >> 13), \
512        a -= b, a -= c, a ^= (c >> 12), \
513        b -= c, b -= a, b ^= (a << 16), \
514        c -= a, c -= b, c ^= (b >>  5), \
515        a -= b, a -= c, a ^= (c >>  3), \
516        b -= c, b -= a, b ^= (a << 10), \
517        c -= a, c -= b, c ^= (b >> 15)
518
519#define GOLDEN_RATIO32  0x9e3779b9      /* An arbitrary value */
520
521/*
522 * --------------------------------------------------------------------
523 *
524 * HashArray --
525 *
526 *      Bob Jenkins, 1996.  Public Domain.
527 *
528 *  This works on all machines.  Length has to be measured in
529 *  unsigned longs instead of bytes.  It requires that
530 *
531 *    o The key be an array of unsigned ints.
532 *    o All your machines have the same endianness
533 *    o The length be the number of unsigned ints in the key.
534 *
535 * --------------------------------------------------------------------
536 */
537static Rp_Hash
538HashArray(
539    CONST void *key,
540    size_t length)      /* Length of the key in 32-bit words */
541{
542    register uint32_t a, b, c, len;
543    register uint32_t *arrayPtr = (uint32_t *)key;
544    /* Set up the internal state */
545    len = length;
546    a = b = GOLDEN_RATIO32; /* An arbitrary value */
547    c = 0;                  /* Previous hash value */
548
549    while (len >= 3) {      /* Handle most of the key */
550        a += arrayPtr[0];
551        b += arrayPtr[1];
552        c += arrayPtr[2];
553        MIX32(a, b, c);
554        arrayPtr += 3; len -= 3;
555    }
556    c += length;
557    /* And now the last 2 words */
558    /* Note that all the case statements fall through */
559    switch(len) {
560        /* c is reserved for the length */
561    case 2 : b += arrayPtr[1];
562    case 1 : a += arrayPtr[0];
563        /* case 0: nothing left to add */
564    }
565    MIX32(a, b, c);
566    return (Rp_Hash)c;
567}
568#endif /* SIZEOF_VOID_P == 4 */
569
570#if (SIZEOF_VOID_P == 8)
571
572/*
573 * --------------------------------------------------------------------
574 *
575 * MIX64 --
576 *
577 *  Bob Jenkins, January 4 1997, Public Domain.  You can use
578 *  this free for any purpose.  It has no warranty.
579 *
580 *  Returns a 64-bit value.  Every bit of the key affects every
581 *  bit of the return value.  No funnels.  Every 1-bit and 2-bit
582 *  delta achieves avalanche.  About 41+5len instructions.
583 *
584 *  The best hash table sizes are powers of 2.  There is no need
585 *  to do mod a prime (mod is sooo slow!).  If you need less than
586 *  64 bits, use a bitmask.  For example, if you need only 10
587 *  bits, do h = (h & hashmask(10)); In which case, the hash table
588 *  should have hashsize(10) elements.
589 *
590 *  By Bob Jenkins, Jan 4 1997.  bob_jenkins@burtleburtle.net.
591 *  You may use this code any way you wish, private, educational,
592 *  or commercial, as long as this whole comment accompanies it.
593 *
594 *  See http://burtleburtle.net/bob/hash/evahash.html
595 *  Use for hash table lookup, or anything where one collision in
596 *  2^^64 * is acceptable.  Do NOT use for cryptographic purposes.
597 *
598 * --------------------------------------------------------------------
599 */
600
601#define MIX64(a,b,c) \
602        a -= b, a -= c, a ^= (c >> 43), \
603        b -= c, b -= a, b ^= (a <<  9), \
604        c -= a, c -= b, c ^= (b >>  8), \
605        a -= b, a -= c, a ^= (c >> 38), \
606        b -= c, b -= a, b ^= (a << 23), \
607        c -= a, c -= b, c ^= (b >>  5), \
608        a -= b, a -= c, a ^= (c >> 35), \
609        b -= c, b -= a, b ^= (a << 49), \
610        c -= a, c -= b, c ^= (b >> 11), \
611        a -= b, a -= c, a ^= (c >> 12), \
612        b -= c, b -= a, b ^= (a << 18), \
613        c -= a, c -= b, c ^= (b >> 22)
614
615#define GOLDEN_RATIO64  0x9e3779b97f4a7c13LL
616
617/*
618 * --------------------------------------------------------------------
619 *
620 * HashArray --
621 *
622 *  Bob Jenkins, January 4 1997, Public Domain.  You can use
623 *  this free for any purpose.  It has no warranty.
624 *
625 *  This works on all machines.  The length has to be measured in
626 *  64 bit words, instead of bytes.  It requires that
627 *
628 *    o The key be an array of 64 bit words (unsigned longs).
629 *    o All your machines have the same endianness.
630 *    o The length be the number of 64 bit words in the key.
631 *
632 * --------------------------------------------------------------------
633 */
634static Rp_Hash
635HashArray(
636    CONST void *key,
637    size_t length)      /* Length of key in 32-bit words. */
638{
639    register uint64_t a, b, c, len;
640    register uint32_t *iPtr = (uint32_t *)key;
641
642#ifdef WORDS_BIGENDIAN
643#define PACK(a,b)   ((uint64_t)(b) | ((uint64_t)(a) << 32))
644#else
645#define PACK(a,b)   ((uint64_t)(a) | ((uint64_t)(b) << 32))
646#endif
647    /* Set up the internal state */
648    len = length;           /* Length is the number of 64-bit words. */
649    a = b = GOLDEN_RATIO64; /* An arbitrary value */
650    c = 0;                  /* Previous hash value */
651
652    while (len >= 6) {      /* Handle most of the key */
653        a += PACK(iPtr[0], iPtr[1]);
654        b += PACK(iPtr[2], iPtr[3]);
655        c += PACK(iPtr[4], iPtr[5]);
656        MIX64(a,b,c);
657        iPtr += 6; len -= 6;
658    }
659    c += length;
660    /* And now the last 2 words */
661    /* Note that all the case statements fall through */
662    switch(len) {
663        /* c is reserved for the length */
664    case 5 :
665    case 4 :
666        a += PACK(iPtr[0], iPtr[1]);
667        b += PACK(iPtr[2], iPtr[3]);
668        iPtr += 4; len -= 4;
669        break;
670    case 3 :
671    case 2 :
672        a += PACK(iPtr[0], iPtr[1]);
673        iPtr += 2; len -= 2;
674 /* case 0: nothing left to add */
675    }
676    if (len > 0) {
677        b += iPtr[0];
678    }
679    MIX64(a,b,c);
680    return (Rp_Hash)c;
681}
682#endif /* SIZEOF_VOID_P == 8 */
683
684/*
685 *----------------------------------------------------------------------
686 *
687 * ArrayFind --
688 *
689 *  Given a hash table with array-of-int keys, and a key, find
690 *  the entry with a matching key.
691 *
692 * Results:
693 *  The return value is a token for the matching entry in the
694 *  hash table, or NULL if there was no matching entry.
695 *
696 * Side effects:
697 *  None.
698 *
699 *----------------------------------------------------------------------
700 */
701static Rp_HashEntry *
702ArrayFind(
703    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
704    CONST void *key)        /* Key to use to find matching entry. */
705{
706    Rp_Hash hval;
707    register Rp_HashEntry *hPtr;
708    size_t hindex;
709
710    hval = HashArray(key, tablePtr->keyType);
711    hindex = hval & tablePtr->mask;
712    /*
713     * Search all of the entries in the appropriate bucket.
714     */
715
716    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
717        hPtr = hPtr->nextPtr) {
718        if (hPtr->hval == hval) {
719            register unsigned int *iPtr1, *iPtr2;
720            unsigned int count;
721
722            for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words,
723                 count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
724                if (count == 0) {
725                    return hPtr;
726                }
727                if (*iPtr1 != *iPtr2) {
728                    break;
729                }
730            }
731        }
732    }
733    return NULL;
734}
735
736/*
737 *----------------------------------------------------------------------
738 *
739 * ArrayCreate --
740 *
741 *  Given a hash table with one-word keys, and a one-word key, find
742 *  the entry with a matching key.  If there is no matching entry,
743 *  then create a new entry that does match.
744 *
745 * Results:
746 *  The return value is a pointer to the matching entry.  If this
747 *  is a newly-created entry, then *newPtr will be set to a non-zero
748 *  value;  otherwise *newPtr will be set to 0.  If this is a new
749 *  entry the value stored in the entry will initially be 0.
750 *
751 * Side effects:
752 *  A new entry may be added to the hash table.
753 *
754 *----------------------------------------------------------------------
755 */
756static Rp_HashEntry *
757ArrayCreate(
758    Rp_HashTable *tablePtr,     /* Table in which to lookup entry. */
759    register CONST void *key,   /* Key to use to find or create matching
760                                 * entry. */
761    int *newPtr)                /* Store info here telling whether a new
762                                 * entry was created. */
763{
764    Rp_Hash hval;
765    Rp_HashEntry **bucketPtr;
766    int count;
767    register Rp_HashEntry *hPtr;
768    register uint32_t *iPtr1, *iPtr2;
769    size_t size, hindex;
770
771    hval = HashArray(key, tablePtr->keyType);
772    hindex = hval & tablePtr->mask;
773
774    /*
775     * Search all of the entries in the appropriate bucket.
776     */
777    for (hPtr = tablePtr->buckets[hindex]; hPtr != NULL;
778        hPtr = hPtr->nextPtr) {
779        if (hPtr->hval == hval) {
780            for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words,
781                 count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
782                if (count == 0) {
783                    *newPtr = FALSE;
784                    return hPtr;
785                }
786                if (*iPtr1 != *iPtr2) {
787                    break;
788                }
789            }
790        }
791    }
792
793    /*
794     * Entry not found.  Add a new one to the bucket.
795     */
796    *newPtr = TRUE;
797    /* We assume here that the size of the key is at least 2 words */
798    size = sizeof(Rp_HashEntry) + tablePtr->keyType * sizeof(uint32_t) -
799        sizeof(Rp_HashKey);
800    if (tablePtr->hPool != NULL) {
801        hPtr = Rp_PoolAllocItem(tablePtr->hPool, size);
802    } else {
803        hPtr = Rp_Malloc(size);
804    }
805    bucketPtr = tablePtr->buckets + hindex;
806    hPtr->nextPtr = *bucketPtr;
807    hPtr->hval = hval;
808    hPtr->clientData = 0;
809    count = tablePtr->keyType;
810    for (iPtr1 = (uint32_t *)key, iPtr2 = (uint32_t *)hPtr->key.words;
811         count > 0; count--, iPtr1++, iPtr2++) {
812        *iPtr2 = *iPtr1;
813    }
814    *bucketPtr = hPtr;
815    tablePtr->numEntries++;
816
817    /*
818     * If the table has exceeded a decent size, rebuild it with many
819     * more buckets.
820     */
821    if (tablePtr->numEntries >= tablePtr->rebuildSize) {
822        RebuildTable(tablePtr);
823    }
824    return hPtr;
825}
826
827/*
828 *----------------------------------------------------------------------
829 *
830 * BogusFind --
831 *
832 *  This procedure is invoked when an Rp_FindHashEntry is called
833 *  on a table that has been deleted.
834 *
835 * Results:
836 *  If panic returns (which it shouldn't) this procedure returns
837 *  NULL.
838 *
839 * Side effects:
840 *  Generates a panic.
841 *
842 *----------------------------------------------------------------------
843 */
844/* ARGSUSED */
845static Rp_HashEntry *
846BogusFind(
847    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
848    CONST void *key)        /* Key to use to find matching entry. */
849{
850    Rp_Panic("called Rp_FindHashEntry on deleted table");
851    return NULL;
852}
853
854/*
855 *----------------------------------------------------------------------
856 *
857 * BogusCreate --
858 *
859 *  This procedure is invoked when an Rp_CreateHashEntry is called
860 *  on a table that has been deleted.
861 *
862 * Results:
863 *  If panic returns (which it shouldn't) this procedure returns
864 *  NULL.
865 *
866 * Side effects:
867 *  Generates a panic.
868 *
869 *----------------------------------------------------------------------
870 */
871/* ARGSUSED */
872static Rp_HashEntry *
873BogusCreate(
874    Rp_HashTable *tablePtr, /* Table in which to lookup entry. */
875    CONST void *key,        /* Key to use to find or create matching
876                             * entry. */
877    int *newPtr)            /* Store info here telling whether a new
878                             * entry was created. */
879{
880    Rp_Panic("called Rp_CreateHashEntry on deleted table");
881    return NULL;
882}
883
884/*
885 *----------------------------------------------------------------------
886 *
887 * RebuildTable --
888 *
889 *  This procedure is invoked when the ratio of entries to hash
890 *  buckets becomes too large.  It creates a new table with a
891 *  larger bucket array and moves all of the entries into the
892 *  new table.
893 *
894 * Results:
895 *  None.
896 *
897 * Side effects:
898 *  Memory gets reallocated and entries get re-hashed to new
899 *  buckets.
900 *
901 *----------------------------------------------------------------------
902 */
903static void
904RebuildTable(Rp_HashTable *tablePtr) /* Table to enlarge. */
905{
906    Rp_HashEntry **bucketPtr, **oldBuckets;
907    register Rp_HashEntry **oldChainPtr, **endPtr;
908    register Rp_HashEntry *hPtr, *nextPtr;
909    size_t hindex;
910
911    oldBuckets = tablePtr->buckets;
912    endPtr = tablePtr->buckets + tablePtr->numBuckets;
913    /*
914     * Allocate and initialize the new bucket array, and set up
915     * hashing constants for new array size.
916     */
917    tablePtr->numBuckets <<= 2;
918    tablePtr->buckets = Rp_Calloc(tablePtr->numBuckets,
919                           sizeof(Rp_HashEntry *));
920    tablePtr->rebuildSize <<= 2;
921    tablePtr->downShift -= 2;
922    tablePtr->mask = tablePtr->numBuckets - 1;
923
924    /*
925     * Move all of the existing entries into the new bucket array,
926     * based on their hash values.
927     */
928    if (tablePtr->keyType == RP_ONE_WORD_KEYS) {
929    /*
930     * RP_ONE_WORD_KEYS are handled slightly differently because
931     * they use the current table size (number of buckets) to be
932     * distributed.
933     */
934        for (oldChainPtr = oldBuckets; oldChainPtr < endPtr; oldChainPtr++) {
935            for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = nextPtr) {
936                nextPtr = hPtr->nextPtr;
937                hindex = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
938                bucketPtr = tablePtr->buckets + hindex;
939                hPtr->nextPtr = *bucketPtr;
940                *bucketPtr = hPtr;
941            }
942        }
943    } else {
944        for (oldChainPtr = oldBuckets; oldChainPtr < endPtr; oldChainPtr++) {
945            for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = nextPtr) {
946                nextPtr = hPtr->nextPtr;
947                hindex = hPtr->hval & tablePtr->mask;
948                bucketPtr = tablePtr->buckets + hindex;
949                hPtr->nextPtr = *bucketPtr;
950                *bucketPtr = hPtr;
951            }
952        }
953    }
954
955    /*
956     * Free up the old bucket array, if it was dynamically allocated.
957     */
958    if (oldBuckets != tablePtr->staticBuckets) {
959        Rp_Free(oldBuckets);
960    }
961}
962
963
964/* Public hash table routines */
965
966/*
967 *----------------------------------------------------------------------
968 *
969 * Rp_InitHashTable --
970 *
971 *  Given storage for a hash table, set up the fields to prepare
972 *  the hash table for use.
973 *
974 * Results:
975 *  None.
976 *
977 * Side effects:
978 *  TablePtr is now ready to be passed to Rp_FindHashEntry and
979 *  Rp_CreateHashEntry.
980 *
981 *----------------------------------------------------------------------
982 */
983void
984Rp_InitHashTable(
985    register Rp_HashTable *tablePtr,    /* Pointer to table record, which
986                                         * is supplied by the caller. */
987    size_t keyType)                     /* Type of keys to use in table. */
988{
989#if (RP_SMALL_HASH_TABLE != 4)
990    Rp_Panic("Rp_InitHashTable: RP_SMALL_HASH_TABLE is %d, not 4\n",
991        RP_SMALL_HASH_TABLE);
992#endif
993    tablePtr->buckets = tablePtr->staticBuckets;
994    tablePtr->numBuckets = RP_SMALL_HASH_TABLE;
995    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
996    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
997    tablePtr->numEntries = 0;
998    tablePtr->rebuildSize = RP_SMALL_HASH_TABLE * REBUILD_MULTIPLIER;
999    tablePtr->downShift = DOWNSHIFT_START;
1000
1001    /* The number of buckets is always a power of 2, so we can
1002     * generate the mask by simply subtracting 1 from the number of
1003     * buckets. */
1004    tablePtr->mask = (Rp_Hash)(tablePtr->numBuckets - 1);
1005    tablePtr->keyType = keyType;
1006
1007    switch (keyType) {
1008    case RP_STRING_KEYS:    /* NUL terminated string keys. */
1009        tablePtr->findProc = StringFind;
1010        tablePtr->createProc = StringCreate;
1011        break;
1012
1013    case RP_ONE_WORD_KEYS:  /* 32 or 64 bit atomic keys. */
1014        tablePtr->findProc = OneWordFind;
1015        tablePtr->createProc = OneWordCreate;
1016        break;
1017
1018    default:                /* Structures/arrays. */
1019        if (keyType == 0) {
1020            Rp_Panic("Rp_InitHashTable: Key size can't be %d, must be > 0\n",
1021              keyType);
1022        }
1023        tablePtr->findProc = ArrayFind;
1024        tablePtr->createProc = ArrayCreate;
1025        break;
1026    }
1027    tablePtr->hPool = NULL;
1028}
1029
1030/*
1031 *----------------------------------------------------------------------
1032 *
1033 * Rp_InitHashTableWithPool --
1034 *
1035 *  Given storage for a hash table, set up the fields to prepare
1036 *  the hash table for use.  The only difference between this
1037 *  routine and Rp_InitHashTable is that is uses a pool allocator
1038 *  to allocate memory for hash table entries.  The type of pool
1039 *  is either fixed or variable size (string) keys.
1040 *
1041 * Results:
1042 *  None.
1043 *
1044 * Side effects:
1045 *  TablePtr is now ready to be passed to Rp_FindHashEntry and
1046 *  Rp_CreateHashEntry.
1047 *
1048 *----------------------------------------------------------------------
1049 */
1050void
1051Rp_InitHashTableWithPool(
1052    register Rp_HashTable *tablePtr,    /* Pointer to table record, which
1053                                         * is supplied by the caller. */
1054    size_t keyType)                     /* Type of keys to use in table. */
1055{
1056    Rp_InitHashTable(tablePtr, keyType);
1057    if (keyType == RP_STRING_KEYS) {
1058        tablePtr->hPool = Rp_PoolCreate(RP_VARIABLE_SIZE_ITEMS);
1059    } else {
1060        tablePtr->hPool = Rp_PoolCreate(RP_FIXED_SIZE_ITEMS);
1061    }
1062}
1063
1064/*
1065 *----------------------------------------------------------------------
1066 *
1067 * Rp_DeleteHashEntry --
1068 *
1069 *  Remove a single entry from a hash table.
1070 *
1071 * Results:
1072 *  None.
1073 *
1074 * Side effects:
1075 *  The entry given by entryPtr is deleted from its table and
1076 *  should never again be used by the caller.  It is up to the
1077 *  caller to free the clientData field of the entry, if that
1078 *  is relevant.
1079 *
1080 *----------------------------------------------------------------------
1081 */
1082void
1083Rp_DeleteHashEntry(
1084    Rp_HashTable *tablePtr,
1085    Rp_HashEntry *entryPtr)
1086{
1087    register Rp_HashEntry *prevPtr;
1088    Rp_HashEntry **bucketPtr;
1089    size_t hindex;
1090
1091    if (tablePtr->keyType == RP_ONE_WORD_KEYS) {
1092        hindex = RANDOM_INDEX(tablePtr, (CONST void *)entryPtr->hval);
1093    } else {
1094        hindex = (entryPtr->hval & tablePtr->mask);
1095    }
1096    bucketPtr = tablePtr->buckets + hindex;
1097    if (*bucketPtr == entryPtr) {
1098        *bucketPtr = entryPtr->nextPtr;
1099    } else {
1100        for (prevPtr = *bucketPtr; /*empty*/; prevPtr = prevPtr->nextPtr) {
1101            if (prevPtr == NULL) {
1102                Rp_Panic("malformed bucket chain in Rp_DeleteHashEntry");
1103            }
1104            if (prevPtr->nextPtr == entryPtr) {
1105                prevPtr->nextPtr = entryPtr->nextPtr;
1106                break;
1107            }
1108        }
1109    }
1110    tablePtr->numEntries--;
1111    if (tablePtr->hPool != NULL) {
1112        Rp_PoolFreeItem(tablePtr->hPool, (char *)entryPtr);
1113    } else {
1114        Rp_Free(entryPtr);
1115    }
1116}
1117
1118/*
1119 *----------------------------------------------------------------------
1120 *
1121 * Rp_DeleteHashTable --
1122 *
1123 *  Free up everything associated with a hash table except for
1124 *  the record for the table itself.
1125 *
1126 * Results:
1127 *  None.
1128 *
1129 * Side effects:
1130 *  The hash table is no longer useable.
1131 *
1132 *----------------------------------------------------------------------
1133 */
1134void
1135Rp_DeleteHashTable(Rp_HashTable *tablePtr)      /* Table to delete. */
1136{
1137    /*
1138     * Free up all the entries in the table.
1139     */
1140    if (tablePtr->hPool != NULL) {
1141        Rp_PoolDestroy(tablePtr->hPool);
1142        tablePtr->hPool = NULL;
1143    } else {
1144        register Rp_HashEntry *hPtr, *nextPtr;
1145        size_t i;
1146
1147        for (i = 0; i < tablePtr->numBuckets; i++) {
1148            hPtr = tablePtr->buckets[i];
1149            while (hPtr != NULL) {
1150                nextPtr = hPtr->nextPtr;
1151                Rp_Free(hPtr);
1152                hPtr = nextPtr;
1153            }
1154        }
1155    }
1156
1157    /*
1158     * Free up the bucket array, if it was dynamically allocated.
1159     */
1160    if (tablePtr->buckets != tablePtr->staticBuckets) {
1161        Rp_Free(tablePtr->buckets);
1162    }
1163
1164    /*
1165     * Arrange for panics if the table is used again without
1166     * re-initialization.
1167     */
1168
1169    tablePtr->findProc = BogusFind;
1170    tablePtr->createProc = BogusCreate;
1171}
1172
1173/*
1174 *----------------------------------------------------------------------
1175 *
1176 * Rp_FirstHashEntry --
1177 *
1178 *  Locate the first entry in a hash table and set up a record
1179 *  that can be used to step through all the remaining entries
1180 *  of the table.
1181 *
1182 * Results:
1183 *  The return value is a pointer to the first entry in tablePtr,
1184 *  or NULL if tablePtr has no entries in it.  The memory at
1185 *  *searchPtr is initialized so that subsequent calls to
1186 *  Rp_NextHashEntry will return all of the entries in the table,
1187 *  one at a time.
1188 *
1189 * Side effects:
1190 *  None.
1191 *
1192 *----------------------------------------------------------------------
1193 */
1194Rp_HashEntry *
1195Rp_FirstHashEntry(
1196    Rp_HashTable *tablePtr,         /* Table to search. */
1197    Rp_HashSearch *searchPtr)       /* Place to store information about
1198                                     * progress through the table. */
1199{
1200    searchPtr->tablePtr = tablePtr;
1201    searchPtr->nextIndex = 0;
1202    searchPtr->nextEntryPtr = NULL;
1203    return Rp_NextHashEntry(searchPtr);
1204}
1205
1206/*
1207 *----------------------------------------------------------------------
1208 *
1209 * Rp_NextHashEntry --
1210 *
1211 *  Once a hash table enumeration has been initiated by calling
1212 *  Rp_FirstHashEntry, this procedure may be called to return
1213 *  successive elements of the table.
1214 *
1215 * Results:
1216 *  The return value is the next entry in the hash table being
1217 *  enumerated, or NULL if the end of the table is reached.
1218 *
1219 * Side effects:
1220 *  None.
1221 *
1222 *----------------------------------------------------------------------
1223 */
1224Rp_HashEntry *
1225Rp_NextHashEntry(Rp_HashSearch *searchPtr)
1226{
1227    Rp_HashEntry *hPtr;
1228
1229    while (searchPtr->nextEntryPtr == NULL) {
1230        if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) {
1231            return NULL;
1232        }
1233        searchPtr->nextEntryPtr =
1234                searchPtr->tablePtr->buckets[searchPtr->nextIndex];
1235        searchPtr->nextIndex++;
1236    }
1237    hPtr = searchPtr->nextEntryPtr;
1238    searchPtr->nextEntryPtr = hPtr->nextPtr;
1239    return hPtr;
1240}
1241
1242/*
1243 *----------------------------------------------------------------------
1244 *
1245 * Rp_HashStats --
1246 *
1247 *  Return statistics describing the layout of the hash table
1248 *  in its hash buckets.
1249 *
1250 * Results:
1251 *  The return value is a malloc-ed string containing information
1252 *  about tablePtr.  It is the caller's responsibility to free
1253 *  this string.
1254 *
1255 * Side effects:
1256 *  None.
1257 *
1258 *----------------------------------------------------------------------
1259 */
1260char *
1261Rp_HashStats(Rp_HashTable *tablePtr) /* Table for which to produce stats. */
1262{
1263#define NUM_COUNTERS 10
1264    size_t count[NUM_COUNTERS], overflow, i, j, max;
1265    double average, tmp;
1266    register Rp_HashEntry *hPtr;
1267    Rp_HashEntry **bucketPtr, **endPtr;
1268    char *result, *p;
1269
1270    /*
1271     * Compute a histogram of bucket usage.
1272     */
1273    for (i = 0; i < NUM_COUNTERS; i++) {
1274        count[i] = 0;
1275    }
1276    overflow = 0;
1277    average = 0.0;
1278    max = 0;
1279    endPtr = tablePtr->buckets + tablePtr->numBuckets;
1280    for (bucketPtr = tablePtr->buckets; bucketPtr < endPtr; bucketPtr++) {
1281        j = 0;
1282        for (hPtr = *bucketPtr; hPtr != NULL; hPtr = hPtr->nextPtr) {
1283            j++;
1284        }
1285        if (j > max) {
1286            max = j;
1287        }
1288        if (j < NUM_COUNTERS) {
1289            count[j]++;
1290        } else {
1291            overflow++;
1292        }
1293        tmp = j;
1294        average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
1295    }
1296
1297    /*
1298     * Print out the histogram and a few other pieces of information.
1299     */
1300    result = Rp_Malloc((unsigned) ((NUM_COUNTERS*60) + 300));
1301#if SIZEOF_VOID_P == 8
1302    sprintf(result, "%ld entries in table, %ld buckets\n",
1303            tablePtr->numEntries, tablePtr->numBuckets);
1304#else
1305    sprintf(result, "%d entries in table, %d buckets\n",
1306            tablePtr->numEntries, tablePtr->numBuckets);
1307#endif
1308    p = result + strlen(result);
1309    for (i = 0; i < NUM_COUNTERS; i++) {
1310#if SIZEOF_VOID_P == 8
1311        sprintf(p, "number of buckets with %ld entries: %ld\n",
1312                i, count[i]);
1313#else
1314        sprintf(p, "number of buckets with %d entries: %d\n",
1315                i, count[i]);
1316#endif
1317        p += strlen(p);
1318    }
1319#if SIZEOF_VOID_P == 8
1320    sprintf(p, "number of buckets with %d or more entries: %ld\n",
1321            NUM_COUNTERS, overflow);
1322#else
1323    sprintf(p, "number of buckets with %d or more entries: %d\n",
1324            NUM_COUNTERS, overflow);
1325#endif
1326    p += strlen(p);
1327    sprintf(p, "average search distance for entry: %.2f\n", average);
1328    p += strlen(p);
1329#if SIZEOF_VOID_P == 8
1330    sprintf(p, "maximum search distance for entry: %ld", max);
1331#else
1332    sprintf(p, "maximum search distance for entry: %d", max);
1333#endif
1334    return result;
1335}
Note: See TracBrowser for help on using the repository browser.