Commit | Line | Data |
---|---|---|
e6c0deb9 KB |
1 | /* |
2 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
3 | * Copyright (c) 1988, 1989 by Adam de Boor | |
4 | * Copyright (c) 1989 by Berkeley Softworks | |
5 | * All rights reserved. | |
6 | * | |
7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | |
9 | * | |
10 | * Redistribution and use in source and binary forms are permitted | |
11 | * provided that the above copyright notice and this paragraph are | |
12 | * duplicated in all such forms and that any documentation, | |
13 | * advertising materials, and other materials related to such | |
14 | * distribution and use acknowledge that the software was developed | |
15 | * by the University of California, Berkeley. The name of the | |
16 | * University may not be used to endorse or promote products derived | |
17 | * from this software without specific prior written permission. | |
18 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
19 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
21 | */ | |
22 | ||
23 | #ifndef lint | |
24 | static char sccsid[] = "@(#)hash.c 5.2 (Berkeley) %G%"; | |
25 | #endif /* not lint */ | |
26 | ||
92a1926a KB |
27 | /* hash.c -- |
28 | * | |
29 | * This module contains routines to manipulate a hash table. | |
30 | * See hash.h for a definition of the structure of the hash | |
31 | * table. Hash tables grow automatically as the amount of | |
32 | * information increases. | |
92a1926a KB |
33 | */ |
34 | ||
92a1926a KB |
35 | #include "sprite.h" |
36 | #include "hash.h" | |
37 | #include "list.h" | |
38 | ||
39 | /* | |
40 | * Forward references to local procedures that are used before they're | |
41 | * defined: | |
42 | */ | |
43 | ||
44 | static Hash_Entry * ChainSearch(); | |
45 | static int Hash(); | |
46 | static void RebuildTable(); | |
47 | ||
48 | /* | |
49 | * The following defines the ratio of # entries to # buckets | |
50 | * at which we rebuild the table to make it larger. | |
51 | */ | |
52 | ||
53 | static rebuildLimit = 3; | |
54 | \f | |
55 | /* | |
56 | *--------------------------------------------------------- | |
57 | * | |
58 | * Hash_InitTable -- | |
59 | * | |
60 | * This routine just sets up the hash table. | |
61 | * | |
62 | * Results: | |
63 | * None. | |
64 | * | |
65 | * Side Effects: | |
66 | * Memory is allocated for the initial bucket area. | |
67 | * | |
68 | *--------------------------------------------------------- | |
69 | */ | |
70 | ||
71 | void | |
72 | Hash_InitTable(tablePtr, numBuckets, keyType) | |
73 | register Hash_Table *tablePtr; /* Structure to use to hold table. */ | |
74 | int numBuckets; /* How many buckets to create for | |
75 | * starters. This number is rounded | |
76 | * up to a power of two. If <= 0, | |
77 | * a reasonable default is chosen. | |
78 | * The table will grow in size later | |
79 | * as needed. */ | |
80 | int keyType; /* HASH_STRING_KEYS means that key | |
81 | * values passed to HashFind will be | |
82 | * strings, passed via a (char *) | |
83 | * pointer. HASH_ONE_WORD_KEYS means | |
84 | * that key values will be any | |
85 | * one-word value passed as Address. | |
86 | * > 1 means that key values will be | |
87 | * multi-word values whose address is | |
88 | * passed as Address. In this last | |
89 | * case, keyType is the number of | |
90 | * words in the key, not the number | |
91 | * of bytes. */ | |
92 | { | |
93 | register int i; | |
94 | register List_Links *bucketPtr; | |
95 | ||
96 | /* | |
97 | * Round up the size to a power of two. | |
98 | */ | |
99 | ||
100 | if (numBuckets <= 0) { | |
101 | numBuckets = 16; | |
102 | } | |
103 | tablePtr->numEntries = 0; | |
104 | tablePtr->keyType = keyType; | |
105 | tablePtr->size = 2; | |
106 | tablePtr->mask = 1; | |
107 | tablePtr->downShift = 29; | |
108 | while (tablePtr->size < numBuckets) { | |
109 | tablePtr->size <<= 1; | |
110 | tablePtr->mask = (tablePtr->mask << 1) + 1; | |
111 | tablePtr->downShift--; | |
112 | } | |
113 | ||
114 | tablePtr->bucketPtr = (List_Links *) malloc(sizeof(List_Links) | |
115 | * tablePtr->size); | |
116 | for (i=0, bucketPtr = tablePtr->bucketPtr; i < tablePtr->size; | |
117 | i++, bucketPtr++) { | |
118 | List_Init(bucketPtr); | |
119 | } | |
120 | } | |
121 | \f | |
122 | /* | |
123 | *--------------------------------------------------------- | |
124 | * | |
125 | * Hash_DeleteTable -- | |
126 | * | |
127 | * This routine removes everything from a hash table | |
128 | * and frees up the memory space it occupied (except for | |
129 | * the space in the Hash_Table structure). | |
130 | * | |
131 | * Results: | |
132 | * None. | |
133 | * | |
134 | * Side Effects: | |
135 | * Lots of memory is freed up. | |
136 | * | |
137 | *--------------------------------------------------------- | |
138 | */ | |
139 | ||
140 | void | |
141 | Hash_DeleteTable(tablePtr) | |
142 | Hash_Table *tablePtr; /* Hash table whose entries are all to | |
143 | * be freed. */ | |
144 | { | |
145 | register List_Links *hashTableEnd; | |
146 | register Hash_Entry *hashEntryPtr; | |
147 | register List_Links *bucketPtr; | |
148 | ||
149 | bucketPtr = tablePtr->bucketPtr; | |
150 | hashTableEnd = &(bucketPtr[tablePtr->size]); | |
151 | for (; bucketPtr < hashTableEnd; bucketPtr++) { | |
152 | while (!List_IsEmpty(bucketPtr)) { | |
153 | hashEntryPtr = (Hash_Entry *) List_First(bucketPtr); | |
154 | List_Remove((List_Links *) hashEntryPtr); | |
155 | free((Address) hashEntryPtr); | |
156 | } | |
157 | } | |
158 | free((Address) tablePtr->bucketPtr); | |
159 | ||
160 | /* | |
161 | * Set up the hash table to cause memory faults on any future | |
162 | * access attempts until re-initialization. | |
163 | */ | |
164 | ||
165 | tablePtr->bucketPtr = (List_Links *) NIL; | |
166 | } | |
167 | \f | |
168 | /* | |
169 | *--------------------------------------------------------- | |
170 | * | |
171 | * Hash_FindEntry -- | |
172 | * | |
173 | * Searches a hash table for an entry corresponding to key. | |
174 | * | |
175 | * Results: | |
176 | * The return value is a pointer to the entry for key, | |
177 | * if key was present in the table. If key was not | |
178 | * present, NULL is returned. | |
179 | * | |
180 | * Side Effects: | |
181 | * None. | |
182 | * | |
183 | *--------------------------------------------------------- | |
184 | */ | |
185 | ||
186 | Hash_Entry * | |
187 | Hash_FindEntry(tablePtr, key) | |
188 | Hash_Table *tablePtr; /* Hash table to search. */ | |
189 | Address key; /* A hash key. */ | |
190 | { | |
191 | return(ChainSearch(tablePtr, key, | |
192 | &(tablePtr->bucketPtr[Hash(tablePtr, key)]))); | |
193 | } | |
194 | \f | |
195 | /* | |
196 | *--------------------------------------------------------- | |
197 | * | |
198 | * Hash_CreateEntry -- | |
199 | * | |
200 | * Searches a hash table for an entry corresponding to | |
201 | * key. If no entry is found, then one is created. | |
202 | * | |
203 | * Results: | |
204 | * The return value is a pointer to the entry. If *newPtr | |
205 | * isn't NULL, then *newPtr is filled in with TRUE if a | |
206 | * new entry was created, and FALSE if an entry already existed | |
207 | * with the given key. | |
208 | * | |
209 | * Side Effects: | |
210 | * Memory may be allocated, and the hash buckets may be modified. | |
211 | *--------------------------------------------------------- | |
212 | */ | |
213 | ||
214 | Hash_Entry * | |
215 | Hash_CreateEntry(tablePtr, key, newPtr) | |
216 | register Hash_Table *tablePtr; /* Hash table to search. */ | |
217 | Address key; /* A hash key. */ | |
218 | Boolean *newPtr; /* Filled in with TRUE if new entry | |
219 | * created, FALSE otherwise. */ | |
220 | { | |
221 | register Hash_Entry *hashEntryPtr; | |
222 | register int *hashKeyPtr; | |
223 | register int *keyPtr; | |
224 | List_Links *hashList; | |
225 | ||
226 | keyPtr = (int *) key; | |
227 | ||
228 | hashList = &(tablePtr->bucketPtr[Hash(tablePtr, (Address) keyPtr)]); | |
229 | hashEntryPtr = ChainSearch(tablePtr, (Address) keyPtr, hashList); | |
230 | ||
231 | if (hashEntryPtr != (Hash_Entry *) NULL) { | |
232 | if (newPtr != NULL) { | |
233 | *newPtr = FALSE; | |
234 | } | |
235 | return hashEntryPtr; | |
236 | } | |
237 | ||
238 | /* | |
239 | * The desired entry isn't there. Before allocating a new entry, | |
240 | * see if we're overloading the buckets. If so, then make a | |
241 | * bigger table. | |
242 | */ | |
243 | ||
244 | if (tablePtr->numEntries >= rebuildLimit * tablePtr->size) { | |
245 | RebuildTable(tablePtr); | |
246 | hashList = &(tablePtr->bucketPtr[Hash(tablePtr, (Address) keyPtr)]); | |
247 | } | |
248 | tablePtr->numEntries += 1; | |
249 | ||
250 | /* | |
251 | * Not there, we have to allocate. If the string is longer | |
252 | * than 3 bytes, then we have to allocate extra space in the | |
253 | * entry. | |
254 | */ | |
255 | ||
256 | switch (tablePtr->keyType) { | |
257 | case HASH_STRING_KEYS: | |
258 | hashEntryPtr = (Hash_Entry *) malloc(sizeof(Hash_Entry) + | |
259 | strlen((char *) keyPtr) - 3); | |
260 | strcpy(hashEntryPtr->key.name, (char *) keyPtr); | |
261 | break; | |
262 | case HASH_ONE_WORD_KEYS: | |
263 | hashEntryPtr = (Hash_Entry *) malloc(sizeof(Hash_Entry)); | |
264 | hashEntryPtr->key.ptr = (Address) keyPtr; | |
265 | break; | |
266 | case 2: | |
267 | hashEntryPtr = | |
268 | (Hash_Entry *) malloc(sizeof(Hash_Entry) + sizeof(int)); | |
269 | hashKeyPtr = hashEntryPtr->key.words; | |
270 | *hashKeyPtr++ = *keyPtr++; | |
271 | *hashKeyPtr = *keyPtr; | |
272 | break; | |
273 | default: { | |
274 | register n; | |
275 | ||
276 | n = tablePtr->keyType; | |
277 | hashEntryPtr = (Hash_Entry *) | |
278 | malloc(sizeof(Hash_Entry) + (n - 1) * sizeof(int)); | |
279 | hashKeyPtr = hashEntryPtr->key.words; | |
280 | do { | |
281 | *hashKeyPtr++ = *keyPtr++; | |
282 | } while (--n); | |
283 | break; | |
284 | } | |
285 | } | |
286 | ||
287 | hashEntryPtr->clientData = (ClientData) NULL; | |
288 | List_Insert((List_Links *) hashEntryPtr, LIST_ATFRONT(hashList)); | |
289 | ||
290 | if (newPtr != NULL) { | |
291 | *newPtr = TRUE; | |
292 | } | |
293 | return hashEntryPtr; | |
294 | } | |
295 | \f | |
296 | /* | |
297 | *--------------------------------------------------------- | |
298 | * | |
299 | * Hash_DeleteEntry -- | |
300 | * | |
301 | * Delete the given hash table entry and free memory associated with | |
302 | * it. | |
303 | * | |
304 | * Results: | |
305 | * None. | |
306 | * | |
307 | * Side Effects: | |
308 | * Hash chain that entry lives in is modified and memory is freed. | |
309 | * | |
310 | *--------------------------------------------------------- | |
311 | */ | |
312 | ||
313 | void | |
314 | Hash_DeleteEntry(tablePtr, hashEntryPtr) | |
315 | Hash_Table *tablePtr; | |
316 | register Hash_Entry *hashEntryPtr; | |
317 | { | |
318 | if (hashEntryPtr != (Hash_Entry *) NULL) { | |
319 | List_Remove((List_Links *) hashEntryPtr); | |
320 | free((Address) hashEntryPtr); | |
321 | tablePtr->numEntries--; | |
322 | } | |
323 | } | |
324 | \f | |
325 | /* | |
326 | *--------------------------------------------------------- | |
327 | * | |
328 | * Hash_EnumFirst -- | |
329 | * This procedure sets things up for a complete search | |
330 | * of all entries recorded in the hash table. | |
331 | * | |
332 | * Results: | |
333 | * The return value is the address of the first entry in | |
334 | * the hash table, or NULL if the table is empty. | |
335 | * | |
336 | * Side Effects: | |
337 | * The information in hashSearchPtr is initialized so that successive | |
338 | * calls to Hash_Next will return successive HashEntry's | |
339 | * from the table. | |
340 | * | |
341 | *--------------------------------------------------------- | |
342 | */ | |
343 | ||
344 | Hash_Entry * | |
345 | Hash_EnumFirst(tablePtr, hashSearchPtr) | |
346 | Hash_Table *tablePtr; /* Table to be searched. */ | |
347 | register Hash_Search *hashSearchPtr; /* Area in which to keep state | |
348 | * about search.*/ | |
349 | { | |
350 | hashSearchPtr->tablePtr = tablePtr; | |
351 | hashSearchPtr->nextIndex = 0; | |
352 | hashSearchPtr->hashEntryPtr = (Hash_Entry *) NULL; | |
353 | return Hash_EnumNext(hashSearchPtr); | |
354 | } | |
355 | ||
356 | /* | |
357 | *--------------------------------------------------------- | |
358 | * | |
359 | * Hash_EnumNext -- | |
360 | * This procedure returns successive entries in the hash table. | |
361 | * | |
362 | * Results: | |
363 | * The return value is a pointer to the next HashEntry | |
364 | * in the table, or NULL when the end of the table is | |
365 | * reached. | |
366 | * | |
367 | * Side Effects: | |
368 | * The information in hashSearchPtr is modified to advance to the | |
369 | * next entry. | |
370 | * | |
371 | *--------------------------------------------------------- | |
372 | */ | |
373 | ||
374 | Hash_Entry * | |
375 | Hash_EnumNext(hashSearchPtr) | |
376 | register Hash_Search *hashSearchPtr; /* Area used to keep state about | |
377 | search. */ | |
378 | { | |
379 | register List_Links *hashList; | |
380 | register Hash_Entry *hashEntryPtr; | |
381 | ||
382 | hashEntryPtr = hashSearchPtr->hashEntryPtr; | |
383 | while (hashEntryPtr == (Hash_Entry *) NULL || | |
384 | List_IsAtEnd(hashSearchPtr->hashList, | |
385 | (List_Links *) hashEntryPtr)) { | |
386 | if (hashSearchPtr->nextIndex >= hashSearchPtr->tablePtr->size) { | |
387 | return((Hash_Entry *) NULL); | |
388 | } | |
389 | hashList = &(hashSearchPtr->tablePtr->bucketPtr[ | |
390 | hashSearchPtr->nextIndex]); | |
391 | hashSearchPtr->nextIndex++; | |
392 | if (!List_IsEmpty(hashList)) { | |
393 | hashEntryPtr = (Hash_Entry *) List_First(hashList); | |
394 | hashSearchPtr->hashList = hashList; | |
395 | break; | |
396 | } | |
397 | } | |
398 | ||
399 | hashSearchPtr->hashEntryPtr = | |
400 | (Hash_Entry *) List_Next((List_Links *) hashEntryPtr); | |
401 | ||
402 | return(hashEntryPtr); | |
403 | } | |
404 | \f | |
405 | /* | |
406 | *--------------------------------------------------------- | |
407 | * | |
408 | * Hash_PrintStats -- | |
409 | * | |
410 | * This routine calls a caller-supplied procedure to print | |
411 | * statistics about the current bucket situation. | |
412 | * | |
413 | * Results: | |
414 | * None. | |
415 | * | |
416 | * Side Effects: | |
417 | * Proc gets called (potentially many times) to output information | |
418 | * about the hash table. It must have the following calling sequence: | |
419 | * | |
420 | * void | |
421 | * proc(clientData, string) | |
422 | * ClientData clientData; | |
423 | * char *string; | |
424 | * { | |
425 | * } | |
426 | * | |
427 | * In each call, clientData is the same as the clientData argument | |
428 | * to this procedure, and string is a null-terminated string of | |
429 | * characters to output. | |
430 | * | |
431 | *--------------------------------------------------------- | |
432 | */ | |
433 | ||
434 | void | |
435 | Hash_PrintStats(tablePtr, proc, clientData) | |
436 | Hash_Table *tablePtr; /* Table for which to print info. */ | |
437 | void (*proc)(); /* Procedure to call to do actual | |
438 | * I/O. */ | |
439 | { | |
440 | int count[10], overflow, i, j; | |
441 | char msg[100]; | |
442 | Hash_Entry *hashEntryPtr; | |
443 | List_Links *hashList; | |
444 | ||
445 | for (i=0; i<10; i++) { | |
446 | count[i] = 0; | |
447 | } | |
448 | overflow = 0; | |
449 | for (i = 0; i < tablePtr->size; i++) { | |
450 | j = 0; | |
451 | hashList = &(tablePtr->bucketPtr[i]); | |
452 | LIST_FORALL(hashList, (List_Links *) hashEntryPtr) { | |
453 | j++; | |
454 | } | |
455 | if (j < 10) { | |
456 | count[j]++; | |
457 | } else { | |
458 | overflow++; | |
459 | } | |
460 | } | |
461 | ||
462 | sprintf(msg, "Entries in table %d number of buckets %d\n", | |
463 | tablePtr->numEntries, tablePtr->size); | |
464 | (*proc)(clientData, msg); | |
465 | for (i = 0; i < 10; i++) { | |
466 | sprintf(msg, "Number of buckets with %d entries: %d.\n", | |
467 | i, count[i]); | |
468 | (*proc)(clientData, msg); | |
469 | } | |
470 | sprintf(msg, "Number of buckets with > 9 entries: %d.\n", | |
471 | overflow); | |
472 | (*proc)(clientData, msg); | |
473 | } | |
474 | \f | |
475 | /* | |
476 | *--------------------------------------------------------- | |
477 | * | |
478 | * Hash -- | |
479 | * This is a local procedure to compute a hash table | |
480 | * bucket address based on a string value. | |
481 | * | |
482 | * Results: | |
483 | * The return value is an integer between 0 and size - 1. | |
484 | * | |
485 | * Side Effects: | |
486 | * None. | |
487 | * | |
488 | * Design: | |
489 | * It is expected that most keys are decimal numbers, | |
490 | * so the algorithm behaves accordingly. The randomizing | |
491 | * code is stolen straight from the rand library routine. | |
492 | * | |
493 | *--------------------------------------------------------- | |
494 | */ | |
495 | ||
496 | static int | |
497 | Hash(tablePtr, key) | |
498 | register Hash_Table *tablePtr; | |
499 | register char *key; | |
500 | { | |
501 | register int i = 0; | |
502 | register int j; | |
503 | register int *intPtr; | |
504 | ||
505 | switch (tablePtr->keyType) { | |
506 | case HASH_STRING_KEYS: | |
507 | while (*key != 0) { | |
508 | i = (i * 10) + (*key++ - '0'); | |
509 | } | |
510 | break; | |
511 | case HASH_ONE_WORD_KEYS: | |
512 | i = (int) key; | |
513 | break; | |
514 | case 2: | |
515 | i = ((int *) key)[0] + ((int *) key)[1]; | |
516 | break; | |
517 | default: | |
518 | j = tablePtr->keyType; | |
519 | intPtr = (int *) key; | |
520 | do { | |
521 | i += *intPtr++; | |
522 | j--; | |
523 | } while (j > 0); | |
524 | break; | |
525 | } | |
526 | ||
527 | ||
528 | return(((i*1103515245 + 12345) >> tablePtr->downShift) & tablePtr->mask); | |
529 | } | |
530 | \f | |
531 | /* | |
532 | *--------------------------------------------------------- | |
533 | * | |
534 | * ChainSearch -- | |
535 | * | |
536 | * Search the hash table for the entry in the hash chain. | |
537 | * | |
538 | * Results: | |
539 | * Pointer to entry in hash chain, NULL if none found. | |
540 | * | |
541 | * Side Effects: | |
542 | * None. | |
543 | * | |
544 | *--------------------------------------------------------- | |
545 | */ | |
546 | ||
547 | static Hash_Entry * | |
548 | ChainSearch(tablePtr, key, hashList) | |
549 | Hash_Table *tablePtr; /* Hash table to search. */ | |
550 | register Address key; /* A hash key. */ | |
551 | register List_Links *hashList; | |
552 | { | |
553 | register Hash_Entry *hashEntryPtr; | |
554 | register int *hashKeyPtr; | |
555 | int *keyPtr; | |
556 | register int numKeys; | |
557 | ||
558 | numKeys = tablePtr->keyType; | |
559 | LIST_FORALL(hashList, (List_Links *) hashEntryPtr) { | |
560 | switch (numKeys) { | |
561 | case 0: | |
562 | if (strcmp(hashEntryPtr->key.name, key) == 0) { | |
563 | return(hashEntryPtr); | |
564 | } | |
565 | break; | |
566 | case 1: | |
567 | if (hashEntryPtr->key.ptr == key) { | |
568 | return(hashEntryPtr); | |
569 | } | |
570 | break; | |
571 | case 2: | |
572 | hashKeyPtr = hashEntryPtr->key.words; | |
573 | keyPtr = (int *) key; | |
574 | if (*hashKeyPtr++ == *keyPtr++ && *hashKeyPtr == *keyPtr) { | |
575 | return(hashEntryPtr); | |
576 | } | |
577 | break; | |
578 | default: | |
579 | if (bcmp((Address) hashEntryPtr->key.words, | |
580 | (Address) key, numKeys * sizeof(int))) { | |
581 | return(hashEntryPtr); | |
582 | } | |
583 | break; | |
584 | } | |
585 | } | |
586 | ||
587 | /* | |
588 | * The desired entry isn't there | |
589 | */ | |
590 | ||
591 | return ((Hash_Entry *) NULL); | |
592 | } | |
593 | \f | |
594 | /* | |
595 | *--------------------------------------------------------- | |
596 | * | |
597 | * RebuildTable -- | |
598 | * This local routine makes a new hash table that | |
599 | * is larger than the old one. | |
600 | * | |
601 | * Results: | |
602 | * None. | |
603 | * | |
604 | * Side Effects: | |
605 | * The entire hash table is moved, so any bucket numbers | |
606 | * from the old table are invalid. | |
607 | * | |
608 | *--------------------------------------------------------- | |
609 | */ | |
610 | ||
611 | static void | |
612 | RebuildTable(tablePtr) | |
613 | Hash_Table *tablePtr; /* Table to be enlarged. */ | |
614 | { | |
615 | int oldSize; | |
616 | int bucket; | |
617 | List_Links *oldBucketPtr; | |
618 | register Hash_Entry *hashEntryPtr; | |
619 | register List_Links *oldHashList; | |
620 | ||
621 | oldBucketPtr = tablePtr->bucketPtr; | |
622 | oldSize = tablePtr->size; | |
623 | ||
624 | /* | |
625 | * Build a new table 4 times as large as the old one. | |
626 | */ | |
627 | ||
628 | Hash_InitTable(tablePtr, tablePtr->size * 4, tablePtr->keyType); | |
629 | ||
630 | for (oldHashList = oldBucketPtr; oldSize > 0; oldSize--, oldHashList++) { | |
631 | while (!List_IsEmpty(oldHashList)) { | |
632 | hashEntryPtr = (Hash_Entry *) List_First(oldHashList); | |
633 | List_Remove((List_Links *) hashEntryPtr); | |
634 | switch (tablePtr->keyType) { | |
635 | case HASH_STRING_KEYS: | |
636 | bucket = Hash(tablePtr, (Address) hashEntryPtr->key.name); | |
637 | break; | |
638 | case HASH_ONE_WORD_KEYS: | |
639 | bucket = Hash(tablePtr, (Address) hashEntryPtr->key.ptr); | |
640 | break; | |
641 | default: | |
642 | bucket = Hash(tablePtr, (Address) hashEntryPtr->key.words); | |
643 | break; | |
644 | } | |
645 | List_Insert((List_Links *) hashEntryPtr, | |
646 | LIST_ATFRONT(&(tablePtr->bucketPtr[bucket]))); | |
647 | tablePtr->numEntries++; | |
648 | } | |
649 | } | |
650 | ||
651 | free((Address) oldBucketPtr); | |
652 | } |