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
);
236 return (local_table
!= NULL
);
240 hdestroy(void) /* Reset the module to its initial state */
244 lmutex_lock(&table_lock
);
248 for (i
= 0; i
< length
; i
++) {
249 if (table
[i
] != (NODE
*)NULL
) {
251 while (p
!= (NODE
*)NULL
) {
255 * This is a locking vs malloc() violation.
256 * Fortunately, it is not actually compiled.
263 local_table
= (POINTER
)table
;
268 lmutex_unlock(&table_lock
);
274 * Hash search of a fixed-capacity table. Open addressing used to
275 * resolve collisions. Algorithm modified from Knuth, Volume 3,
276 * section 6.4, algorithm D. Labels flag corresponding actions.
279 /* Find or insert the item into the table */
281 *hsearch(ENTRY item
, ACTION action
)
282 /* "item" to be inserted or found */
283 /* action: FIND or ENTER */
285 unsigned int i
; /* Insertion index */
286 unsigned int c
; /* Secondary probe displacement */
288 lmutex_lock(&table_lock
);
292 i
= HASH(item
.key
); /* Primary hash on key */
295 printf("hash = %o\n", i
);
299 if (table
[i
].key
== NULL
) /* Empty slot? */
301 else if (COMPARE(table
[i
].key
, item
.key
) == 0) /* Match? */
305 c
= HASH2(item
.key
); /* No match => compute secondary hash */
308 printf("hash2 = %o\n", c
);
312 i
= (i
+ c
) % length
; /* Advance to next slot */
316 if (table
[i
].key
== NULL
) /* Empty slot? */
318 else if (COMPARE(table
[i
].key
, item
.key
) == 0) /* Match? */
323 D6
: if (action
== FIND
) /* Insert if requested */
324 RETURN((ENTRY
*) NULL
);
325 if (count
== (length
- 1)) /* Table full? */
330 * Brent's variation of the open addressing algorithm. Do extra
331 * work during insertion to speed retrieval. May require switching
332 * of previously placed items. Adapted from Knuth, Volume 3, section
333 * 4.6 and Brent's article in CACM, volume 10, #2, February 1973.
337 unsigned int p0
= HASH(item
.key
); /* First probe index */
338 unsigned int c0
= HASH2(item
.key
); /* Main branch increment */
339 unsigned int r
= prcnt
- 1; /* Current minimum distance */
340 unsigned int j
; /* Counts along main branch */
341 unsigned int k
; /* Counts along secondary branch */
342 unsigned int curj
; /* Current best main branch site */
343 unsigned int curpos
; /* Current best table index */
344 unsigned int pj
; /* Main branch indices */
345 unsigned int cj
; /* Secondary branch increment distance */
346 unsigned int pjk
; /* Secondary branch probe indices */
349 for (j
= 0; j
< prcnt
; j
++) { /* Count along main branch */
350 pj
= (p0
+ j
* c0
) % length
; /* New main branch index */
351 cj
= HASH2(table
[pj
].key
); /* Secondary branch incr. */
352 for (k
= 1; j
+k
<= r
; k
++) {
353 /* Count on secondary branch */
354 pjk
= (pj
+ k
* cj
) % length
;
355 /* Secondary probe */
356 if (table
[pjk
].key
== NULL
) {
357 /* Improvement found */
358 r
= j
+ k
; /* Decrement upper bound */
359 curj
= pj
; /* Save main probe index */
361 /* Save secondeary index */
365 if (r
!= prcnt
- 1) { /* If an improvement occurred */
366 table
[curpos
] = table
[curj
]; /* Old key to new site */
368 printf("Switch curpos = %o, curj = %o, oldi = %o\n",
376 count
++; /* Increment table occupancy count */
377 table
[i
] = item
; /* Save item */
379 lmutex_unlock(&table_lock
);
380 return (&table
[i
]); /* Address of item is returned */
391 return (strcmp(a
, b
));
394 int (* hcompar
)() = compare
;
400 #define STRCMP(A, B) (COMPARE((A), (B)) > 0)
403 #define STRCMP(A, B) (COMPARE((A), (B)) < 0)
405 #define STRCMP(A, B) (COMPARE((A), (B)) != 0)
410 *hsearch(item
, action
) /* Chained search with sorted lists */
411 ENTRY item
; /* Item to be inserted or found */
412 ACTION action
; /* FIND or ENTER */
414 NODE
*p
; /* Searches through the linked list */
415 NODE
**q
; /* Where to store the pointer to a new NODE */
416 unsigned int i
; /* Result of hash */
417 int res
; /* Result of string comparison */
419 lmutex_lock(&table_lock
);
422 i
= HASH(item
.key
); /* Table[i] contains list head */
424 if (table
[i
] == (NODE
*)NULL
) { /* List has not yet been begun */
426 RETURN((ENTRY
*) NULL
);
428 RETURN(build(&table
[i
], (NODE
*) NULL
, item
));
429 } else { /* List is not empty */
432 while (p
!= NULL
&& (res
= STRCMP(item
.key
, p
->item
.key
))) {
438 if (p
!= NULL
&& res
== 0) /* Item has been found */
440 else { /* Item is not yet on list */
442 RETURN((ENTRY
*) NULL
);
445 RETURN(build(&table
[i
], table
[i
], item
));
447 RETURN(build(q
, p
, item
));
454 *build(last
, next
, item
)
455 NODE
**last
; /* Where to store in last list item */
456 NODE
*next
; /* Link to next list item */
457 ENTRY item
; /* Item to be kept in node */
460 * This is a locking vs malloc() violation.
461 * Fortunately, it is not actually compiled.
463 NODE
*p
= (NODE
*) malloc(sizeof (NODE
));
477 hashd(key
) /* Division hashing scheme */
478 POINTER key
; /* Key to be hashed */
480 return (crunch(key
) % length
);
485 * NOTE: The following algorithm only works on machines where
486 * the results of multiplying two integers is the least
487 * significant part of the double word integer required to hold
488 * the result. It is adapted from Knuth, Volume 3, section 6.4.
492 hashm(POINTER key
) /* Multiplication hashing scheme */
493 /* "key" to be hashed */
495 return ((int)(((unsigned)(crunch(key
) * FACTOR
)) >> SHIFT
));
499 * Secondary hashing, for use with multiplicitive hashing scheme.
500 * Adapted from Knuth, Volume 3, section 6.4.
504 hash2m(POINTER key
) /* Secondary hashing routine */
505 /* "key" is the string to be hashed */
507 return (((unsigned int)((crunch(key
) * FACTOR
) << m
) >> SHIFT
) | 1);
512 /* PJ Weinberger's hash function */
514 crunch(POINTER key
) /* Convert multicharacter key to unsigned int */
518 unsigned char *p
= (unsigned char *)key
;
533 hdump() /* Dumps loc, data, probe count, key */
535 unsigned int i
; /* Counts table slots */
537 unsigned int sum
= 0; /* Counts probes */
540 NODE
*a
; /* Current Node on list */
544 for (i
= 0; i
< length
; i
++)
546 if (table
[i
].key
== NULL
)
547 printf("%o.\t-,\t-,\t(NULL)\n", i
);
549 unsigned int oldpr
= prcnt
;
550 /* Save current probe count */
552 hsearch(table
[i
], FIND
);
554 printf("%o.\t%d,\t%d,\t%s\n", i
,
555 *table
[i
].data
, prcnt
, table
[i
].key
);
558 printf("Total probes = %d\n", sum
);
561 if (table
[i
] == NULL
)
562 printf("%o.\t-,\t-,\t(NULL)\n", i
);
565 for (a
= table
[i
]; a
!= NULL
; a
= a
->next
)
566 printf("\t%d,\t%#0.4x,\t%s\n",
567 *a
->item
.data
, a
, a
->item
.key
);