4 * Implementation of in-memory hash tables for Tcl and Tcl-based
7 * Copyright (c) 1991-1993 The Regents of the University of California.
8 * Copyright (c) 1994 Sun Microsystems, Inc.
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 * Prevent macros from clashing with function definitions.
22 #if TCL_PRESERVE_BINARY_COMPATABILITY
23 # undef Tcl_FindHashEntry
24 # undef Tcl_CreateHashEntry
28 * When there are this many entries per bucket, on average, rebuild
29 * the hash table to make it larger.
32 #define REBUILD_MULTIPLIER 3
35 * The following macro takes a preliminary integer hash value and
36 * produces an index into a hash tables bucket list. The idea is
37 * to make it so that preliminary values that are arbitrarily similar
38 * will end up in different buckets. The hash function was taken
39 * from a random-number generator.
42 #define RANDOM_INDEX(tablePtr, i) \
43 (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)
46 * Prototypes for the array hash key methods.
49 static Tcl_HashEntry * AllocArrayEntry _ANSI_ARGS_((
50 Tcl_HashTable *tablePtr,
52 static int CompareArrayKeys _ANSI_ARGS_((
53 VOID *keyPtr, Tcl_HashEntry *hPtr));
54 static unsigned int HashArrayKey _ANSI_ARGS_((
55 Tcl_HashTable *tablePtr,
59 * Prototypes for the one word hash key methods.
63 static Tcl_HashEntry * AllocOneWordEntry _ANSI_ARGS_((
64 Tcl_HashTable *tablePtr,
66 static int CompareOneWordKeys _ANSI_ARGS_((
67 VOID *keyPtr, Tcl_HashEntry *hPtr));
68 static unsigned int HashOneWordKey _ANSI_ARGS_((
69 Tcl_HashTable *tablePtr,
74 * Prototypes for the string hash key methods.
77 static Tcl_HashEntry * AllocStringEntry _ANSI_ARGS_((
78 Tcl_HashTable *tablePtr,
80 static int CompareStringKeys _ANSI_ARGS_((
81 VOID *keyPtr, Tcl_HashEntry *hPtr));
82 static unsigned int HashStringKey _ANSI_ARGS_((
83 Tcl_HashTable *tablePtr,
87 * Procedure prototypes for static procedures in this file:
90 #if TCL_PRESERVE_BINARY_COMPATABILITY
91 static Tcl_HashEntry * BogusFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
93 static Tcl_HashEntry * BogusCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
94 CONST char *key, int *newPtr));
97 static void RebuildTable _ANSI_ARGS_((Tcl_HashTable *tablePtr));
99 Tcl_HashKeyType tclArrayHashKeyType = {
100 TCL_HASH_KEY_TYPE_VERSION, /* version */
101 TCL_HASH_KEY_RANDOMIZE_HASH, /* flags */
102 HashArrayKey, /* hashKeyProc */
103 CompareArrayKeys, /* compareKeysProc */
104 AllocArrayEntry, /* allocEntryProc */
105 NULL /* freeEntryProc */
108 Tcl_HashKeyType tclOneWordHashKeyType = {
109 TCL_HASH_KEY_TYPE_VERSION, /* version */
111 NULL, /* HashOneWordKey, */ /* hashProc */
112 NULL, /* CompareOneWordKey, */ /* compareProc */
113 NULL, /* AllocOneWordKey, */ /* allocEntryProc */
114 NULL /* FreeOneWordKey, */ /* freeEntryProc */
117 Tcl_HashKeyType tclStringHashKeyType = {
118 TCL_HASH_KEY_TYPE_VERSION, /* version */
120 HashStringKey, /* hashKeyProc */
121 CompareStringKeys, /* compareKeysProc */
122 AllocStringEntry, /* allocEntryProc */
123 NULL /* freeEntryProc */
128 *----------------------------------------------------------------------
130 * Tcl_InitHashTable --
132 * Given storage for a hash table, set up the fields to prepare
133 * the hash table for use.
139 * TablePtr is now ready to be passed to Tcl_FindHashEntry and
140 * Tcl_CreateHashEntry.
142 *----------------------------------------------------------------------
145 #undef Tcl_InitHashTable
147 Tcl_InitHashTable(tablePtr, keyType)
148 register Tcl_HashTable *tablePtr; /* Pointer to table record, which
149 * is supplied by the caller. */
150 int keyType; /* Type of keys to use in table:
151 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
152 * or an integer >= 2. */
155 * Use a special value to inform the extended version that it must
156 * not access any of the new fields in the Tcl_HashTable. If an
157 * extension is rebuilt then any calls to this function will be
158 * redirected to the extended version by a macro.
160 Tcl_InitCustomHashTable(tablePtr, keyType, (Tcl_HashKeyType *) -1);
164 *----------------------------------------------------------------------
166 * Tcl_InitCustomHashTable --
168 * Given storage for a hash table, set up the fields to prepare
169 * the hash table for use. This is an extended version of
170 * Tcl_InitHashTable which supports user defined keys.
176 * TablePtr is now ready to be passed to Tcl_FindHashEntry and
177 * Tcl_CreateHashEntry.
179 *----------------------------------------------------------------------
183 Tcl_InitCustomHashTable(tablePtr, keyType, typePtr)
184 register Tcl_HashTable *tablePtr; /* Pointer to table record, which
185 * is supplied by the caller. */
186 int keyType; /* Type of keys to use in table:
187 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
188 * TCL_CUSTOM_TYPE_KEYS,
189 * TCL_CUSTOM_PTR_KEYS, or an
191 Tcl_HashKeyType *typePtr; /* Pointer to structure which defines
192 * the behaviour of this table. */
194 #if (TCL_SMALL_HASH_TABLE != 4)
195 panic("Tcl_InitCustomHashTable: TCL_SMALL_HASH_TABLE is %d, not 4\n",
196 TCL_SMALL_HASH_TABLE);
199 tablePtr->buckets = tablePtr->staticBuckets;
200 tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
201 tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
202 tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
203 tablePtr->numEntries = 0;
204 tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
205 tablePtr->downShift = 28;
207 tablePtr->keyType = keyType;
208 #if TCL_PRESERVE_BINARY_COMPATABILITY
209 tablePtr->findProc = Tcl_FindHashEntry;
210 tablePtr->createProc = Tcl_CreateHashEntry;
212 if (typePtr == NULL) {
214 * The caller has been rebuilt so the hash table is an extended
217 } else if (typePtr != (Tcl_HashKeyType *) -1) {
219 * The caller is requesting a customized hash table so it must be
220 * an extended version.
222 tablePtr->typePtr = typePtr;
225 * The caller has not been rebuilt so the hash table is not
230 if (typePtr == NULL) {
232 * Use the key type to decide which key type is needed.
234 if (keyType == TCL_STRING_KEYS) {
235 typePtr = &tclStringHashKeyType;
236 } else if (keyType == TCL_ONE_WORD_KEYS) {
237 typePtr = &tclOneWordHashKeyType;
238 } else if (keyType == TCL_CUSTOM_TYPE_KEYS) {
239 Tcl_Panic ("No type structure specified for TCL_CUSTOM_TYPE_KEYS");
240 } else if (keyType == TCL_CUSTOM_PTR_KEYS) {
241 Tcl_Panic ("No type structure specified for TCL_CUSTOM_PTR_KEYS");
243 typePtr = &tclArrayHashKeyType;
245 } else if (typePtr == (Tcl_HashKeyType *) -1) {
247 * If the caller has not been rebuilt then we cannot continue as
248 * the hash table is not an extended version.
250 Tcl_Panic ("Hash table is not compatible");
252 tablePtr->typePtr = typePtr;
257 *----------------------------------------------------------------------
259 * Tcl_FindHashEntry --
261 * Given a hash table find the entry with a matching key.
264 * The return value is a token for the matching entry in the
265 * hash table, or NULL if there was no matching entry.
270 *----------------------------------------------------------------------
274 Tcl_FindHashEntry(tablePtr, key)
275 Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
276 CONST char *key; /* Key to use to find matching entry. */
278 register Tcl_HashEntry *hPtr;
279 Tcl_HashKeyType *typePtr;
283 #if TCL_PRESERVE_BINARY_COMPATABILITY
284 if (tablePtr->keyType == TCL_STRING_KEYS) {
285 typePtr = &tclStringHashKeyType;
286 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
287 typePtr = &tclOneWordHashKeyType;
288 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
289 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
290 typePtr = tablePtr->typePtr;
292 typePtr = &tclArrayHashKeyType;
295 typePtr = tablePtr->typePtr;
296 if (typePtr == NULL) {
297 Tcl_Panic("called Tcl_FindHashEntry on deleted table");
302 if (typePtr->hashKeyProc) {
303 hash = typePtr->hashKeyProc (tablePtr, (VOID *) key);
304 if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
305 index = RANDOM_INDEX (tablePtr, hash);
307 index = hash & tablePtr->mask;
310 hash = (unsigned int) key;
311 index = RANDOM_INDEX (tablePtr, hash);
315 * Search all of the entries in the appropriate bucket.
318 if (typePtr->compareKeysProc) {
319 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
320 hPtr = hPtr->nextPtr) {
321 #if TCL_HASH_KEY_STORE_HASH
322 if (hash != (unsigned int) hPtr->hash) {
326 if (typePtr->compareKeysProc ((VOID *) key, hPtr)) {
331 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
332 hPtr = hPtr->nextPtr) {
333 #if TCL_HASH_KEY_STORE_HASH
334 if (hash != (unsigned int) hPtr->hash) {
338 if (key == hPtr->key.oneWordValue) {
348 *----------------------------------------------------------------------
350 * Tcl_CreateHashEntry --
352 * Given a hash table with string keys, and a string key, find
353 * the entry with a matching key. If there is no matching entry,
354 * then create a new entry that does match.
357 * The return value is a pointer to the matching entry. If this
358 * is a newly-created entry, then *newPtr will be set to a non-zero
359 * value; otherwise *newPtr will be set to 0. If this is a new
360 * entry the value stored in the entry will initially be 0.
363 * A new entry may be added to the hash table.
365 *----------------------------------------------------------------------
369 Tcl_CreateHashEntry(tablePtr, key, newPtr)
370 Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
371 CONST char *key; /* Key to use to find or create matching
373 int *newPtr; /* Store info here telling whether a new
374 * entry was created. */
376 register Tcl_HashEntry *hPtr;
377 Tcl_HashKeyType *typePtr;
381 #if TCL_PRESERVE_BINARY_COMPATABILITY
382 if (tablePtr->keyType == TCL_STRING_KEYS) {
383 typePtr = &tclStringHashKeyType;
384 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
385 typePtr = &tclOneWordHashKeyType;
386 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
387 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
388 typePtr = tablePtr->typePtr;
390 typePtr = &tclArrayHashKeyType;
393 typePtr = tablePtr->typePtr;
394 if (typePtr == NULL) {
395 Tcl_Panic("called Tcl_CreateHashEntry on deleted table");
400 if (typePtr->hashKeyProc) {
401 hash = typePtr->hashKeyProc (tablePtr, (VOID *) key);
402 if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
403 index = RANDOM_INDEX (tablePtr, hash);
405 index = hash & tablePtr->mask;
408 hash = (unsigned int) key;
409 index = RANDOM_INDEX (tablePtr, hash);
413 * Search all of the entries in the appropriate bucket.
416 if (typePtr->compareKeysProc) {
417 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
418 hPtr = hPtr->nextPtr) {
419 #if TCL_HASH_KEY_STORE_HASH
420 if (hash != (unsigned int) hPtr->hash) {
424 if (typePtr->compareKeysProc ((VOID *) key, hPtr)) {
430 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
431 hPtr = hPtr->nextPtr) {
432 #if TCL_HASH_KEY_STORE_HASH
433 if (hash != (unsigned int) hPtr->hash) {
437 if (key == hPtr->key.oneWordValue) {
445 * Entry not found. Add a new one to the bucket.
449 if (typePtr->allocEntryProc) {
450 hPtr = typePtr->allocEntryProc (tablePtr, (VOID *) key);
452 hPtr = (Tcl_HashEntry *) ckalloc((unsigned) sizeof(Tcl_HashEntry));
453 hPtr->key.oneWordValue = (char *) key;
456 hPtr->tablePtr = tablePtr;
457 #if TCL_HASH_KEY_STORE_HASH
458 # if TCL_PRESERVE_BINARY_COMPATABILITY
459 hPtr->hash = (VOID *) hash;
463 hPtr->nextPtr = tablePtr->buckets[index];
464 tablePtr->buckets[index] = hPtr;
466 hPtr->bucketPtr = &(tablePtr->buckets[index]);
467 hPtr->nextPtr = *hPtr->bucketPtr;
468 *hPtr->bucketPtr = hPtr;
470 hPtr->clientData = 0;
471 tablePtr->numEntries++;
474 * If the table has exceeded a decent size, rebuild it with many
478 if (tablePtr->numEntries >= tablePtr->rebuildSize) {
479 RebuildTable(tablePtr);
485 *----------------------------------------------------------------------
487 * Tcl_DeleteHashEntry --
489 * Remove a single entry from a hash table.
495 * The entry given by entryPtr is deleted from its table and
496 * should never again be used by the caller. It is up to the
497 * caller to free the clientData field of the entry, if that
500 *----------------------------------------------------------------------
504 Tcl_DeleteHashEntry(entryPtr)
505 Tcl_HashEntry *entryPtr;
507 register Tcl_HashEntry *prevPtr;
508 Tcl_HashKeyType *typePtr;
509 Tcl_HashTable *tablePtr;
510 Tcl_HashEntry **bucketPtr;
511 #if TCL_HASH_KEY_STORE_HASH
515 tablePtr = entryPtr->tablePtr;
517 #if TCL_PRESERVE_BINARY_COMPATABILITY
518 if (tablePtr->keyType == TCL_STRING_KEYS) {
519 typePtr = &tclStringHashKeyType;
520 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
521 typePtr = &tclOneWordHashKeyType;
522 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
523 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
524 typePtr = tablePtr->typePtr;
526 typePtr = &tclArrayHashKeyType;
529 typePtr = tablePtr->typePtr;
532 #if TCL_HASH_KEY_STORE_HASH
533 if (typePtr->hashKeyProc == NULL
534 || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
535 index = RANDOM_INDEX (tablePtr, entryPtr->hash);
537 index = ((unsigned int) entryPtr->hash) & tablePtr->mask;
540 bucketPtr = &(tablePtr->buckets[index]);
542 bucketPtr = entryPtr->bucketPtr;
545 if (*bucketPtr == entryPtr) {
546 *bucketPtr = entryPtr->nextPtr;
548 for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) {
549 if (prevPtr == NULL) {
550 panic("malformed bucket chain in Tcl_DeleteHashEntry");
552 if (prevPtr->nextPtr == entryPtr) {
553 prevPtr->nextPtr = entryPtr->nextPtr;
559 tablePtr->numEntries--;
560 if (typePtr->freeEntryProc) {
561 typePtr->freeEntryProc (entryPtr);
563 ckfree((char *) entryPtr);
568 *----------------------------------------------------------------------
570 * Tcl_DeleteHashTable --
572 * Free up everything associated with a hash table except for
573 * the record for the table itself.
579 * The hash table is no longer useable.
581 *----------------------------------------------------------------------
585 Tcl_DeleteHashTable(tablePtr)
586 register Tcl_HashTable *tablePtr; /* Table to delete. */
588 register Tcl_HashEntry *hPtr, *nextPtr;
589 Tcl_HashKeyType *typePtr;
592 #if TCL_PRESERVE_BINARY_COMPATABILITY
593 if (tablePtr->keyType == TCL_STRING_KEYS) {
594 typePtr = &tclStringHashKeyType;
595 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
596 typePtr = &tclOneWordHashKeyType;
597 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
598 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
599 typePtr = tablePtr->typePtr;
601 typePtr = &tclArrayHashKeyType;
604 typePtr = tablePtr->typePtr;
608 * Free up all the entries in the table.
611 for (i = 0; i < tablePtr->numBuckets; i++) {
612 hPtr = tablePtr->buckets[i];
613 while (hPtr != NULL) {
614 nextPtr = hPtr->nextPtr;
615 if (typePtr->freeEntryProc) {
616 typePtr->freeEntryProc (hPtr);
618 ckfree((char *) hPtr);
625 * Free up the bucket array, if it was dynamically allocated.
628 if (tablePtr->buckets != tablePtr->staticBuckets) {
629 ckfree((char *) tablePtr->buckets);
633 * Arrange for panics if the table is used again without
637 #if TCL_PRESERVE_BINARY_COMPATABILITY
638 tablePtr->findProc = BogusFind;
639 tablePtr->createProc = BogusCreate;
641 tablePtr->typePtr = NULL;
646 *----------------------------------------------------------------------
648 * Tcl_FirstHashEntry --
650 * Locate the first entry in a hash table and set up a record
651 * that can be used to step through all the remaining entries
655 * The return value is a pointer to the first entry in tablePtr,
656 * or NULL if tablePtr has no entries in it. The memory at
657 * *searchPtr is initialized so that subsequent calls to
658 * Tcl_NextHashEntry will return all of the entries in the table,
664 *----------------------------------------------------------------------
668 Tcl_FirstHashEntry(tablePtr, searchPtr)
669 Tcl_HashTable *tablePtr; /* Table to search. */
670 Tcl_HashSearch *searchPtr; /* Place to store information about
671 * progress through the table. */
673 searchPtr->tablePtr = tablePtr;
674 searchPtr->nextIndex = 0;
675 searchPtr->nextEntryPtr = NULL;
676 return Tcl_NextHashEntry(searchPtr);
680 *----------------------------------------------------------------------
682 * Tcl_NextHashEntry --
684 * Once a hash table enumeration has been initiated by calling
685 * Tcl_FirstHashEntry, this procedure may be called to return
686 * successive elements of the table.
689 * The return value is the next entry in the hash table being
690 * enumerated, or NULL if the end of the table is reached.
695 *----------------------------------------------------------------------
699 Tcl_NextHashEntry(searchPtr)
700 register Tcl_HashSearch *searchPtr; /* Place to store information about
701 * progress through the table. Must
702 * have been initialized by calling
703 * Tcl_FirstHashEntry. */
707 while (searchPtr->nextEntryPtr == NULL) {
708 if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) {
711 searchPtr->nextEntryPtr =
712 searchPtr->tablePtr->buckets[searchPtr->nextIndex];
713 searchPtr->nextIndex++;
715 hPtr = searchPtr->nextEntryPtr;
716 searchPtr->nextEntryPtr = hPtr->nextPtr;
721 *----------------------------------------------------------------------
725 * Return statistics describing the layout of the hash table
726 * in its hash buckets.
729 * The return value is a malloc-ed string containing information
730 * about tablePtr. It is the caller's responsibility to free
736 *----------------------------------------------------------------------
740 Tcl_HashStats(tablePtr)
741 Tcl_HashTable *tablePtr; /* Table for which to produce stats. */
743 #define NUM_COUNTERS 10
744 int count[NUM_COUNTERS], overflow, i, j;
746 register Tcl_HashEntry *hPtr;
750 * Compute a histogram of bucket usage.
753 for (i = 0; i < NUM_COUNTERS; i++) {
758 for (i = 0; i < tablePtr->numBuckets; i++) {
760 for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) {
763 if (j < NUM_COUNTERS) {
769 average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
773 * Print out the histogram and a few other pieces of information.
776 result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300));
777 sprintf(result, "%d entries in table, %d buckets\n",
778 tablePtr->numEntries, tablePtr->numBuckets);
779 p = result + strlen(result);
780 for (i = 0; i < NUM_COUNTERS; i++) {
781 sprintf(p, "number of buckets with %d entries: %d\n",
785 sprintf(p, "number of buckets with %d or more entries: %d\n",
786 NUM_COUNTERS, overflow);
788 sprintf(p, "average search distance for entry: %.1f", average);
793 *----------------------------------------------------------------------
797 * Allocate space for a Tcl_HashEntry containing the array key.
800 * The return value is a pointer to the created entry.
805 *----------------------------------------------------------------------
808 static Tcl_HashEntry *
809 AllocArrayEntry(tablePtr, keyPtr)
810 Tcl_HashTable *tablePtr; /* Hash table. */
811 VOID *keyPtr; /* Key to store in the hash table entry. */
813 int *array = (int *) keyPtr;
814 register int *iPtr1, *iPtr2;
819 count = tablePtr->keyType;
821 size = sizeof(Tcl_HashEntry) + (count*sizeof(int)) - sizeof(hPtr->key);
822 if (size < sizeof(Tcl_HashEntry))
823 size = sizeof(Tcl_HashEntry);
824 hPtr = (Tcl_HashEntry *) ckalloc(size);
826 for (iPtr1 = array, iPtr2 = hPtr->key.words;
827 count > 0; count--, iPtr1++, iPtr2++) {
835 *----------------------------------------------------------------------
837 * CompareArrayKeys --
839 * Compares two array keys.
842 * The return value is 0 if they are different and 1 if they are
848 *----------------------------------------------------------------------
852 CompareArrayKeys(keyPtr, hPtr)
853 VOID *keyPtr; /* New key to compare. */
854 Tcl_HashEntry *hPtr; /* Existing key to compare. */
856 register CONST int *iPtr1 = (CONST int *) keyPtr;
857 register CONST int *iPtr2 = (CONST int *) hPtr->key.words;
858 Tcl_HashTable *tablePtr = hPtr->tablePtr;
861 for (count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
865 if (*iPtr1 != *iPtr2) {
873 *----------------------------------------------------------------------
877 * Compute a one-word summary of an array, which can be
878 * used to generate a hash index.
881 * The return value is a one-word summary of the information in
887 *----------------------------------------------------------------------
891 HashArrayKey(tablePtr, keyPtr)
892 Tcl_HashTable *tablePtr; /* Hash table. */
893 VOID *keyPtr; /* Key from which to compute hash value. */
895 register CONST int *array = (CONST int *) keyPtr;
896 register unsigned int result;
899 for (result = 0, count = tablePtr->keyType; count > 0;
907 *----------------------------------------------------------------------
909 * AllocStringEntry --
911 * Allocate space for a Tcl_HashEntry containing the string key.
914 * The return value is a pointer to the created entry.
919 *----------------------------------------------------------------------
922 static Tcl_HashEntry *
923 AllocStringEntry(tablePtr, keyPtr)
924 Tcl_HashTable *tablePtr; /* Hash table. */
925 VOID *keyPtr; /* Key to store in the hash table entry. */
927 CONST char *string = (CONST char *) keyPtr;
931 size = sizeof(Tcl_HashEntry) + strlen(string) + 1 - sizeof(hPtr->key);
932 if (size < sizeof(Tcl_HashEntry))
933 size = sizeof(Tcl_HashEntry);
934 hPtr = (Tcl_HashEntry *) ckalloc(size);
935 strcpy(hPtr->key.string, string);
941 *----------------------------------------------------------------------
943 * CompareStringKeys --
945 * Compares two string keys.
948 * The return value is 0 if they are different and 1 if they are
954 *----------------------------------------------------------------------
958 CompareStringKeys(keyPtr, hPtr)
959 VOID *keyPtr; /* New key to compare. */
960 Tcl_HashEntry *hPtr; /* Existing key to compare. */
962 register CONST char *p1 = (CONST char *) keyPtr;
963 register CONST char *p2 = (CONST char *) hPtr->key.string;
965 for (;; p1++, p2++) {
977 *----------------------------------------------------------------------
981 * Compute a one-word summary of a text string, which can be
982 * used to generate a hash index.
985 * The return value is a one-word summary of the information in
991 *----------------------------------------------------------------------
995 HashStringKey(tablePtr, keyPtr)
996 Tcl_HashTable *tablePtr; /* Hash table. */
997 VOID *keyPtr; /* Key from which to compute hash value. */
999 register CONST char *string = (CONST char *) keyPtr;
1000 register unsigned int result;
1004 * I tried a zillion different hash functions and asked many other
1005 * people for advice. Many people had their own favorite functions,
1006 * all different, but no-one had much idea why they were good ones.
1007 * I chose the one below (multiply by 9 and add new character)
1008 * because of the following reasons:
1010 * 1. Multiplying by 10 is perfect for keys that are decimal strings,
1011 * and multiplying by 9 is just about as good.
1012 * 2. Times-9 is (shift-left-3) plus (old). This means that each
1013 * character's bits hang around in the low-order bits of the
1014 * hash value for ever, plus they spread fairly rapidly up to
1015 * the high-order bits to fill out the hash value. This seems
1016 * works well both for decimal and non-decimal strings.
1026 result += (result<<3) + c;
1031 #if TCL_PRESERVE_BINARY_COMPATABILITY
1033 *----------------------------------------------------------------------
1037 * This procedure is invoked when an Tcl_FindHashEntry is called
1038 * on a table that has been deleted.
1041 * If panic returns (which it shouldn't) this procedure returns
1045 * Generates a panic.
1047 *----------------------------------------------------------------------
1051 static Tcl_HashEntry *
1052 BogusFind(tablePtr, key)
1053 Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
1054 CONST char *key; /* Key to use to find matching entry. */
1056 panic("called Tcl_FindHashEntry on deleted table");
1061 *----------------------------------------------------------------------
1065 * This procedure is invoked when an Tcl_CreateHashEntry is called
1066 * on a table that has been deleted.
1069 * If panic returns (which it shouldn't) this procedure returns
1073 * Generates a panic.
1075 *----------------------------------------------------------------------
1079 static Tcl_HashEntry *
1080 BogusCreate(tablePtr, key, newPtr)
1081 Tcl_HashTable *tablePtr; /* Table in which to lookup entry. */
1082 CONST char *key; /* Key to use to find or create matching
1084 int *newPtr; /* Store info here telling whether a new
1085 * entry was created. */
1087 panic("called Tcl_CreateHashEntry on deleted table");
1093 *----------------------------------------------------------------------
1097 * This procedure is invoked when the ratio of entries to hash
1098 * buckets becomes too large. It creates a new table with a
1099 * larger bucket array and moves all of the entries into the
1106 * Memory gets reallocated and entries get re-hashed to new
1109 *----------------------------------------------------------------------
1113 RebuildTable(tablePtr)
1114 register Tcl_HashTable *tablePtr; /* Table to enlarge. */
1116 int oldSize, count, index;
1117 Tcl_HashEntry **oldBuckets;
1118 register Tcl_HashEntry **oldChainPtr, **newChainPtr;
1119 register Tcl_HashEntry *hPtr;
1120 Tcl_HashKeyType *typePtr;
1123 oldSize = tablePtr->numBuckets;
1124 oldBuckets = tablePtr->buckets;
1127 * Allocate and initialize the new bucket array, and set up
1128 * hashing constants for new array size.
1131 tablePtr->numBuckets *= 4;
1132 tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned)
1133 (tablePtr->numBuckets * sizeof(Tcl_HashEntry *)));
1134 for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
1135 count > 0; count--, newChainPtr++) {
1136 *newChainPtr = NULL;
1138 tablePtr->rebuildSize *= 4;
1139 tablePtr->downShift -= 2;
1140 tablePtr->mask = (tablePtr->mask << 2) + 3;
1142 #if TCL_PRESERVE_BINARY_COMPATABILITY
1143 if (tablePtr->keyType == TCL_STRING_KEYS) {
1144 typePtr = &tclStringHashKeyType;
1145 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
1146 typePtr = &tclOneWordHashKeyType;
1147 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
1148 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
1149 typePtr = tablePtr->typePtr;
1151 typePtr = &tclArrayHashKeyType;
1154 typePtr = tablePtr->typePtr;
1158 * Rehash all of the existing entries into the new bucket array.
1161 for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
1162 for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
1163 *oldChainPtr = hPtr->nextPtr;
1165 key = (VOID *) Tcl_GetHashKey (tablePtr, hPtr);
1167 #if TCL_HASH_KEY_STORE_HASH
1168 if (typePtr->hashKeyProc == NULL
1169 || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
1170 index = RANDOM_INDEX (tablePtr, hPtr->hash);
1172 index = ((unsigned int) hPtr->hash) & tablePtr->mask;
1174 hPtr->nextPtr = tablePtr->buckets[index];
1175 tablePtr->buckets[index] = hPtr;
1177 if (typePtr->hashKeyProc) {
1179 hash = typePtr->hashKeyProc (tablePtr, (VOID *) key);
1180 if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
1181 index = RANDOM_INDEX (tablePtr, hash);
1183 index = hash & tablePtr->mask;
1186 index = RANDOM_INDEX (tablePtr, key);
1189 hPtr->bucketPtr = &(tablePtr->buckets[index]);
1190 hPtr->nextPtr = *hPtr->bucketPtr;
1191 *hPtr->bucketPtr = hPtr;
1197 * Free up the old bucket array, if it was dynamically allocated.
1200 if (oldBuckets != tablePtr->staticBuckets) {
1201 ckfree((char *) oldBuckets);