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 of
11 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
17 * Prevent macros from clashing with function definitions.
20 #undef Tcl_FindHashEntry
21 #undef Tcl_CreateHashEntry
24 * When there are this many entries per bucket, on average, rebuild the hash
25 * table to make it larger.
28 #define REBUILD_MULTIPLIER 3
31 * The following macro takes a preliminary integer hash value and produces an
32 * index into a hash tables bucket list. The idea is to make it so that
33 * preliminary values that are arbitrarily similar will end up in different
34 * buckets. The hash function was taken from a random-number generator.
37 #define RANDOM_INDEX(tablePtr, i) \
38 ((((i)*1103515245L) >> (tablePtr)->downShift) & (tablePtr)->mask)
41 * Prototypes for the array hash key methods.
44 static Tcl_HashEntry * AllocArrayEntry(Tcl_HashTable *tablePtr, void *keyPtr);
45 static int CompareArrayKeys(void *keyPtr, Tcl_HashEntry *hPtr);
46 static unsigned int HashArrayKey(Tcl_HashTable *tablePtr, void *keyPtr);
49 * Prototypes for the one word hash key methods. Not actually declared because
50 * this is a critical path that is implemented in the core hash table access
55 static Tcl_HashEntry * AllocOneWordEntry(Tcl_HashTable *tablePtr,
57 static int CompareOneWordKeys(void *keyPtr, Tcl_HashEntry *hPtr);
58 static unsigned int HashOneWordKey(Tcl_HashTable *tablePtr, void *keyPtr);
62 * Prototypes for the string hash key methods.
65 static Tcl_HashEntry * AllocStringEntry(Tcl_HashTable *tablePtr,
67 static int CompareStringKeys(void *keyPtr, Tcl_HashEntry *hPtr);
68 static unsigned int HashStringKey(Tcl_HashTable *tablePtr, void *keyPtr);
71 * Function prototypes for static functions in this file:
74 static Tcl_HashEntry * BogusFind(Tcl_HashTable *tablePtr, const char *key);
75 static Tcl_HashEntry * BogusCreate(Tcl_HashTable *tablePtr, const char *key,
77 static Tcl_HashEntry * CreateHashEntry(Tcl_HashTable *tablePtr, const char *key,
79 static Tcl_HashEntry * FindHashEntry(Tcl_HashTable *tablePtr, const char *key);
80 static void RebuildTable(Tcl_HashTable *tablePtr);
82 const Tcl_HashKeyType tclArrayHashKeyType = {
83 TCL_HASH_KEY_TYPE_VERSION, /* version */
84 TCL_HASH_KEY_RANDOMIZE_HASH, /* flags */
85 HashArrayKey, /* hashKeyProc */
86 CompareArrayKeys, /* compareKeysProc */
87 AllocArrayEntry, /* allocEntryProc */
88 NULL /* freeEntryProc */
91 const Tcl_HashKeyType tclOneWordHashKeyType = {
92 TCL_HASH_KEY_TYPE_VERSION, /* version */
94 NULL, /* HashOneWordKey, */ /* hashProc */
95 NULL, /* CompareOneWordKey, */ /* compareProc */
96 NULL, /* AllocOneWordKey, */ /* allocEntryProc */
97 NULL /* FreeOneWordKey, */ /* freeEntryProc */
100 const Tcl_HashKeyType tclStringHashKeyType = {
101 TCL_HASH_KEY_TYPE_VERSION, /* version */
103 HashStringKey, /* hashKeyProc */
104 CompareStringKeys, /* compareKeysProc */
105 AllocStringEntry, /* allocEntryProc */
106 NULL /* freeEntryProc */
110 *----------------------------------------------------------------------
112 * Tcl_InitHashTable --
114 * Given storage for a hash table, set up the fields to prepare the hash
121 * TablePtr is now ready to be passed to Tcl_FindHashEntry and
122 * Tcl_CreateHashEntry.
124 *----------------------------------------------------------------------
129 Tcl_HashTable *tablePtr,
130 /* Pointer to table record, which is supplied
132 int keyType) /* Type of keys to use in table:
133 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS, or an
137 * Use a special value to inform the extended version that it must not
138 * access any of the new fields in the Tcl_HashTable. If an extension is
139 * rebuilt then any calls to this function will be redirected to the
140 * extended version by a macro.
143 Tcl_InitCustomHashTable(tablePtr, keyType, (const Tcl_HashKeyType *) -1);
147 *----------------------------------------------------------------------
149 * Tcl_InitCustomHashTable --
151 * Given storage for a hash table, set up the fields to prepare the hash
152 * table for use. This is an extended version of Tcl_InitHashTable which
153 * supports user defined keys.
159 * TablePtr is now ready to be passed to Tcl_FindHashEntry and
160 * Tcl_CreateHashEntry.
162 *----------------------------------------------------------------------
166 Tcl_InitCustomHashTable(
167 Tcl_HashTable *tablePtr,
168 /* Pointer to table record, which is supplied
170 int keyType, /* Type of keys to use in table:
171 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
172 * TCL_CUSTOM_TYPE_KEYS, TCL_CUSTOM_PTR_KEYS,
173 * or an integer >= 2. */
174 const Tcl_HashKeyType *typePtr) /* Pointer to structure which defines the
175 * behaviour of this table. */
177 #if (TCL_SMALL_HASH_TABLE != 4)
178 Tcl_Panic("Tcl_InitCustomHashTable: TCL_SMALL_HASH_TABLE is %d, not 4",
179 TCL_SMALL_HASH_TABLE);
182 tablePtr->buckets = tablePtr->staticBuckets;
183 tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
184 tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
185 tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
186 tablePtr->numEntries = 0;
187 tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
188 tablePtr->downShift = 28;
190 tablePtr->keyType = keyType;
191 tablePtr->findProc = FindHashEntry;
192 tablePtr->createProc = CreateHashEntry;
194 if (typePtr == NULL) {
196 * The caller has been rebuilt so the hash table is an extended
199 } else if (typePtr != (Tcl_HashKeyType *) -1) {
201 * The caller is requesting a customized hash table so it must be an
205 tablePtr->typePtr = typePtr;
208 * The caller has not been rebuilt so the hash table is not extended.
214 *----------------------------------------------------------------------
216 * Tcl_FindHashEntry --
218 * Given a hash table find the entry with a matching key.
221 * The return value is a token for the matching entry in the hash table,
222 * or NULL if there was no matching entry.
227 *----------------------------------------------------------------------
232 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
233 const void *key) /* Key to use to find matching entry. */
235 return (*((tablePtr)->findProc))(tablePtr, key);
238 static Tcl_HashEntry *
240 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
241 const char *key) /* Key to use to find matching entry. */
243 return CreateHashEntry(tablePtr, key, NULL);
248 *----------------------------------------------------------------------
250 * Tcl_CreateHashEntry --
252 * Given a hash table with string keys, and a string key, find the entry
253 * with a matching key. If there is no matching entry, then create a new
254 * entry that does match.
257 * The return value is a pointer to the matching entry. If this is a
258 * newly-created entry, then *newPtr will be set to a non-zero value;
259 * otherwise *newPtr will be set to 0. If this is a new entry the value
260 * stored in the entry will initially be 0.
263 * A new entry may be added to the hash table.
265 *----------------------------------------------------------------------
270 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
271 const void *key, /* Key to use to find or create matching
273 int *newPtr) /* Store info here telling whether a new entry
276 return (*((tablePtr)->createProc))(tablePtr, key, newPtr);
279 static Tcl_HashEntry *
281 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
282 const char *key, /* Key to use to find or create matching
284 int *newPtr) /* Store info here telling whether a new entry
288 const Tcl_HashKeyType *typePtr;
292 if (tablePtr->keyType == TCL_STRING_KEYS) {
293 typePtr = &tclStringHashKeyType;
294 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
295 typePtr = &tclOneWordHashKeyType;
296 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
297 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
298 typePtr = tablePtr->typePtr;
300 typePtr = &tclArrayHashKeyType;
303 if (typePtr->hashKeyProc) {
304 hash = typePtr->hashKeyProc(tablePtr, (void *) key);
305 if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
306 index = RANDOM_INDEX(tablePtr, hash);
308 index = hash & tablePtr->mask;
311 hash = PTR2UINT(key);
312 index = RANDOM_INDEX(tablePtr, hash);
316 * Search all of the entries in the appropriate bucket.
319 if (typePtr->compareKeysProc) {
320 Tcl_CompareHashKeysProc *compareKeysProc = typePtr->compareKeysProc;
322 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
323 hPtr = hPtr->nextPtr) {
324 #if TCL_HASH_KEY_STORE_HASH
325 if (hash != PTR2UINT(hPtr->hash)) {
329 /* if keys pointers or values are equal */
330 if ((key == hPtr->key.oneWordValue)
331 || compareKeysProc((void *) key, hPtr)
340 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
341 hPtr = hPtr->nextPtr) {
342 #if TCL_HASH_KEY_STORE_HASH
343 if (hash != PTR2UINT(hPtr->hash)) {
347 if (key == hPtr->key.oneWordValue) {
361 * Entry not found. Add a new one to the bucket.
365 if (typePtr->allocEntryProc) {
366 hPtr = typePtr->allocEntryProc(tablePtr, (void *) key);
368 hPtr = ckalloc(sizeof(Tcl_HashEntry));
369 hPtr->key.oneWordValue = (char *) key;
370 hPtr->clientData = 0;
373 hPtr->tablePtr = tablePtr;
374 #if TCL_HASH_KEY_STORE_HASH
375 hPtr->hash = UINT2PTR(hash);
376 hPtr->nextPtr = tablePtr->buckets[index];
377 tablePtr->buckets[index] = hPtr;
379 hPtr->bucketPtr = &tablePtr->buckets[index];
380 hPtr->nextPtr = *hPtr->bucketPtr;
381 *hPtr->bucketPtr = hPtr;
383 tablePtr->numEntries++;
386 * If the table has exceeded a decent size, rebuild it with many more
390 if (tablePtr->numEntries >= tablePtr->rebuildSize) {
391 RebuildTable(tablePtr);
397 *----------------------------------------------------------------------
399 * Tcl_DeleteHashEntry --
401 * Remove a single entry from a hash table.
407 * The entry given by entryPtr is deleted from its table and should never
408 * again be used by the caller. It is up to the caller to free the
409 * clientData field of the entry, if that is relevant.
411 *----------------------------------------------------------------------
416 Tcl_HashEntry *entryPtr)
418 Tcl_HashEntry *prevPtr;
419 const Tcl_HashKeyType *typePtr;
420 Tcl_HashTable *tablePtr;
421 Tcl_HashEntry **bucketPtr;
422 #if TCL_HASH_KEY_STORE_HASH
426 tablePtr = entryPtr->tablePtr;
428 if (tablePtr->keyType == TCL_STRING_KEYS) {
429 typePtr = &tclStringHashKeyType;
430 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
431 typePtr = &tclOneWordHashKeyType;
432 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
433 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
434 typePtr = tablePtr->typePtr;
436 typePtr = &tclArrayHashKeyType;
439 #if TCL_HASH_KEY_STORE_HASH
440 if (typePtr->hashKeyProc == NULL
441 || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
442 index = RANDOM_INDEX(tablePtr, PTR2INT(entryPtr->hash));
444 index = PTR2UINT(entryPtr->hash) & tablePtr->mask;
447 bucketPtr = &tablePtr->buckets[index];
449 bucketPtr = entryPtr->bucketPtr;
452 if (*bucketPtr == entryPtr) {
453 *bucketPtr = entryPtr->nextPtr;
455 for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) {
456 if (prevPtr == NULL) {
457 Tcl_Panic("malformed bucket chain in Tcl_DeleteHashEntry");
459 if (prevPtr->nextPtr == entryPtr) {
460 prevPtr->nextPtr = entryPtr->nextPtr;
466 tablePtr->numEntries--;
467 if (typePtr->freeEntryProc) {
468 typePtr->freeEntryProc(entryPtr);
475 *----------------------------------------------------------------------
477 * Tcl_DeleteHashTable --
479 * Free up everything associated with a hash table except for the record
480 * for the table itself.
486 * The hash table is no longer useable.
488 *----------------------------------------------------------------------
493 Tcl_HashTable *tablePtr) /* Table to delete. */
495 Tcl_HashEntry *hPtr, *nextPtr;
496 const Tcl_HashKeyType *typePtr;
499 if (tablePtr->keyType == TCL_STRING_KEYS) {
500 typePtr = &tclStringHashKeyType;
501 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
502 typePtr = &tclOneWordHashKeyType;
503 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
504 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
505 typePtr = tablePtr->typePtr;
507 typePtr = &tclArrayHashKeyType;
511 * Free up all the entries in the table.
514 for (i = 0; i < tablePtr->numBuckets; i++) {
515 hPtr = tablePtr->buckets[i];
516 while (hPtr != NULL) {
517 nextPtr = hPtr->nextPtr;
518 if (typePtr->freeEntryProc) {
519 typePtr->freeEntryProc(hPtr);
528 * Free up the bucket array, if it was dynamically allocated.
531 if (tablePtr->buckets != tablePtr->staticBuckets) {
532 if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) {
533 TclpSysFree((char *) tablePtr->buckets);
535 ckfree(tablePtr->buckets);
540 * Arrange for panics if the table is used again without
544 tablePtr->findProc = BogusFind;
545 tablePtr->createProc = BogusCreate;
549 *----------------------------------------------------------------------
551 * Tcl_FirstHashEntry --
553 * Locate the first entry in a hash table and set up a record that can be
554 * used to step through all the remaining entries of the table.
557 * The return value is a pointer to the first entry in tablePtr, or NULL
558 * if tablePtr has no entries in it. The memory at *searchPtr is
559 * initialized so that subsequent calls to Tcl_NextHashEntry will return
560 * all of the entries in the table, one at a time.
565 *----------------------------------------------------------------------
570 Tcl_HashTable *tablePtr, /* Table to search. */
571 Tcl_HashSearch *searchPtr) /* Place to store information about progress
572 * through the table. */
574 searchPtr->tablePtr = tablePtr;
575 searchPtr->nextIndex = 0;
576 searchPtr->nextEntryPtr = NULL;
577 return Tcl_NextHashEntry(searchPtr);
581 *----------------------------------------------------------------------
583 * Tcl_NextHashEntry --
585 * Once a hash table enumeration has been initiated by calling
586 * Tcl_FirstHashEntry, this function may be called to return successive
587 * elements of the table.
590 * The return value is the next entry in the hash table being enumerated,
591 * or NULL if the end of the table is reached.
596 *----------------------------------------------------------------------
601 Tcl_HashSearch *searchPtr)
602 /* Place to store information about progress
603 * through the table. Must have been
604 * initialized by calling
605 * Tcl_FirstHashEntry. */
608 Tcl_HashTable *tablePtr = searchPtr->tablePtr;
610 while (searchPtr->nextEntryPtr == NULL) {
611 if (searchPtr->nextIndex >= tablePtr->numBuckets) {
614 searchPtr->nextEntryPtr =
615 tablePtr->buckets[searchPtr->nextIndex];
616 searchPtr->nextIndex++;
618 hPtr = searchPtr->nextEntryPtr;
619 searchPtr->nextEntryPtr = hPtr->nextPtr;
624 *----------------------------------------------------------------------
628 * Return statistics describing the layout of the hash table in its hash
632 * The return value is a malloc-ed string containing information about
633 * tablePtr. It is the caller's responsibility to free this string.
638 *----------------------------------------------------------------------
643 Tcl_HashTable *tablePtr) /* Table for which to produce stats. */
645 #define NUM_COUNTERS 10
646 int count[NUM_COUNTERS], overflow, i, j;
652 * Compute a histogram of bucket usage.
655 for (i = 0; i < NUM_COUNTERS; i++) {
660 for (i = 0; i < tablePtr->numBuckets; i++) {
662 for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) {
665 if (j < NUM_COUNTERS) {
671 if (tablePtr->numEntries != 0) {
672 average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
677 * Print out the histogram and a few other pieces of information.
680 result = ckalloc((NUM_COUNTERS * 60) + 300);
681 sprintf(result, "%d entries in table, %d buckets\n",
682 tablePtr->numEntries, tablePtr->numBuckets);
683 p = result + strlen(result);
684 for (i = 0; i < NUM_COUNTERS; i++) {
685 sprintf(p, "number of buckets with %d entries: %d\n",
689 sprintf(p, "number of buckets with %d or more entries: %d\n",
690 NUM_COUNTERS, overflow);
692 sprintf(p, "average search distance for entry: %.1f", average);
697 *----------------------------------------------------------------------
701 * Allocate space for a Tcl_HashEntry containing the array key.
704 * The return value is a pointer to the created entry.
709 *----------------------------------------------------------------------
712 static Tcl_HashEntry *
714 Tcl_HashTable *tablePtr, /* Hash table. */
715 void *keyPtr) /* Key to store in the hash table entry. */
717 int *array = (int *) keyPtr;
723 count = tablePtr->keyType;
725 size = sizeof(Tcl_HashEntry) + (count*sizeof(int)) - sizeof(hPtr->key);
726 if (size < sizeof(Tcl_HashEntry)) {
727 size = sizeof(Tcl_HashEntry);
729 hPtr = ckalloc(size);
731 for (iPtr1 = array, iPtr2 = hPtr->key.words;
732 count > 0; count--, iPtr1++, iPtr2++) {
735 hPtr->clientData = 0;
741 *----------------------------------------------------------------------
743 * CompareArrayKeys --
745 * Compares two array keys.
748 * The return value is 0 if they are different and 1 if they are the
754 *----------------------------------------------------------------------
759 void *keyPtr, /* New key to compare. */
760 Tcl_HashEntry *hPtr) /* Existing key to compare. */
762 const int *iPtr1 = (const int *) keyPtr;
763 const int *iPtr2 = (const int *) hPtr->key.words;
764 Tcl_HashTable *tablePtr = hPtr->tablePtr;
767 for (count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
771 if (*iPtr1 != *iPtr2) {
779 *----------------------------------------------------------------------
783 * Compute a one-word summary of an array, which can be used to generate
787 * The return value is a one-word summary of the information in
793 *----------------------------------------------------------------------
798 Tcl_HashTable *tablePtr, /* Hash table. */
799 void *keyPtr) /* Key from which to compute hash value. */
801 const int *array = (const int *) keyPtr;
805 for (result = 0, count = tablePtr->keyType; count > 0;
813 *----------------------------------------------------------------------
815 * AllocStringEntry --
817 * Allocate space for a Tcl_HashEntry containing the string key.
820 * The return value is a pointer to the created entry.
825 *----------------------------------------------------------------------
828 static Tcl_HashEntry *
830 Tcl_HashTable *tablePtr, /* Hash table. */
831 void *keyPtr) /* Key to store in the hash table entry. */
833 const char *string = (const char *) keyPtr;
835 unsigned int size, allocsize;
837 allocsize = size = strlen(string) + 1;
838 if (size < sizeof(hPtr->key)) {
839 allocsize = sizeof(hPtr->key);
841 hPtr = ckalloc(TclOffset(Tcl_HashEntry, key) + allocsize);
842 memset(hPtr, 0, sizeof(Tcl_HashEntry) + allocsize - sizeof(hPtr->key));
843 memcpy(hPtr->key.string, string, size);
844 hPtr->clientData = 0;
849 *----------------------------------------------------------------------
851 * CompareStringKeys --
853 * Compares two string keys.
856 * The return value is 0 if they are different and 1 if they are the
862 *----------------------------------------------------------------------
867 void *keyPtr, /* New key to compare. */
868 Tcl_HashEntry *hPtr) /* Existing key to compare. */
870 const char *p1 = (const char *) keyPtr;
871 const char *p2 = (const char *) hPtr->key.string;
873 return !strcmp(p1, p2);
877 *----------------------------------------------------------------------
881 * Compute a one-word summary of a text string, which can be used to
882 * generate a hash index.
885 * The return value is a one-word summary of the information in string.
890 *----------------------------------------------------------------------
895 Tcl_HashTable *tablePtr, /* Hash table. */
896 void *keyPtr) /* Key from which to compute hash value. */
898 const char *string = keyPtr;
903 * I tried a zillion different hash functions and asked many other people
904 * for advice. Many people had their own favorite functions, all
905 * different, but no-one had much idea why they were good ones. I chose
906 * the one below (multiply by 9 and add new character) because of the
909 * 1. Multiplying by 10 is perfect for keys that are decimal strings, and
910 * multiplying by 9 is just about as good.
911 * 2. Times-9 is (shift-left-3) plus (old). This means that each
912 * character's bits hang around in the low-order bits of the hash value
913 * for ever, plus they spread fairly rapidly up to the high-order bits
914 * to fill out the hash value. This seems works well both for decimal
915 * and non-decimal strings, but isn't strong against maliciously-chosen
918 * Note that this function is very weak against malicious strings; it's
919 * very easy to generate multiple keys that have the same hashcode. On the
920 * other hand, that hardly ever actually occurs and this function *is*
921 * very cheap, even by comparison with industry-standard hashes like FNV.
922 * If real strength of hash is required though, use a custom hash based on
923 * Bob Jenkins's lookup3(), but be aware that it's significantly slower.
924 * Since Tcl command and namespace names are usually reasonably-named (the
925 * main use for string hashes in modern Tcl) speed is far more important
928 * See also HashString in tclLiteral.c.
929 * See also TclObjHashKey in tclObj.c.
931 * See [tcl-Feature Request #2958832]
934 if ((result = UCHAR(*string)) != 0) {
935 while ((c = *++string) != 0) {
936 result += (result << 3) + UCHAR(c);
943 *----------------------------------------------------------------------
947 * This function is invoked when an Tcl_FindHashEntry is called on a
948 * table that has been deleted.
951 * If Tcl_Panic returns (which it shouldn't) this function returns NULL.
956 *----------------------------------------------------------------------
960 static Tcl_HashEntry *
962 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
963 const char *key) /* Key to use to find matching entry. */
965 Tcl_Panic("called %s on deleted table", "Tcl_FindHashEntry");
970 *----------------------------------------------------------------------
974 * This function is invoked when an Tcl_CreateHashEntry is called on a
975 * table that has been deleted.
978 * If panic returns (which it shouldn't) this function returns NULL.
983 *----------------------------------------------------------------------
987 static Tcl_HashEntry *
989 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
990 const char *key, /* Key to use to find or create matching
992 int *newPtr) /* Store info here telling whether a new entry
995 Tcl_Panic("called %s on deleted table", "Tcl_CreateHashEntry");
1000 *----------------------------------------------------------------------
1004 * This function is invoked when the ratio of entries to hash buckets
1005 * becomes too large. It creates a new table with a larger bucket array
1006 * and moves all of the entries into the new table.
1012 * Memory gets reallocated and entries get re-hashed to new buckets.
1014 *----------------------------------------------------------------------
1019 Tcl_HashTable *tablePtr) /* Table to enlarge. */
1021 int count, index, oldSize = tablePtr->numBuckets;
1022 Tcl_HashEntry **oldBuckets = tablePtr->buckets;
1023 Tcl_HashEntry **oldChainPtr, **newChainPtr;
1024 Tcl_HashEntry *hPtr;
1025 const Tcl_HashKeyType *typePtr;
1027 /* Avoid outgrowing capability of the memory allocators */
1028 if (oldSize > (int)(UINT_MAX / (4 * sizeof(Tcl_HashEntry *)))) {
1029 tablePtr->rebuildSize = INT_MAX;
1033 if (tablePtr->keyType == TCL_STRING_KEYS) {
1034 typePtr = &tclStringHashKeyType;
1035 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
1036 typePtr = &tclOneWordHashKeyType;
1037 } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
1038 || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
1039 typePtr = tablePtr->typePtr;
1041 typePtr = &tclArrayHashKeyType;
1045 * Allocate and initialize the new bucket array, and set up hashing
1046 * constants for new array size.
1049 tablePtr->numBuckets *= 4;
1050 if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) {
1051 tablePtr->buckets = (Tcl_HashEntry **) TclpSysAlloc((unsigned)
1052 (tablePtr->numBuckets * sizeof(Tcl_HashEntry *)), 0);
1055 ckalloc(tablePtr->numBuckets * sizeof(Tcl_HashEntry *));
1057 for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
1058 count > 0; count--, newChainPtr++) {
1059 *newChainPtr = NULL;
1061 tablePtr->rebuildSize *= 4;
1062 tablePtr->downShift -= 2;
1063 tablePtr->mask = (tablePtr->mask << 2) + 3;
1066 * Rehash all of the existing entries into the new bucket array.
1069 for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
1070 for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
1071 *oldChainPtr = hPtr->nextPtr;
1072 #if TCL_HASH_KEY_STORE_HASH
1073 if (typePtr->hashKeyProc == NULL
1074 || typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
1075 index = RANDOM_INDEX(tablePtr, PTR2INT(hPtr->hash));
1077 index = PTR2UINT(hPtr->hash) & tablePtr->mask;
1079 hPtr->nextPtr = tablePtr->buckets[index];
1080 tablePtr->buckets[index] = hPtr;
1082 void *key = Tcl_GetHashKey(tablePtr, hPtr);
1084 if (typePtr->hashKeyProc) {
1087 hash = typePtr->hashKeyProc(tablePtr, key);
1088 if (typePtr->flags & TCL_HASH_KEY_RANDOMIZE_HASH) {
1089 index = RANDOM_INDEX(tablePtr, hash);
1091 index = hash & tablePtr->mask;
1094 index = RANDOM_INDEX(tablePtr, key);
1097 hPtr->bucketPtr = &tablePtr->buckets[index];
1098 hPtr->nextPtr = *hPtr->bucketPtr;
1099 *hPtr->bucketPtr = hPtr;
1105 * Free up the old bucket array, if it was dynamically allocated.
1108 if (oldBuckets != tablePtr->staticBuckets) {
1109 if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) {
1110 TclpSysFree((char *) oldBuckets);