]>
cvs.zerfleddert.de Git - micropolis/blob - src/tcl/tclhash.c
4 * Implementation of in-memory hash tables for Tcl and Tcl-based
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.
18 static char rcsid
[] = "$Header: /user6/ouster/tcl/RCS/tclHash.c,v 1.9 92/01/04 15:45:21 ouster Exp $ SPRITE (Berkeley)";
24 * Imported library procedures for which there are no header files:
30 * When there are this many entries per bucket, on average, rebuild
31 * the hash table to make it larger.
34 #define REBUILD_MULTIPLIER 3
38 * The following macro takes a preliminary integer hash value and
39 * produces an index into a hash tables bucket list. The idea is
40 * to make it so that preliminary values that are arbitrarily similar
41 * will end up in different buckets. The hash function was taken
42 * from a random-number generator.
45 #define RANDOM_INDEX(tablePtr, i) \
46 (((((long) (i))*1103515245) >> (tablePtr)->downShift) & (tablePtr)->mask)
49 * Procedure prototypes for static procedures in this file:
52 static Tcl_HashEntry
* ArrayFind
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
54 static Tcl_HashEntry
* ArrayCreate
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
55 char *key
, int *newPtr
));
56 static Tcl_HashEntry
* BogusFind
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
58 static Tcl_HashEntry
* BogusCreate
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
59 char *key
, int *newPtr
));
60 static int HashString
_ANSI_ARGS_((char *string
));
61 static void RebuildTable
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
));
62 static Tcl_HashEntry
* StringFind
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
64 static Tcl_HashEntry
* StringCreate
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
65 char *key
, int *newPtr
));
66 static Tcl_HashEntry
* OneWordFind
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
68 static Tcl_HashEntry
* OneWordCreate
_ANSI_ARGS_((Tcl_HashTable
*tablePtr
,
69 char *key
, int *newPtr
));
72 *----------------------------------------------------------------------
74 * Tcl_InitHashTable --
76 * Given storage for a hash table, set up the fields to prepare
77 * the hash table for use.
83 * TablePtr is now ready to be passed to Tcl_FindHashEntry and
84 * Tcl_CreateHashEntry.
86 *----------------------------------------------------------------------
90 Tcl_InitHashTable(tablePtr
, keyType
)
91 register Tcl_HashTable
*tablePtr
; /* Pointer to table record, which
92 * is supplied by the caller. */
93 int keyType
; /* Type of keys to use in table:
94 * TCL_STRING_KEYS, TCL_ONE_WORD_KEYS,
95 * or an integer >= 2. */
97 tablePtr
->buckets
= tablePtr
->staticBuckets
;
98 tablePtr
->staticBuckets
[0] = tablePtr
->staticBuckets
[1] = 0;
99 tablePtr
->staticBuckets
[2] = tablePtr
->staticBuckets
[3] = 0;
100 tablePtr
->numBuckets
= TCL_SMALL_HASH_TABLE
;
101 tablePtr
->numEntries
= 0;
102 tablePtr
->rebuildSize
= TCL_SMALL_HASH_TABLE
*REBUILD_MULTIPLIER
;
103 tablePtr
->downShift
= 28;
105 tablePtr
->keyType
= keyType
;
106 if (keyType
== TCL_STRING_KEYS
) {
107 tablePtr
->findProc
= StringFind
;
108 tablePtr
->createProc
= StringCreate
;
109 } else if (keyType
== TCL_ONE_WORD_KEYS
) {
110 tablePtr
->findProc
= OneWordFind
;
111 tablePtr
->createProc
= OneWordCreate
;
113 tablePtr
->findProc
= ArrayFind
;
114 tablePtr
->createProc
= ArrayCreate
;
119 *----------------------------------------------------------------------
121 * Tcl_DeleteHashEntry --
123 * Remove a single entry from a hash table.
129 * The entry given by entryPtr is deleted from its table and
130 * should never again be used by the caller. It is up to the
131 * caller to free the clientData field of the entry, if that
134 *----------------------------------------------------------------------
138 Tcl_DeleteHashEntry(entryPtr
)
139 Tcl_HashEntry
*entryPtr
;
141 register Tcl_HashEntry
*prevPtr
;
143 if (*entryPtr
->bucketPtr
== entryPtr
) {
144 *entryPtr
->bucketPtr
= entryPtr
->nextPtr
;
146 for (prevPtr
= *entryPtr
->bucketPtr
; ; prevPtr
= prevPtr
->nextPtr
) {
147 if (prevPtr
== NULL
) {
148 panic("malformed bucket chain in Tcl_DeleteHashEntry");
150 if (prevPtr
->nextPtr
== entryPtr
) {
151 prevPtr
->nextPtr
= entryPtr
->nextPtr
;
156 entryPtr
->tablePtr
->numEntries
--;
157 ckfree((char *) entryPtr
);
161 *----------------------------------------------------------------------
163 * Tcl_DeleteHashTable --
165 * Free up everything associated with a hash table except for
166 * the record for the table itself.
172 * The hash table is no longer useable.
174 *----------------------------------------------------------------------
178 Tcl_DeleteHashTable(tablePtr
)
179 register Tcl_HashTable
*tablePtr
; /* Table to delete. */
181 register Tcl_HashEntry
*hPtr
, *nextPtr
;
185 * Free up all the entries in the table.
188 for (i
= 0; i
< tablePtr
->numBuckets
; i
++) {
189 hPtr
= tablePtr
->buckets
[i
];
190 while (hPtr
!= NULL
) {
191 nextPtr
= hPtr
->nextPtr
;
192 ckfree((char *) hPtr
);
198 * Free up the bucket array, if it was dynamically allocated.
201 if (tablePtr
->buckets
!= tablePtr
->staticBuckets
) {
202 ckfree((char *) tablePtr
->buckets
);
206 * Arrange for panics if the table is used again without
210 tablePtr
->findProc
= BogusFind
;
211 tablePtr
->createProc
= BogusCreate
;
215 *----------------------------------------------------------------------
217 * Tcl_FirstHashEntry --
219 * Locate the first entry in a hash table and set up a record
220 * that can be used to step through all the remaining entries
224 * The return value is a pointer to the first entry in tablePtr,
225 * or NULL if tablePtr has no entries in it. The memory at
226 * *searchPtr is initialized so that subsequent calls to
227 * Tcl_NextHashEntry will return all of the entries in the table,
233 *----------------------------------------------------------------------
237 Tcl_FirstHashEntry(tablePtr
, searchPtr
)
238 Tcl_HashTable
*tablePtr
; /* Table to search. */
239 Tcl_HashSearch
*searchPtr
; /* Place to store information about
240 * progress through the table. */
242 searchPtr
->tablePtr
= tablePtr
;
243 searchPtr
->nextIndex
= 0;
244 searchPtr
->nextEntryPtr
= NULL
;
245 return Tcl_NextHashEntry(searchPtr
);
249 *----------------------------------------------------------------------
251 * Tcl_NextHashEntry --
253 * Once a hash table enumeration has been initiated by calling
254 * Tcl_FirstHashEntry, this procedure may be called to return
255 * successive elements of the table.
258 * The return value is the next entry in the hash table being
259 * enumerated, or NULL if the end of the table is reached.
264 *----------------------------------------------------------------------
268 Tcl_NextHashEntry(searchPtr
)
269 register Tcl_HashSearch
*searchPtr
; /* Place to store information about
270 * progress through the table. Must
271 * have been initialized by calling
272 * Tcl_FirstHashEntry. */
276 while (searchPtr
->nextEntryPtr
== NULL
) {
277 if (searchPtr
->nextIndex
>= searchPtr
->tablePtr
->numBuckets
) {
280 searchPtr
->nextEntryPtr
=
281 searchPtr
->tablePtr
->buckets
[searchPtr
->nextIndex
];
282 searchPtr
->nextIndex
++;
284 hPtr
= searchPtr
->nextEntryPtr
;
285 searchPtr
->nextEntryPtr
= hPtr
->nextPtr
;
290 *----------------------------------------------------------------------
294 * Return statistics describing the layout of the hash table
295 * in its hash buckets.
298 * The return value is a malloc-ed string containing information
299 * about tablePtr. It is the caller's responsibility to free
305 *----------------------------------------------------------------------
309 Tcl_HashStats(tablePtr
)
310 Tcl_HashTable
*tablePtr
; /* Table for which to produce stats. */
312 #define NUM_COUNTERS 10
313 int count
[NUM_COUNTERS
], overflow
, i
, j
;
315 register Tcl_HashEntry
*hPtr
;
319 * Compute a histogram of bucket usage.
322 for (i
= 0; i
< NUM_COUNTERS
; i
++) {
327 for (i
= 0; i
< tablePtr
->numBuckets
; i
++) {
329 for (hPtr
= tablePtr
->buckets
[i
]; hPtr
!= NULL
; hPtr
= hPtr
->nextPtr
) {
332 if (j
< NUM_COUNTERS
) {
338 average
+= (tmp
+1.0)*(tmp
/tablePtr
->numEntries
)/2.0;
342 * Print out the histogram and a few other pieces of information.
345 result
= (char *) ckalloc((unsigned) ((NUM_COUNTERS
*60) + 300));
346 sprintf(result
, "%d entries in table, %d buckets\n",
347 tablePtr
->numEntries
, tablePtr
->numBuckets
);
348 p
= result
+ strlen(result
);
349 for (i
= 0; i
< NUM_COUNTERS
; i
++) {
350 sprintf(p
, "number of buckets with %d entries: %d\n",
354 sprintf(p
, "number of buckets with more %d or more entries: %d\n",
355 NUM_COUNTERS
, overflow
);
357 sprintf(p
, "average search distance for entry: %.1f", average
);
362 *----------------------------------------------------------------------
366 * Compute a one-word summary of a text string, which can be
367 * used to generate a hash index.
370 * The return value is a one-word summary of the information in
376 *----------------------------------------------------------------------
381 register char *string
; /* String from which to compute hash value. */
383 register int result
, c
;
386 * I tried a zillion different hash functions and asked many other
387 * people for advice. Many people had their own favorite functions,
388 * all different, but no-one had much idea why they were good ones.
389 * I chose the one below (multiply by 9 and add new character)
390 * because of the following reasons:
392 * 1. Multiplying by 10 is perfect for keys that are decimal strings,
393 * and multiplying by 9 is just about as good.
394 * 2. Times-9 is (shift-left-3) plus (old). This means that each
395 * character's bits hang around in the low-order bits of the
396 * hash value for ever, plus they spread fairly rapidly up to
397 * the high-order bits to fill out the hash value. This seems
398 * works well both for decimal and non-decimal strings.
408 result
+= (result
<<3) + c
;
414 *----------------------------------------------------------------------
418 * Given a hash table with string keys, and a string key, find
419 * the entry with a matching key.
422 * The return value is a token for the matching entry in the
423 * hash table, or NULL if there was no matching entry.
428 *----------------------------------------------------------------------
431 static Tcl_HashEntry
*
432 StringFind(tablePtr
, key
)
433 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
434 char *key
; /* Key to use to find matching entry. */
436 register Tcl_HashEntry
*hPtr
;
437 register char *p1
, *p2
;
440 index
= HashString(key
) & tablePtr
->mask
;
443 * Search all of the entries in the appropriate bucket.
446 for (hPtr
= tablePtr
->buckets
[index
]; hPtr
!= NULL
;
447 hPtr
= hPtr
->nextPtr
) {
448 for (p1
= key
, p2
= hPtr
->key
.string
; ; p1
++, p2
++) {
461 *----------------------------------------------------------------------
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.
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.
476 * A new entry may be added to the hash table.
478 *----------------------------------------------------------------------
481 static Tcl_HashEntry
*
482 StringCreate(tablePtr
, key
, newPtr
)
483 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
484 char *key
; /* Key to use to find or create matching
486 int *newPtr
; /* Store info here telling whether a new
487 * entry was created. */
489 register Tcl_HashEntry
*hPtr
;
490 register char *p1
, *p2
;
493 index
= HashString(key
) & tablePtr
->mask
;
496 * Search all of the entries in this bucket.
499 for (hPtr
= tablePtr
->buckets
[index
]; hPtr
!= NULL
;
500 hPtr
= hPtr
->nextPtr
) {
501 for (p1
= key
, p2
= hPtr
->key
.string
; ; p1
++, p2
++) {
513 * Entry not found. Add a new one to the bucket.
517 hPtr
= (Tcl_HashEntry
*) ckalloc((unsigned)
518 (sizeof(Tcl_HashEntry
) + strlen(key
) - (sizeof(hPtr
->key
) -1)));
519 hPtr
->tablePtr
= tablePtr
;
520 hPtr
->bucketPtr
= &(tablePtr
->buckets
[index
]);
521 hPtr
->nextPtr
= *hPtr
->bucketPtr
;
522 hPtr
->clientData
= 0;
523 strcpy(hPtr
->key
.string
, key
);
524 *hPtr
->bucketPtr
= hPtr
;
525 tablePtr
->numEntries
++;
528 * If the table has exceeded a decent size, rebuild it with many
532 if (tablePtr
->numEntries
>= tablePtr
->rebuildSize
) {
533 RebuildTable(tablePtr
);
539 *----------------------------------------------------------------------
543 * Given a hash table with one-word keys, and a one-word key, find
544 * the entry with a matching key.
547 * The return value is a token for the matching entry in the
548 * hash table, or NULL if there was no matching entry.
553 *----------------------------------------------------------------------
556 static Tcl_HashEntry
*
557 OneWordFind(tablePtr
, key
)
558 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
559 register char *key
; /* Key to use to find matching entry. */
561 register Tcl_HashEntry
*hPtr
;
564 index
= RANDOM_INDEX(tablePtr
, key
);
567 * Search all of the entries in the appropriate bucket.
570 for (hPtr
= tablePtr
->buckets
[index
]; hPtr
!= NULL
;
571 hPtr
= hPtr
->nextPtr
) {
572 if (hPtr
->key
.oneWordValue
== key
) {
580 *----------------------------------------------------------------------
584 * Given a hash table with one-word keys, and a one-word key, find
585 * the entry with a matching key. If there is no matching entry,
586 * then create a new entry that does match.
589 * The return value is a pointer to the matching entry. If this
590 * is a newly-created entry, then *newPtr will be set to a non-zero
591 * value; otherwise *newPtr will be set to 0. If this is a new
592 * entry the value stored in the entry will initially be 0.
595 * A new entry may be added to the hash table.
597 *----------------------------------------------------------------------
600 static Tcl_HashEntry
*
601 OneWordCreate(tablePtr
, key
, newPtr
)
602 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
603 register char *key
; /* Key to use to find or create matching
605 int *newPtr
; /* Store info here telling whether a new
606 * entry was created. */
608 register Tcl_HashEntry
*hPtr
;
611 index
= RANDOM_INDEX(tablePtr
, key
);
614 * Search all of the entries in this bucket.
617 for (hPtr
= tablePtr
->buckets
[index
]; hPtr
!= NULL
;
618 hPtr
= hPtr
->nextPtr
) {
619 if (hPtr
->key
.oneWordValue
== key
) {
626 * Entry not found. Add a new one to the bucket.
630 hPtr
= (Tcl_HashEntry
*) ckalloc(sizeof(Tcl_HashEntry
));
631 hPtr
->tablePtr
= tablePtr
;
632 hPtr
->bucketPtr
= &(tablePtr
->buckets
[index
]);
633 hPtr
->nextPtr
= *hPtr
->bucketPtr
;
634 hPtr
->clientData
= 0;
635 hPtr
->key
.oneWordValue
= key
;
636 *hPtr
->bucketPtr
= hPtr
;
637 tablePtr
->numEntries
++;
640 * If the table has exceeded a decent size, rebuild it with many
644 if (tablePtr
->numEntries
>= tablePtr
->rebuildSize
) {
645 RebuildTable(tablePtr
);
651 *----------------------------------------------------------------------
655 * Given a hash table with array-of-int keys, and a key, find
656 * the entry with a matching key.
659 * The return value is a token for the matching entry in the
660 * hash table, or NULL if there was no matching entry.
665 *----------------------------------------------------------------------
668 static Tcl_HashEntry
*
669 ArrayFind(tablePtr
, key
)
670 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
671 char *key
; /* Key to use to find matching entry. */
673 register Tcl_HashEntry
*hPtr
;
674 int *arrayPtr
= (int *) key
;
675 register int *iPtr1
, *iPtr2
;
678 for (index
= 0, count
= tablePtr
->keyType
, iPtr1
= arrayPtr
;
679 count
> 0; count
--, iPtr1
++) {
682 index
= RANDOM_INDEX(tablePtr
, index
);
685 * Search all of the entries in the appropriate bucket.
688 for (hPtr
= tablePtr
->buckets
[index
]; hPtr
!= NULL
;
689 hPtr
= hPtr
->nextPtr
) {
690 for (iPtr1
= arrayPtr
, iPtr2
= hPtr
->key
.words
,
691 count
= tablePtr
->keyType
; ; count
--, iPtr1
++, iPtr2
++) {
695 if (*iPtr1
!= *iPtr2
) {
704 *----------------------------------------------------------------------
708 * Given a hash table with one-word keys, and a one-word key, find
709 * the entry with a matching key. If there is no matching entry,
710 * then create a new entry that does match.
713 * The return value is a pointer to the matching entry. If this
714 * is a newly-created entry, then *newPtr will be set to a non-zero
715 * value; otherwise *newPtr will be set to 0. If this is a new
716 * entry the value stored in the entry will initially be 0.
719 * A new entry may be added to the hash table.
721 *----------------------------------------------------------------------
724 static Tcl_HashEntry
*
725 ArrayCreate(tablePtr
, key
, newPtr
)
726 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
727 register char *key
; /* Key to use to find or create matching
729 int *newPtr
; /* Store info here telling whether a new
730 * entry was created. */
732 register Tcl_HashEntry
*hPtr
;
733 int *arrayPtr
= (int *) key
;
734 register int *iPtr1
, *iPtr2
;
737 for (index
= 0, count
= tablePtr
->keyType
, iPtr1
= arrayPtr
;
738 count
> 0; count
--, iPtr1
++) {
741 index
= RANDOM_INDEX(tablePtr
, index
);
744 * Search all of the entries in the appropriate bucket.
747 for (hPtr
= tablePtr
->buckets
[index
]; hPtr
!= NULL
;
748 hPtr
= hPtr
->nextPtr
) {
749 for (iPtr1
= arrayPtr
, iPtr2
= hPtr
->key
.words
,
750 count
= tablePtr
->keyType
; ; count
--, iPtr1
++, iPtr2
++) {
755 if (*iPtr1
!= *iPtr2
) {
762 * Entry not found. Add a new one to the bucket.
766 hPtr
= (Tcl_HashEntry
*) ckalloc((unsigned) (sizeof(Tcl_HashEntry
)
767 + (tablePtr
->keyType
*sizeof(int)) - 4));
768 hPtr
->tablePtr
= tablePtr
;
769 hPtr
->bucketPtr
= &(tablePtr
->buckets
[index
]);
770 hPtr
->nextPtr
= *hPtr
->bucketPtr
;
771 hPtr
->clientData
= 0;
772 for (iPtr1
= arrayPtr
, iPtr2
= hPtr
->key
.words
, count
= tablePtr
->keyType
;
773 count
> 0; count
--, iPtr1
++, iPtr2
++) {
776 *hPtr
->bucketPtr
= hPtr
;
777 tablePtr
->numEntries
++;
780 * If the table has exceeded a decent size, rebuild it with many
784 if (tablePtr
->numEntries
>= tablePtr
->rebuildSize
) {
785 RebuildTable(tablePtr
);
791 *----------------------------------------------------------------------
795 * This procedure is invoked when an Tcl_FindHashEntry is called
796 * on a table that has been deleted.
799 * If panic returns (which it shouldn't) this procedure returns
805 *----------------------------------------------------------------------
809 static Tcl_HashEntry
*
810 BogusFind(tablePtr
, key
)
811 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
812 char *key
; /* Key to use to find matching entry. */
814 panic("called Tcl_FindHashEntry on deleted table");
819 *----------------------------------------------------------------------
823 * This procedure is invoked when an Tcl_CreateHashEntry is called
824 * on a table that has been deleted.
827 * If panic returns (which it shouldn't) this procedure returns
833 *----------------------------------------------------------------------
837 static Tcl_HashEntry
*
838 BogusCreate(tablePtr
, key
, newPtr
)
839 Tcl_HashTable
*tablePtr
; /* Table in which to lookup entry. */
840 char *key
; /* Key to use to find or create matching
842 int *newPtr
; /* Store info here telling whether a new
843 * entry was created. */
845 panic("called Tcl_CreateHashEntry on deleted table");
850 *----------------------------------------------------------------------
854 * This procedure is invoked when the ratio of entries to hash
855 * buckets becomes too large. It creates a new table with a
856 * larger bucket array and moves all of the entries into the
863 * Memory gets reallocated and entries get re-hashed to new
866 *----------------------------------------------------------------------
870 RebuildTable(tablePtr
)
871 register Tcl_HashTable
*tablePtr
; /* Table to enlarge. */
873 int oldSize
, count
, index
;
874 Tcl_HashEntry
**oldBuckets
;
875 register Tcl_HashEntry
**oldChainPtr
, **newChainPtr
;
876 register Tcl_HashEntry
*hPtr
;
878 oldSize
= tablePtr
->numBuckets
;
879 oldBuckets
= tablePtr
->buckets
;
882 * Allocate and initialize the new bucket array, and set up
883 * hashing constants for new array size.
886 tablePtr
->numBuckets
*= 4;
887 tablePtr
->buckets
= (Tcl_HashEntry
**) ckalloc((unsigned)
888 (tablePtr
->numBuckets
* sizeof(Tcl_HashEntry
*)));
889 for (count
= tablePtr
->numBuckets
, newChainPtr
= tablePtr
->buckets
;
890 count
> 0; count
--, newChainPtr
++) {
893 tablePtr
->rebuildSize
*= 4;
894 tablePtr
->downShift
-= 2;
895 tablePtr
->mask
= (tablePtr
->mask
<< 2) + 3;
898 * Rehash all of the existing entries into the new bucket array.
901 for (oldChainPtr
= oldBuckets
; oldSize
> 0; oldSize
--, oldChainPtr
++) {
902 for (hPtr
= *oldChainPtr
; hPtr
!= NULL
; hPtr
= *oldChainPtr
) {
903 *oldChainPtr
= hPtr
->nextPtr
;
904 if (tablePtr
->keyType
== TCL_STRING_KEYS
) {
905 index
= HashString(hPtr
->key
.string
) & tablePtr
->mask
;
906 } else if (tablePtr
->keyType
== TCL_ONE_WORD_KEYS
) {
907 index
= RANDOM_INDEX(tablePtr
, hPtr
->key
.oneWordValue
);
912 for (index
= 0, count
= tablePtr
->keyType
,
913 iPtr
= hPtr
->key
.words
; count
> 0; count
--, iPtr
++) {
916 index
= RANDOM_INDEX(tablePtr
, index
);
918 hPtr
->bucketPtr
= &(tablePtr
->buckets
[index
]);
919 hPtr
->nextPtr
= *hPtr
->bucketPtr
;
920 *hPtr
->bucketPtr
= hPtr
;
925 * Free up the old bucket array, if it was dynamically allocated.
928 if (oldBuckets
!= tablePtr
->staticBuckets
) {
929 ckfree((char *) oldBuckets
);