4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1988 AT&T */
28 /* All Rights Reserved */
31 * Compile time switches:
33 * MULT - use a multiplicative hashing function.
34 * DIV - use the remainder mod table size as a hashing function.
35 * CHAINED - use a linked list to resolve collisions.
36 * OPEN - use open addressing to resolve collisions.
37 * BRENT - use Brent's modification to improve the OPEN algorithm.
38 * SORTUP - CHAINED list is sorted in increasing order.
39 * SORTDOWN - CHAINED list is sorted in decreasing order.
40 * START - CHAINED list with entries appended at front.
41 * DRIVER - compile in a main program to drive the tests.
42 * DEBUG - compile some debugging printout statements.
43 * USCR - user supplied comparison routine.
46 #pragma weak _hcreate = hcreate
47 #pragma weak _hdestroy = hdestroy
48 #pragma weak _hsearch = hsearch
60 typedef char *POINTER
;
66 #define repeat for (;;)
67 #define until(A) if (A) break;
95 #define COMPARE(A, B) (* hcompar)((A), (B))
96 extern int (* hcompar
)();
98 #define COMPARE(A, B) strcmp((A), (B))
102 #define SHIFT ((CHAR_BIT * sizeof (int)) - m) /* Shift factor */
103 #define FACTOR 035761254233 /* Magic multiplication factor */
104 #define HASH hashm /* Multiplicative hash function */
105 #define HASH2 hash2m /* Secondary hash function */
106 static unsigned int hashm(POINTER
);
107 static unsigned int hash2m(POINTER
);
110 #define HASH hashd /* Division hashing routine */
111 #define HASH2(A) 1 /* Secondary hash function */
112 static unsigned int hashd();
117 typedef struct node
{ /* Part of the linked list of entries */
121 typedef NODE
*TABELEM
;
122 static NODE
**table
; /* The address of the hash table */
123 static ENTRY
*build();
126 typedef ENTRY TABELEM
; /* What the table contains (TABle ELEMents) */
127 static TABELEM
*table
; /* The address of the hash table */
128 static unsigned int count
= 0; /* Number of entries in hash table */
132 static unsigned int length
; /* Size of the hash table */
133 static unsigned int m
; /* Log base 2 of length */
134 static unsigned int prcnt
; /* Number of probes this item */
135 static mutex_t table_lock
= DEFAULTMUTEX
;
136 #define RETURN(n) { lmutex_unlock(&table_lock); return (n); }
139 * forward declarations
142 static unsigned int crunch(POINTER
);
149 char line
[80]; /* Room for the input line */
150 int i
= 0; /* Data generator */
151 ENTRY
*res
; /* Result of hsearch */
152 ENTRY
*new; /* Test entry */
156 printf("Length = %u, m = %u\n", length
, m
);
158 fprintf(stderr
, "Out of core\n");
163 printf("Enter a probe: ");
164 until(EOF
== scanf("%s", line
) || strcmp(line
, "quit") == 0);
166 printf("%s, ", line
);
167 printf("division: %d, ", hashd(line
));
168 printf("multiplication: %d\n", hashm(line
));
170 new = (ENTRY
*) malloc(sizeof (ENTRY
));
172 fprintf(stderr
, "Out of core \n");
175 new->key
= malloc((unsigned)strlen(line
) + 1);
176 if (new->key
== NULL
) {
177 fprintf(stderr
, "Out of core \n");
180 (void) strcpy(new->key
, line
);
181 new->data
= malloc(sizeof (int));
182 if (new->data
== NULL
) {
183 fprintf(stderr
, "Out of core \n");
188 res
= hsearch(*new, ENTER
);
189 printf("The number of probes required was %d\n", prcnt
);
190 if (res
== (ENTRY
*) 0)
191 printf("Table is full\n");
194 printf("Key = %s, Value = %d\n", res
->key
, *res
->data
);
197 printf("Do you wish to start another hash table (yes/no?)");
198 if (EOF
== scanf("%s", line
) || strcmp(line
, "no") == 0)
206 hcreate(size_t size
) /* Create a hash table no smaller than size */
207 /* Minimum "size" for hash table */
209 size_t unsize
; /* Holds the shifted size */
210 TABELEM
*local_table
;
212 unsigned int local_length
;
213 unsigned int local_m
;
218 unsize
= size
; /* +1 for empty table slot; -1 for ceiling */
219 local_length
= 1; /* Maximum entries in table */
220 local_m
= 0; /* Log2 length */
227 local_table
= (TABELEM
*) calloc(local_length
, sizeof (TABELEM
));
229 lmutex_lock(&table_lock
);
232 length
= local_length
;
234 lmutex_unlock(&table_lock
);
235 if (old_table
!= NULL
)
237 return (local_table
!= NULL
);
241 hdestroy(void) /* Reset the module to its initial state */
245 lmutex_lock(&table_lock
);
249 for (i
= 0; i
< length
; i
++) {
250 if (table
[i
] != (NODE
*)NULL
) {
252 while (p
!= (NODE
*)NULL
) {
256 * This is a locking vs malloc() violation.
257 * Fortunately, it is not actually compiled.
264 local_table
= (POINTER
)table
;
269 lmutex_unlock(&table_lock
);
275 * Hash search of a fixed-capacity table. Open addressing used to
276 * resolve collisions. Algorithm modified from Knuth, Volume 3,
277 * section 6.4, algorithm D. Labels flag corresponding actions.
280 /* Find or insert the item into the table */
282 *hsearch(ENTRY item
, ACTION action
)
283 /* "item" to be inserted or found */
284 /* action: FIND or ENTER */
286 unsigned int i
; /* Insertion index */
287 unsigned int c
; /* Secondary probe displacement */
289 lmutex_lock(&table_lock
);
293 i
= HASH(item
.key
); /* Primary hash on key */
296 printf("hash = %o\n", i
);
300 if (table
[i
].key
== NULL
) /* Empty slot? */
302 else if (COMPARE(table
[i
].key
, item
.key
) == 0) /* Match? */
306 c
= HASH2(item
.key
); /* No match => compute secondary hash */
309 printf("hash2 = %o\n", c
);
313 i
= (i
+ c
) % length
; /* Advance to next slot */
317 if (table
[i
].key
== NULL
) /* Empty slot? */
319 else if (COMPARE(table
[i
].key
, item
.key
) == 0) /* Match? */
324 D6
: if (action
== FIND
) /* Insert if requested */
325 RETURN((ENTRY
*) NULL
);
326 if (count
== (length
- 1)) /* Table full? */
331 * Brent's variation of the open addressing algorithm. Do extra
332 * work during insertion to speed retrieval. May require switching
333 * of previously placed items. Adapted from Knuth, Volume 3, section
334 * 4.6 and Brent's article in CACM, volume 10, #2, February 1973.
338 unsigned int p0
= HASH(item
.key
); /* First probe index */
339 unsigned int c0
= HASH2(item
.key
); /* Main branch increment */
340 unsigned int r
= prcnt
- 1; /* Current minimum distance */
341 unsigned int j
; /* Counts along main branch */
342 unsigned int k
; /* Counts along secondary branch */
343 unsigned int curj
; /* Current best main branch site */
344 unsigned int curpos
; /* Current best table index */
345 unsigned int pj
; /* Main branch indices */
346 unsigned int cj
; /* Secondary branch increment distance */
347 unsigned int pjk
; /* Secondary branch probe indices */
350 for (j
= 0; j
< prcnt
; j
++) { /* Count along main branch */
351 pj
= (p0
+ j
* c0
) % length
; /* New main branch index */
352 cj
= HASH2(table
[pj
].key
); /* Secondary branch incr. */
353 for (k
= 1; j
+k
<= r
; k
++) {
354 /* Count on secondary branch */
355 pjk
= (pj
+ k
* cj
) % length
;
356 /* Secondary probe */
357 if (table
[pjk
].key
== NULL
) {
358 /* Improvement found */
359 r
= j
+ k
; /* Decrement upper bound */
360 curj
= pj
; /* Save main probe index */
362 /* Save secondeary index */
366 if (r
!= prcnt
- 1) { /* If an improvement occurred */
367 table
[curpos
] = table
[curj
]; /* Old key to new site */
369 printf("Switch curpos = %o, curj = %o, oldi = %o\n",
377 count
++; /* Increment table occupancy count */
378 table
[i
] = item
; /* Save item */
380 lmutex_unlock(&table_lock
);
381 return (&table
[i
]); /* Address of item is returned */
392 return (strcmp(a
, b
));
395 int (* hcompar
)() = compare
;
401 #define STRCMP(A, B) (COMPARE((A), (B)) > 0)
404 #define STRCMP(A, B) (COMPARE((A), (B)) < 0)
406 #define STRCMP(A, B) (COMPARE((A), (B)) != 0)
411 *hsearch(item
, action
) /* Chained search with sorted lists */
412 ENTRY item
; /* Item to be inserted or found */
413 ACTION action
; /* FIND or ENTER */
415 NODE
*p
; /* Searches through the linked list */
416 NODE
**q
; /* Where to store the pointer to a new NODE */
417 unsigned int i
; /* Result of hash */
418 int res
; /* Result of string comparison */
420 lmutex_lock(&table_lock
);
423 i
= HASH(item
.key
); /* Table[i] contains list head */
425 if (table
[i
] == (NODE
*)NULL
) { /* List has not yet been begun */
427 RETURN((ENTRY
*) NULL
);
429 RETURN(build(&table
[i
], (NODE
*) NULL
, item
));
430 } else { /* List is not empty */
433 while (p
!= NULL
&& (res
= STRCMP(item
.key
, p
->item
.key
))) {
439 if (p
!= NULL
&& res
== 0) /* Item has been found */
441 else { /* Item is not yet on list */
443 RETURN((ENTRY
*) NULL
);
446 RETURN(build(&table
[i
], table
[i
], item
));
448 RETURN(build(q
, p
, item
));
455 *build(last
, next
, item
)
456 NODE
**last
; /* Where to store in last list item */
457 NODE
*next
; /* Link to next list item */
458 ENTRY item
; /* Item to be kept in node */
461 * This is a locking vs malloc() violation.
462 * Fortunately, it is not actually compiled.
464 NODE
*p
= (NODE
*) malloc(sizeof (NODE
));
478 hashd(key
) /* Division hashing scheme */
479 POINTER key
; /* Key to be hashed */
481 return (crunch(key
) % length
);
486 * NOTE: The following algorithm only works on machines where
487 * the results of multiplying two integers is the least
488 * significant part of the double word integer required to hold
489 * the result. It is adapted from Knuth, Volume 3, section 6.4.
493 hashm(POINTER key
) /* Multiplication hashing scheme */
494 /* "key" to be hashed */
496 return ((int)(((unsigned)(crunch(key
) * FACTOR
)) >> SHIFT
));
500 * Secondary hashing, for use with multiplicitive hashing scheme.
501 * Adapted from Knuth, Volume 3, section 6.4.
505 hash2m(POINTER key
) /* Secondary hashing routine */
506 /* "key" is the string to be hashed */
508 return (((unsigned int)((crunch(key
) * FACTOR
) << m
) >> SHIFT
) | 1);
513 /* PJ Weinberger's hash function */
515 crunch(POINTER key
) /* Convert multicharacter key to unsigned int */
519 unsigned char *p
= (unsigned char *)key
;
534 hdump() /* Dumps loc, data, probe count, key */
536 unsigned int i
; /* Counts table slots */
538 unsigned int sum
= 0; /* Counts probes */
541 NODE
*a
; /* Current Node on list */
545 for (i
= 0; i
< length
; i
++)
547 if (table
[i
].key
== NULL
)
548 printf("%o.\t-,\t-,\t(NULL)\n", i
);
550 unsigned int oldpr
= prcnt
;
551 /* Save current probe count */
553 hsearch(table
[i
], FIND
);
555 printf("%o.\t%d,\t%d,\t%s\n", i
,
556 *table
[i
].data
, prcnt
, table
[i
].key
);
559 printf("Total probes = %d\n", sum
);
562 if (table
[i
] == NULL
)
563 printf("%o.\t-,\t-,\t(NULL)\n", i
);
566 for (a
= table
[i
]; a
!= NULL
; a
= a
->next
)
567 printf("\t%d,\t%#0.4x,\t%s\n",
568 *a
->item
.data
, a
, a
->item
.key
);