]> cvs.zerfleddert.de Git - micropolis/blob - src/tcl/tclhash.c
Fixes for compilation with gcc 15
[micropolis] / src / tcl / tclhash.c
1 /*
2 * tclHash.c --
3 *
4 * Implementation of in-memory hash tables for Tcl and Tcl-based
5 * applications.
6 *
7 * Copyright 1991 Regents of the University of California
8 * Permission to use, copy, modify, and distribute this
9 * software and its documentation for any purpose and without
10 * fee is hereby granted, provided that this copyright
11 * notice appears in all copies. The University of California
12 * makes no representations about the suitability of this
13 * software for any purpose. It is provided "as is" without
14 * express or implied warranty.
15 */
16
17 #ifndef lint
18 static char rcsid[] = "$Header: /user6/ouster/tcl/RCS/tclHash.c,v 1.9 92/01/04 15:45:21 ouster Exp $ SPRITE (Berkeley)";
19 #endif /* not lint */
20
21 #include "tclint.h"
22
23 /*
24 * When there are this many entries per bucket, on average, rebuild
25 * the hash table to make it larger.
26 */
27
28 #define REBUILD_MULTIPLIER 3
29
30
31 /*
32 * The following macro takes a preliminary integer hash value and
33 * produces an index into a hash tables bucket list. The idea is
34 * to make it so that preliminary values that are arbitrarily similar
35 * will end up in different buckets. The hash function was taken
36 * from a random-number generator.
37 */
38
39 #define RANDOM_INDEX(tablePtr, i) \
40 (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)
41
42 /*
43 * Procedure prototypes for static procedures in this file:
44 */
45
46 static Tcl_HashEntry * ArrayFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
47 char *key));
48 static Tcl_HashEntry * ArrayCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
49 char *key, int *newPtr));
50 static Tcl_HashEntry * BogusFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
51 char *key));
52 static Tcl_HashEntry * BogusCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
53 char *key, int *newPtr));
54 static int HashString _ANSI_ARGS_((char *string));
55 static void RebuildTable _ANSI_ARGS_((Tcl_HashTable *tablePtr));
56 static Tcl_HashEntry * StringFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
57 char *key));
58 static Tcl_HashEntry * StringCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
59 char *key, int *newPtr));
60 static Tcl_HashEntry * OneWordFind _ANSI_ARGS_((Tcl_HashTable *tablePtr,
61 char *key));
62 static Tcl_HashEntry * OneWordCreate _ANSI_ARGS_((Tcl_HashTable *tablePtr,
63 char *key, int *newPtr));
64 \f
65 /*
66 *----------------------------------------------------------------------
67 *
68 * Tcl_InitHashTable --
69 *
70 * Given storage for a hash table, set up the fields to prepare
71 * the hash table for use.
72 *
73 * Results:
74 * None.
75 *
76 * Side effects:
77 * TablePtr is now ready to be passed to Tcl_FindHashEntry and
78 * Tcl_CreateHashEntry.
79 *
80 *----------------------------------------------------------------------
81 */
82
83 void
84 Tcl_InitHashTable (
85 register Tcl_HashTable *tablePtr, /* Pointer to table record, which
86 * is supplied by the caller. */
87 int keyType /* Type of keys to use in table:
88 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
89 * or an integer >= 2. */
90 )
91 {
92 tablePtr->buckets = tablePtr->staticBuckets;
93 tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
94 tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
95 tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
96 tablePtr->numEntries = 0;
97 tablePtr->rebuildSize = TCL_SMALL_HASH_TABLE*REBUILD_MULTIPLIER;
98 tablePtr->downShift = 28;
99 tablePtr->mask = 3;
100 tablePtr->keyType = keyType;
101 if (keyType == TCL_STRING_KEYS) {
102 tablePtr->findProc = StringFind;
103 tablePtr->createProc = StringCreate;
104 } else if (keyType == TCL_ONE_WORD_KEYS) {
105 tablePtr->findProc = OneWordFind;
106 tablePtr->createProc = OneWordCreate;
107 } else {
108 tablePtr->findProc = ArrayFind;
109 tablePtr->createProc = ArrayCreate;
110 };
111 }
112 \f
113 /*
114 *----------------------------------------------------------------------
115 *
116 * Tcl_DeleteHashEntry --
117 *
118 * Remove a single entry from a hash table.
119 *
120 * Results:
121 * None.
122 *
123 * Side effects:
124 * The entry given by entryPtr is deleted from its table and
125 * should never again be used by the caller. It is up to the
126 * caller to free the clientData field of the entry, if that
127 * is relevant.
128 *
129 *----------------------------------------------------------------------
130 */
131
132 void
133 Tcl_DeleteHashEntry (Tcl_HashEntry *entryPtr)
134 {
135 register Tcl_HashEntry *prevPtr;
136
137 if (*entryPtr->bucketPtr == entryPtr) {
138 *entryPtr->bucketPtr = entryPtr->nextPtr;
139 } else {
140 for (prevPtr = *entryPtr->bucketPtr; ; prevPtr = prevPtr->nextPtr) {
141 if (prevPtr == NULL) {
142 panic("malformed bucket chain in Tcl_DeleteHashEntry");
143 }
144 if (prevPtr->nextPtr == entryPtr) {
145 prevPtr->nextPtr = entryPtr->nextPtr;
146 break;
147 }
148 }
149 }
150 entryPtr->tablePtr->numEntries--;
151 ckfree((char *) entryPtr);
152 }
153 \f
154 /*
155 *----------------------------------------------------------------------
156 *
157 * Tcl_DeleteHashTable --
158 *
159 * Free up everything associated with a hash table except for
160 * the record for the table itself.
161 *
162 * Results:
163 * None.
164 *
165 * Side effects:
166 * The hash table is no longer useable.
167 *
168 *----------------------------------------------------------------------
169 */
170
171 void
172 Tcl_DeleteHashTable (
173 register Tcl_HashTable *tablePtr /* Table to delete. */
174 )
175 {
176 register Tcl_HashEntry *hPtr, *nextPtr;
177 int i;
178
179 /*
180 * Free up all the entries in the table.
181 */
182
183 for (i = 0; i < tablePtr->numBuckets; i++) {
184 hPtr = tablePtr->buckets[i];
185 while (hPtr != NULL) {
186 nextPtr = hPtr->nextPtr;
187 ckfree((char *) hPtr);
188 hPtr = nextPtr;
189 }
190 }
191
192 /*
193 * Free up the bucket array, if it was dynamically allocated.
194 */
195
196 if (tablePtr->buckets != tablePtr->staticBuckets) {
197 ckfree((char *) tablePtr->buckets);
198 }
199
200 /*
201 * Arrange for panics if the table is used again without
202 * re-initialization.
203 */
204
205 tablePtr->findProc = BogusFind;
206 tablePtr->createProc = BogusCreate;
207 }
208 \f
209 /*
210 *----------------------------------------------------------------------
211 *
212 * Tcl_FirstHashEntry --
213 *
214 * Locate the first entry in a hash table and set up a record
215 * that can be used to step through all the remaining entries
216 * of the table.
217 *
218 * Results:
219 * The return value is a pointer to the first entry in tablePtr,
220 * or NULL if tablePtr has no entries in it. The memory at
221 * *searchPtr is initialized so that subsequent calls to
222 * Tcl_NextHashEntry will return all of the entries in the table,
223 * one at a time.
224 *
225 * Side effects:
226 * None.
227 *
228 *----------------------------------------------------------------------
229 */
230
231 Tcl_HashEntry *
232 Tcl_FirstHashEntry (
233 Tcl_HashTable *tablePtr, /* Table to search. */
234 Tcl_HashSearch *searchPtr /* Place to store information about
235 * progress through the table. */
236 )
237 {
238 searchPtr->tablePtr = tablePtr;
239 searchPtr->nextIndex = 0;
240 searchPtr->nextEntryPtr = NULL;
241 return Tcl_NextHashEntry(searchPtr);
242 }
243 \f
244 /*
245 *----------------------------------------------------------------------
246 *
247 * Tcl_NextHashEntry --
248 *
249 * Once a hash table enumeration has been initiated by calling
250 * Tcl_FirstHashEntry, this procedure may be called to return
251 * successive elements of the table.
252 *
253 * Results:
254 * The return value is the next entry in the hash table being
255 * enumerated, or NULL if the end of the table is reached.
256 *
257 * Side effects:
258 * None.
259 *
260 *----------------------------------------------------------------------
261 */
262
263 Tcl_HashEntry *
264 Tcl_NextHashEntry (
265 register Tcl_HashSearch *searchPtr /* Place to store information about
266 * progress through the table. Must
267 * have been initialized by calling
268 * Tcl_FirstHashEntry. */
269 )
270 {
271 Tcl_HashEntry *hPtr;
272
273 while (searchPtr->nextEntryPtr == NULL) {
274 if (searchPtr->nextIndex >= searchPtr->tablePtr->numBuckets) {
275 return NULL;
276 }
277 searchPtr->nextEntryPtr =
278 searchPtr->tablePtr->buckets[searchPtr->nextIndex];
279 searchPtr->nextIndex++;
280 }
281 hPtr = searchPtr->nextEntryPtr;
282 searchPtr->nextEntryPtr = hPtr->nextPtr;
283 return hPtr;
284 }
285 \f
286 /*
287 *----------------------------------------------------------------------
288 *
289 * Tcl_HashStats --
290 *
291 * Return statistics describing the layout of the hash table
292 * in its hash buckets.
293 *
294 * Results:
295 * The return value is a malloc-ed string containing information
296 * about tablePtr. It is the caller's responsibility to free
297 * this string.
298 *
299 * Side effects:
300 * None.
301 *
302 *----------------------------------------------------------------------
303 */
304
305 char *
306 Tcl_HashStats (
307 Tcl_HashTable *tablePtr /* Table for which to produce stats. */
308 )
309 {
310 #define NUM_COUNTERS 10
311 int count[NUM_COUNTERS], overflow, i, j;
312 double average, tmp;
313 register Tcl_HashEntry *hPtr;
314 char *result, *p;
315
316 /*
317 * Compute a histogram of bucket usage.
318 */
319
320 for (i = 0; i < NUM_COUNTERS; i++) {
321 count[i] = 0;
322 }
323 overflow = 0;
324 average = 0.0;
325 for (i = 0; i < tablePtr->numBuckets; i++) {
326 j = 0;
327 for (hPtr = tablePtr->buckets[i]; hPtr != NULL; hPtr = hPtr->nextPtr) {
328 j++;
329 }
330 if (j < NUM_COUNTERS) {
331 count[j]++;
332 } else {
333 overflow++;
334 }
335 tmp = j;
336 average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
337 }
338
339 /*
340 * Print out the histogram and a few other pieces of information.
341 */
342
343 result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300));
344 sprintf(result, "%d entries in table, %d buckets\n",
345 tablePtr->numEntries, tablePtr->numBuckets);
346 p = result + strlen(result);
347 for (i = 0; i < NUM_COUNTERS; i++) {
348 sprintf(p, "number of buckets with %d entries: %d\n",
349 i, count[i]);
350 p += strlen(p);
351 }
352 sprintf(p, "number of buckets with more %d or more entries: %d\n",
353 NUM_COUNTERS, overflow);
354 p += strlen(p);
355 sprintf(p, "average search distance for entry: %.1f", average);
356 return result;
357 }
358 \f
359 /*
360 *----------------------------------------------------------------------
361 *
362 * HashString --
363 *
364 * Compute a one-word summary of a text string, which can be
365 * used to generate a hash index.
366 *
367 * Results:
368 * The return value is a one-word summary of the information in
369 * string.
370 *
371 * Side effects:
372 * None.
373 *
374 *----------------------------------------------------------------------
375 */
376
377 static int
378 HashString (
379 register char *string /* String from which to compute hash value. */
380 )
381 {
382 register int result, c;
383
384 /*
385 * I tried a zillion different hash functions and asked many other
386 * people for advice. Many people had their own favorite functions,
387 * all different, but no-one had much idea why they were good ones.
388 * I chose the one below (multiply by 9 and add new character)
389 * because of the following reasons:
390 *
391 * 1. Multiplying by 10 is perfect for keys that are decimal strings,
392 * and multiplying by 9 is just about as good.
393 * 2. Times-9 is (shift-left-3) plus (old). This means that each
394 * character's bits hang around in the low-order bits of the
395 * hash value for ever, plus they spread fairly rapidly up to
396 * the high-order bits to fill out the hash value. This seems
397 * works well both for decimal and non-decimal strings.
398 */
399
400 result = 0;
401 while (1) {
402 c = *string;
403 string++;
404 if (c == 0) {
405 break;
406 }
407 result += (result<<3) + c;
408 }
409 return result;
410 }
411 \f
412 /*
413 *----------------------------------------------------------------------
414 *
415 * StringFind --
416 *
417 * Given a hash table with string keys, and a string key, find
418 * the entry with a matching key.
419 *
420 * Results:
421 * The return value is a token for the matching entry in the
422 * hash table, or NULL if there was no matching entry.
423 *
424 * Side effects:
425 * None.
426 *
427 *----------------------------------------------------------------------
428 */
429
430 static Tcl_HashEntry *
431 StringFind (
432 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
433 char *key /* Key to use to find matching entry. */
434 )
435 {
436 register Tcl_HashEntry *hPtr;
437 register char *p1, *p2;
438 int index;
439
440 index = HashString(key) & tablePtr->mask;
441
442 /*
443 * Search all of the entries in the appropriate bucket.
444 */
445
446 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
447 hPtr = hPtr->nextPtr) {
448 for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
449 if (*p1 != *p2) {
450 break;
451 }
452 if (*p1 == '\0') {
453 return hPtr;
454 }
455 }
456 }
457 return NULL;
458 }
459 \f
460 /*
461 *----------------------------------------------------------------------
462 *
463 * StringCreate --
464 *
465 * Given a hash table with string keys, and a string key, find
466 * the entry with a matching key. If there is no matching entry,
467 * then create a new entry that does match.
468 *
469 * Results:
470 * The return value is a pointer to the matching entry. If this
471 * is a newly-created entry, then *newPtr will be set to a non-zero
472 * value; otherwise *newPtr will be set to 0. If this is a new
473 * entry the value stored in the entry will initially be 0.
474 *
475 * Side effects:
476 * A new entry may be added to the hash table.
477 *
478 *----------------------------------------------------------------------
479 */
480
481 static Tcl_HashEntry *
482 StringCreate (
483 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
484 char *key, /* Key to use to find or create matching
485 * entry. */
486 int *newPtr /* Store info here telling whether a new
487 * entry was created. */
488 )
489 {
490 register Tcl_HashEntry *hPtr;
491 register char *p1, *p2;
492 int index;
493
494 index = HashString(key) & tablePtr->mask;
495
496 /*
497 * Search all of the entries in this bucket.
498 */
499
500 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
501 hPtr = hPtr->nextPtr) {
502 for (p1 = key, p2 = hPtr->key.string; ; p1++, p2++) {
503 if (*p1 != *p2) {
504 break;
505 }
506 if (*p1 == '\0') {
507 *newPtr = 0;
508 return hPtr;
509 }
510 }
511 }
512
513 /*
514 * Entry not found. Add a new one to the bucket.
515 */
516
517 *newPtr = 1;
518 hPtr = (Tcl_HashEntry *) ckalloc((unsigned)
519 (sizeof(Tcl_HashEntry) + strlen(key) - (sizeof(hPtr->key) -1)));
520 hPtr->tablePtr = tablePtr;
521 hPtr->bucketPtr = &(tablePtr->buckets[index]);
522 hPtr->nextPtr = *hPtr->bucketPtr;
523 hPtr->clientData = 0;
524 strcpy(hPtr->key.string, key);
525 *hPtr->bucketPtr = hPtr;
526 tablePtr->numEntries++;
527
528 /*
529 * If the table has exceeded a decent size, rebuild it with many
530 * more buckets.
531 */
532
533 if (tablePtr->numEntries >= tablePtr->rebuildSize) {
534 RebuildTable(tablePtr);
535 }
536 return hPtr;
537 }
538 \f
539 /*
540 *----------------------------------------------------------------------
541 *
542 * OneWordFind --
543 *
544 * Given a hash table with one-word keys, and a one-word key, find
545 * the entry with a matching key.
546 *
547 * Results:
548 * The return value is a token for the matching entry in the
549 * hash table, or NULL if there was no matching entry.
550 *
551 * Side effects:
552 * None.
553 *
554 *----------------------------------------------------------------------
555 */
556
557 static Tcl_HashEntry *
558 OneWordFind (
559 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
560 register char *key /* Key to use to find matching entry. */
561 )
562 {
563 register Tcl_HashEntry *hPtr;
564 int index;
565
566 index = RANDOM_INDEX(tablePtr, key);
567
568 /*
569 * Search all of the entries in the appropriate bucket.
570 */
571
572 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
573 hPtr = hPtr->nextPtr) {
574 if (hPtr->key.oneWordValue == key) {
575 return hPtr;
576 }
577 }
578 return NULL;
579 }
580 \f
581 /*
582 *----------------------------------------------------------------------
583 *
584 * OneWordCreate --
585 *
586 * Given a hash table with one-word keys, and a one-word key, find
587 * the entry with a matching key. If there is no matching entry,
588 * then create a new entry that does match.
589 *
590 * Results:
591 * The return value is a pointer to the matching entry. If this
592 * is a newly-created entry, then *newPtr will be set to a non-zero
593 * value; otherwise *newPtr will be set to 0. If this is a new
594 * entry the value stored in the entry will initially be 0.
595 *
596 * Side effects:
597 * A new entry may be added to the hash table.
598 *
599 *----------------------------------------------------------------------
600 */
601
602 static Tcl_HashEntry *
603 OneWordCreate (
604 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
605 register char *key, /* Key to use to find or create matching
606 * entry. */
607 int *newPtr /* Store info here telling whether a new
608 * entry was created. */
609 )
610 {
611 register Tcl_HashEntry *hPtr;
612 int index;
613
614 index = RANDOM_INDEX(tablePtr, key);
615
616 /*
617 * Search all of the entries in this bucket.
618 */
619
620 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
621 hPtr = hPtr->nextPtr) {
622 if (hPtr->key.oneWordValue == key) {
623 *newPtr = 0;
624 return hPtr;
625 }
626 }
627
628 /*
629 * Entry not found. Add a new one to the bucket.
630 */
631
632 *newPtr = 1;
633 hPtr = (Tcl_HashEntry *) ckalloc(sizeof(Tcl_HashEntry));
634 hPtr->tablePtr = tablePtr;
635 hPtr->bucketPtr = &(tablePtr->buckets[index]);
636 hPtr->nextPtr = *hPtr->bucketPtr;
637 hPtr->clientData = 0;
638 hPtr->key.oneWordValue = key;
639 *hPtr->bucketPtr = hPtr;
640 tablePtr->numEntries++;
641
642 /*
643 * If the table has exceeded a decent size, rebuild it with many
644 * more buckets.
645 */
646
647 if (tablePtr->numEntries >= tablePtr->rebuildSize) {
648 RebuildTable(tablePtr);
649 }
650 return hPtr;
651 }
652 \f
653 /*
654 *----------------------------------------------------------------------
655 *
656 * ArrayFind --
657 *
658 * Given a hash table with array-of-int keys, and a key, find
659 * the entry with a matching key.
660 *
661 * Results:
662 * The return value is a token for the matching entry in the
663 * hash table, or NULL if there was no matching entry.
664 *
665 * Side effects:
666 * None.
667 *
668 *----------------------------------------------------------------------
669 */
670
671 static Tcl_HashEntry *
672 ArrayFind (
673 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
674 char *key /* Key to use to find matching entry. */
675 )
676 {
677 register Tcl_HashEntry *hPtr;
678 int *arrayPtr = (int *) key;
679 register int *iPtr1, *iPtr2;
680 int index, count;
681
682 for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr;
683 count > 0; count--, iPtr1++) {
684 index += *iPtr1;
685 }
686 index = RANDOM_INDEX(tablePtr, index);
687
688 /*
689 * Search all of the entries in the appropriate bucket.
690 */
691
692 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
693 hPtr = hPtr->nextPtr) {
694 for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words,
695 count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
696 if (count == 0) {
697 return hPtr;
698 }
699 if (*iPtr1 != *iPtr2) {
700 break;
701 }
702 }
703 }
704 return NULL;
705 }
706 \f
707 /*
708 *----------------------------------------------------------------------
709 *
710 * ArrayCreate --
711 *
712 * Given a hash table with one-word keys, and a one-word key, find
713 * the entry with a matching key. If there is no matching entry,
714 * then create a new entry that does match.
715 *
716 * Results:
717 * The return value is a pointer to the matching entry. If this
718 * is a newly-created entry, then *newPtr will be set to a non-zero
719 * value; otherwise *newPtr will be set to 0. If this is a new
720 * entry the value stored in the entry will initially be 0.
721 *
722 * Side effects:
723 * A new entry may be added to the hash table.
724 *
725 *----------------------------------------------------------------------
726 */
727
728 static Tcl_HashEntry *
729 ArrayCreate (
730 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
731 register char *key, /* Key to use to find or create matching
732 * entry. */
733 int *newPtr /* Store info here telling whether a new
734 * entry was created. */
735 )
736 {
737 register Tcl_HashEntry *hPtr;
738 int *arrayPtr = (int *) key;
739 register int *iPtr1, *iPtr2;
740 int index, count;
741
742 for (index = 0, count = tablePtr->keyType, iPtr1 = arrayPtr;
743 count > 0; count--, iPtr1++) {
744 index += *iPtr1;
745 }
746 index = RANDOM_INDEX(tablePtr, index);
747
748 /*
749 * Search all of the entries in the appropriate bucket.
750 */
751
752 for (hPtr = tablePtr->buckets[index]; hPtr != NULL;
753 hPtr = hPtr->nextPtr) {
754 for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words,
755 count = tablePtr->keyType; ; count--, iPtr1++, iPtr2++) {
756 if (count == 0) {
757 *newPtr = 0;
758 return hPtr;
759 }
760 if (*iPtr1 != *iPtr2) {
761 break;
762 }
763 }
764 }
765
766 /*
767 * Entry not found. Add a new one to the bucket.
768 */
769
770 *newPtr = 1;
771 hPtr = (Tcl_HashEntry *) ckalloc((unsigned) (sizeof(Tcl_HashEntry)
772 + (tablePtr->keyType*sizeof(int)) - 4));
773 hPtr->tablePtr = tablePtr;
774 hPtr->bucketPtr = &(tablePtr->buckets[index]);
775 hPtr->nextPtr = *hPtr->bucketPtr;
776 hPtr->clientData = 0;
777 for (iPtr1 = arrayPtr, iPtr2 = hPtr->key.words, count = tablePtr->keyType;
778 count > 0; count--, iPtr1++, iPtr2++) {
779 *iPtr2 = *iPtr1;
780 }
781 *hPtr->bucketPtr = hPtr;
782 tablePtr->numEntries++;
783
784 /*
785 * If the table has exceeded a decent size, rebuild it with many
786 * more buckets.
787 */
788
789 if (tablePtr->numEntries >= tablePtr->rebuildSize) {
790 RebuildTable(tablePtr);
791 }
792 return hPtr;
793 }
794 \f
795 /*
796 *----------------------------------------------------------------------
797 *
798 * BogusFind --
799 *
800 * This procedure is invoked when an Tcl_FindHashEntry is called
801 * on a table that has been deleted.
802 *
803 * Results:
804 * If panic returns (which it shouldn't) this procedure returns
805 * NULL.
806 *
807 * Side effects:
808 * Generates a panic.
809 *
810 *----------------------------------------------------------------------
811 */
812
813 /* ARGSUSED */
814 static Tcl_HashEntry *
815 BogusFind (
816 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
817 char *key /* Key to use to find matching entry. */
818 )
819 {
820 panic("called Tcl_FindHashEntry on deleted table");
821 return NULL;
822 }
823 \f
824 /*
825 *----------------------------------------------------------------------
826 *
827 * BogusCreate --
828 *
829 * This procedure is invoked when an Tcl_CreateHashEntry is called
830 * on a table that has been deleted.
831 *
832 * Results:
833 * If panic returns (which it shouldn't) this procedure returns
834 * NULL.
835 *
836 * Side effects:
837 * Generates a panic.
838 *
839 *----------------------------------------------------------------------
840 */
841
842 /* ARGSUSED */
843 static Tcl_HashEntry *
844 BogusCreate (
845 Tcl_HashTable *tablePtr, /* Table in which to lookup entry. */
846 char *key, /* Key to use to find or create matching
847 * entry. */
848 int *newPtr /* Store info here telling whether a new
849 * entry was created. */
850 )
851 {
852 panic("called Tcl_CreateHashEntry on deleted table");
853 return NULL;
854 }
855 \f
856 /*
857 *----------------------------------------------------------------------
858 *
859 * RebuildTable --
860 *
861 * This procedure is invoked when the ratio of entries to hash
862 * buckets becomes too large. It creates a new table with a
863 * larger bucket array and moves all of the entries into the
864 * new table.
865 *
866 * Results:
867 * None.
868 *
869 * Side effects:
870 * Memory gets reallocated and entries get re-hashed to new
871 * buckets.
872 *
873 *----------------------------------------------------------------------
874 */
875
876 static void
877 RebuildTable (
878 register Tcl_HashTable *tablePtr /* Table to enlarge. */
879 )
880 {
881 int oldSize, count, index;
882 Tcl_HashEntry **oldBuckets;
883 register Tcl_HashEntry **oldChainPtr, **newChainPtr;
884 register Tcl_HashEntry *hPtr;
885
886 oldSize = tablePtr->numBuckets;
887 oldBuckets = tablePtr->buckets;
888
889 /*
890 * Allocate and initialize the new bucket array, and set up
891 * hashing constants for new array size.
892 */
893
894 tablePtr->numBuckets *= 4;
895 tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned)
896 (tablePtr->numBuckets * sizeof(Tcl_HashEntry *)));
897 for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
898 count > 0; count--, newChainPtr++) {
899 *newChainPtr = NULL;
900 }
901 tablePtr->rebuildSize *= 4;
902 tablePtr->downShift -= 2;
903 tablePtr->mask = (tablePtr->mask << 2) + 3;
904
905 /*
906 * Rehash all of the existing entries into the new bucket array.
907 */
908
909 for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
910 for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
911 *oldChainPtr = hPtr->nextPtr;
912 if (tablePtr->keyType == TCL_STRING_KEYS) {
913 index = HashString(hPtr->key.string) & tablePtr->mask;
914 } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
915 index = RANDOM_INDEX(tablePtr, hPtr->key.oneWordValue);
916 } else {
917 register int *iPtr;
918 int count;
919
920 for (index = 0, count = tablePtr->keyType,
921 iPtr = hPtr->key.words; count > 0; count--, iPtr++) {
922 index += *iPtr;
923 }
924 index = RANDOM_INDEX(tablePtr, index);
925 }
926 hPtr->bucketPtr = &(tablePtr->buckets[index]);
927 hPtr->nextPtr = *hPtr->bucketPtr;
928 *hPtr->bucketPtr = hPtr;
929 }
930 }
931
932 /*
933 * Free up the old bucket array, if it was dynamically allocated.
934 */
935
936 if (oldBuckets != tablePtr->staticBuckets) {
937 ckfree((char *) oldBuckets);
938 }
939 }
Impressum, Datenschutz