xref: /onnv-gate/usr/src/lib/libc/port/gen/hsearch.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
30*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
31*0Sstevel@tonic-gate 
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate  * Compile time switches:
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  *  MULT - use a multiplicative hashing function.
37*0Sstevel@tonic-gate  *  DIV - use the remainder mod table size as a hashing function.
38*0Sstevel@tonic-gate  *  CHAINED - use a linked list to resolve collisions.
39*0Sstevel@tonic-gate  *  OPEN - use open addressing to resolve collisions.
40*0Sstevel@tonic-gate  *  BRENT - use Brent's modification to improve the OPEN algorithm.
41*0Sstevel@tonic-gate  *  SORTUP - CHAINED list is sorted in increasing order.
42*0Sstevel@tonic-gate  *  SORTDOWN - CHAINED list is sorted in decreasing order.
43*0Sstevel@tonic-gate  *  START - CHAINED list with entries appended at front.
44*0Sstevel@tonic-gate  *  DRIVER - compile in a main program to drive the tests.
45*0Sstevel@tonic-gate  *  DEBUG - compile some debugging printout statements.
46*0Sstevel@tonic-gate  *  USCR - user supplied comparison routine.
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #pragma weak hcreate = _hcreate
50*0Sstevel@tonic-gate #pragma weak hdestroy = _hdestroy
51*0Sstevel@tonic-gate #pragma weak hsearch = _hsearch
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate #include "synonyms.h"
54*0Sstevel@tonic-gate #include <mtlib.h>
55*0Sstevel@tonic-gate #include <limits.h>
56*0Sstevel@tonic-gate #include <stdio.h>
57*0Sstevel@tonic-gate #include <stdlib.h>
58*0Sstevel@tonic-gate #include <string.h>
59*0Sstevel@tonic-gate #include <thread.h>
60*0Sstevel@tonic-gate #include <synch.h>
61*0Sstevel@tonic-gate #include <search.h>
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate typedef char *POINTER;
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #define	SUCCEED		0
66*0Sstevel@tonic-gate #define	FAIL		1
67*0Sstevel@tonic-gate #define	TRUE		1
68*0Sstevel@tonic-gate #define	FALSE		0
69*0Sstevel@tonic-gate #define	repeat		for (;;)
70*0Sstevel@tonic-gate #define	until(A)	if (A) break;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate #ifdef OPEN
73*0Sstevel@tonic-gate #undef CHAINED
74*0Sstevel@tonic-gate #else
75*0Sstevel@tonic-gate #ifndef CHAINED
76*0Sstevel@tonic-gate #define	OPEN
77*0Sstevel@tonic-gate #endif
78*0Sstevel@tonic-gate #endif
79*0Sstevel@tonic-gate 
80*0Sstevel@tonic-gate #ifdef MULT
81*0Sstevel@tonic-gate #undef DIV
82*0Sstevel@tonic-gate #else
83*0Sstevel@tonic-gate #ifndef DIV
84*0Sstevel@tonic-gate #define	MULT
85*0Sstevel@tonic-gate #endif
86*0Sstevel@tonic-gate #endif
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate #ifdef START
89*0Sstevel@tonic-gate #undef SORTUP
90*0Sstevel@tonic-gate #undef SORTDOWN
91*0Sstevel@tonic-gate #else
92*0Sstevel@tonic-gate #ifdef SORTUP
93*0Sstevel@tonic-gate #undef SORTDOWN
94*0Sstevel@tonic-gate #endif
95*0Sstevel@tonic-gate #endif
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate #ifdef USCR
98*0Sstevel@tonic-gate #define	COMPARE(A, B) (* hcompar)((A), (B))
99*0Sstevel@tonic-gate extern int (* hcompar)();
100*0Sstevel@tonic-gate #else
101*0Sstevel@tonic-gate #define	COMPARE(A, B) strcmp((A), (B))
102*0Sstevel@tonic-gate #endif
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate #ifdef MULT
105*0Sstevel@tonic-gate #define	SHIFT ((CHAR_BIT * sizeof (int)) - m) /* Shift factor */
106*0Sstevel@tonic-gate #define	FACTOR 035761254233	/* Magic multiplication factor */
107*0Sstevel@tonic-gate #define	HASH hashm		/* Multiplicative hash function */
108*0Sstevel@tonic-gate #define	HASH2 hash2m	/* Secondary hash function */
109*0Sstevel@tonic-gate static unsigned int hashm(POINTER);
110*0Sstevel@tonic-gate static unsigned int hash2m(POINTER);
111*0Sstevel@tonic-gate #else
112*0Sstevel@tonic-gate #ifdef DIV
113*0Sstevel@tonic-gate #define	HASH hashd		/* Division hashing routine */
114*0Sstevel@tonic-gate #define	HASH2(A) 1		/* Secondary hash function */
115*0Sstevel@tonic-gate static unsigned int hashd();
116*0Sstevel@tonic-gate #endif
117*0Sstevel@tonic-gate #endif
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate #ifdef CHAINED
120*0Sstevel@tonic-gate typedef struct node {	/* Part of the linked list of entries */
121*0Sstevel@tonic-gate 	ENTRY item;
122*0Sstevel@tonic-gate 	struct node *next;
123*0Sstevel@tonic-gate } NODE;
124*0Sstevel@tonic-gate typedef NODE *TABELEM;
125*0Sstevel@tonic-gate static NODE **table;	/* The address of the hash table */
126*0Sstevel@tonic-gate static ENTRY *build();
127*0Sstevel@tonic-gate #else
128*0Sstevel@tonic-gate #ifdef OPEN
129*0Sstevel@tonic-gate typedef ENTRY TABELEM;	/* What the table contains (TABle ELEMents) */
130*0Sstevel@tonic-gate static TABELEM *table;	/* The address of the hash table */
131*0Sstevel@tonic-gate static unsigned int count = 0;	/* Number of entries in hash table */
132*0Sstevel@tonic-gate #endif
133*0Sstevel@tonic-gate #endif
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate static unsigned int length;	/* Size of the hash table */
136*0Sstevel@tonic-gate static unsigned int m;		/* Log base 2 of length */
137*0Sstevel@tonic-gate static unsigned int prcnt;	/* Number of probes this item */
138*0Sstevel@tonic-gate static mutex_t table_lock = DEFAULTMUTEX;
139*0Sstevel@tonic-gate #define	RETURN(n)    { lmutex_unlock(&table_lock); return (n); }
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate /*
142*0Sstevel@tonic-gate  * forward declarations
143*0Sstevel@tonic-gate  */
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate static unsigned int crunch(POINTER);
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate #ifdef DRIVER
148*0Sstevel@tonic-gate static void hdump();
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate main()
151*0Sstevel@tonic-gate {
152*0Sstevel@tonic-gate 	char line[80];	/* Room for the input line */
153*0Sstevel@tonic-gate 	int i = 0;		/* Data generator */
154*0Sstevel@tonic-gate 	ENTRY *res;		/* Result of hsearch */
155*0Sstevel@tonic-gate 	ENTRY *new;		/* Test entry */
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate start:
158*0Sstevel@tonic-gate 	if (hcreate(5))
159*0Sstevel@tonic-gate 		printf("Length = %u, m = %u\n", length, m);
160*0Sstevel@tonic-gate 	else {
161*0Sstevel@tonic-gate 		fprintf(stderr, "Out of core\n");
162*0Sstevel@tonic-gate 		exit(FAIL);
163*0Sstevel@tonic-gate 	}
164*0Sstevel@tonic-gate 	repeat {
165*0Sstevel@tonic-gate 	hdump();
166*0Sstevel@tonic-gate 	printf("Enter a probe: ");
167*0Sstevel@tonic-gate 	until(EOF == scanf("%s", line) || strcmp(line, "quit") == 0);
168*0Sstevel@tonic-gate #ifdef DEBUG
169*0Sstevel@tonic-gate 	printf("%s, ", line);
170*0Sstevel@tonic-gate 	printf("division: %d, ", hashd(line));
171*0Sstevel@tonic-gate 	printf("multiplication: %d\n", hashm(line));
172*0Sstevel@tonic-gate #endif
173*0Sstevel@tonic-gate 	new = (ENTRY *) malloc(sizeof (ENTRY));
174*0Sstevel@tonic-gate 	if (new == NULL) {
175*0Sstevel@tonic-gate 	    fprintf(stderr, "Out of core \n");
176*0Sstevel@tonic-gate 	    exit(FAIL);
177*0Sstevel@tonic-gate 	} else {
178*0Sstevel@tonic-gate 	    new->key = malloc((unsigned)strlen(line) + 1);
179*0Sstevel@tonic-gate 	    if (new->key == NULL) {
180*0Sstevel@tonic-gate 		fprintf(stderr, "Out of core \n");
181*0Sstevel@tonic-gate 		exit(FAIL);
182*0Sstevel@tonic-gate 	    }
183*0Sstevel@tonic-gate 	    strcpy(new->key, line);
184*0Sstevel@tonic-gate 	    new->data = malloc(sizeof (int));
185*0Sstevel@tonic-gate 	    if (new->data == NULL) {
186*0Sstevel@tonic-gate 		fprintf(stderr, "Out of core \n");
187*0Sstevel@tonic-gate 		exit(FAIL);
188*0Sstevel@tonic-gate 	    }
189*0Sstevel@tonic-gate 	    *new->data = i++;
190*0Sstevel@tonic-gate 	}
191*0Sstevel@tonic-gate 	res = hsearch(*new, ENTER);
192*0Sstevel@tonic-gate 	printf("The number of probes required was %d\n", prcnt);
193*0Sstevel@tonic-gate 	if (res == (ENTRY *) 0)
194*0Sstevel@tonic-gate 	    printf("Table is full\n");
195*0Sstevel@tonic-gate 	else {
196*0Sstevel@tonic-gate 	    printf("Success: ");
197*0Sstevel@tonic-gate 	    printf("Key = %s, Value = %d\n", res->key, *res->data);
198*0Sstevel@tonic-gate 	}
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 	printf("Do you wish to start another hash table (yes/no?)");
201*0Sstevel@tonic-gate 	if (EOF == scanf("%s", line) || strcmp(line, "no") == 0)
202*0Sstevel@tonic-gate 		exit(SUCCEED);
203*0Sstevel@tonic-gate 	hdestroy();
204*0Sstevel@tonic-gate 	goto start;
205*0Sstevel@tonic-gate }
206*0Sstevel@tonic-gate #endif
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate int
209*0Sstevel@tonic-gate hcreate(size_t size)	/* Create a hash table no smaller than size */
210*0Sstevel@tonic-gate 	/* Minimum "size" for hash table */
211*0Sstevel@tonic-gate {
212*0Sstevel@tonic-gate 	size_t unsize;	/* Holds the shifted size */
213*0Sstevel@tonic-gate 	TABELEM *local_table;
214*0Sstevel@tonic-gate 	TABELEM *old_table;
215*0Sstevel@tonic-gate 	unsigned int local_length;
216*0Sstevel@tonic-gate 	unsigned int local_m;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	if (size == 0)
219*0Sstevel@tonic-gate 		return (FALSE);
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 	unsize = size;	/* +1 for empty table slot; -1 for ceiling */
222*0Sstevel@tonic-gate 	local_length = 1;	/* Maximum entries in table */
223*0Sstevel@tonic-gate 	local_m = 0;		/* Log2 length */
224*0Sstevel@tonic-gate 	while (unsize) {
225*0Sstevel@tonic-gate 		unsize >>= 1;
226*0Sstevel@tonic-gate 		local_length <<= 1;
227*0Sstevel@tonic-gate 		local_m++;
228*0Sstevel@tonic-gate 	}
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	local_table = (TABELEM *) calloc(local_length, sizeof (TABELEM));
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	lmutex_lock(&table_lock);
233*0Sstevel@tonic-gate 	old_table = table;
234*0Sstevel@tonic-gate 	table = local_table;
235*0Sstevel@tonic-gate 	length = local_length;
236*0Sstevel@tonic-gate 	m = local_m;
237*0Sstevel@tonic-gate 	lmutex_unlock(&table_lock);
238*0Sstevel@tonic-gate 	if (old_table != NULL)
239*0Sstevel@tonic-gate 		free(old_table);
240*0Sstevel@tonic-gate 	return (local_table != NULL);
241*0Sstevel@tonic-gate }
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate void
244*0Sstevel@tonic-gate hdestroy(void)	/* Reset the module to its initial state */
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate 	POINTER local_table;
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	lmutex_lock(&table_lock);
249*0Sstevel@tonic-gate #ifdef CHAINED
250*0Sstevel@tonic-gate 	int i;
251*0Sstevel@tonic-gate 	NODE *p, *oldp;
252*0Sstevel@tonic-gate 	for (i = 0; i < length; i++) {
253*0Sstevel@tonic-gate 		if (table[i] != (NODE *)NULL) {
254*0Sstevel@tonic-gate 			p = table[i];
255*0Sstevel@tonic-gate 			while (p != (NODE *)NULL) {
256*0Sstevel@tonic-gate 				oldp = p;
257*0Sstevel@tonic-gate 				p = p -> next;
258*0Sstevel@tonic-gate 				/*
259*0Sstevel@tonic-gate 				 * This is a locking vs malloc() violation.
260*0Sstevel@tonic-gate 				 * Fortunately, it is not actually compiled.
261*0Sstevel@tonic-gate 				 */
262*0Sstevel@tonic-gate 				free(oldp);
263*0Sstevel@tonic-gate 			}
264*0Sstevel@tonic-gate 		}
265*0Sstevel@tonic-gate 	}
266*0Sstevel@tonic-gate #endif
267*0Sstevel@tonic-gate 	local_table = (POINTER)table;
268*0Sstevel@tonic-gate 	table = 0;
269*0Sstevel@tonic-gate #ifdef OPEN
270*0Sstevel@tonic-gate 	count = 0;
271*0Sstevel@tonic-gate #endif
272*0Sstevel@tonic-gate 	lmutex_unlock(&table_lock);
273*0Sstevel@tonic-gate 	free(local_table);
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate 
276*0Sstevel@tonic-gate #ifdef OPEN
277*0Sstevel@tonic-gate /*
278*0Sstevel@tonic-gate  * Hash search of a fixed-capacity table.  Open addressing used to
279*0Sstevel@tonic-gate  *  resolve collisions.  Algorithm modified from Knuth, Volume 3,
280*0Sstevel@tonic-gate  *  section 6.4, algorithm D.  Labels flag corresponding actions.
281*0Sstevel@tonic-gate  */
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate /* Find or insert the item into the table */
284*0Sstevel@tonic-gate ENTRY
285*0Sstevel@tonic-gate *hsearch(ENTRY item, ACTION action)
286*0Sstevel@tonic-gate 	/* "item" to be inserted or found */
287*0Sstevel@tonic-gate 	/* action: FIND or ENTER */
288*0Sstevel@tonic-gate {
289*0Sstevel@tonic-gate 	unsigned int i;	/* Insertion index */
290*0Sstevel@tonic-gate 	unsigned int c;	/* Secondary probe displacement */
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate 	lmutex_lock(&table_lock);
293*0Sstevel@tonic-gate 	prcnt = 1;
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate /* D1: */
296*0Sstevel@tonic-gate 	i = HASH(item.key);	/* Primary hash on key */
297*0Sstevel@tonic-gate #ifdef DEBUG
298*0Sstevel@tonic-gate 	if (action == ENTER)
299*0Sstevel@tonic-gate 		printf("hash = %o\n", i);
300*0Sstevel@tonic-gate #endif
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate /* D2: */
303*0Sstevel@tonic-gate 	if (table[i].key == NULL)	/* Empty slot? */
304*0Sstevel@tonic-gate 		goto D6;
305*0Sstevel@tonic-gate 	else if (COMPARE(table[i].key, item.key) == 0)	/* Match? */
306*0Sstevel@tonic-gate 		RETURN(&table[i]);
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate /* D3: */
309*0Sstevel@tonic-gate 	c = HASH2(item.key);	/* No match => compute secondary hash */
310*0Sstevel@tonic-gate #ifdef DEBUG
311*0Sstevel@tonic-gate 	if (action == ENTER)
312*0Sstevel@tonic-gate 		printf("hash2 = %o\n", c);
313*0Sstevel@tonic-gate #endif
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate D4:
316*0Sstevel@tonic-gate 	i = (i + c) % length;	/* Advance to next slot */
317*0Sstevel@tonic-gate 	prcnt++;
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate /* D5: */
320*0Sstevel@tonic-gate 	if (table[i].key == NULL)	/* Empty slot? */
321*0Sstevel@tonic-gate 		goto D6;
322*0Sstevel@tonic-gate 	else if (COMPARE(table[i].key, item.key) == 0)	/* Match? */
323*0Sstevel@tonic-gate 		RETURN(&table[i])
324*0Sstevel@tonic-gate 	else
325*0Sstevel@tonic-gate 		goto D4;
326*0Sstevel@tonic-gate 
327*0Sstevel@tonic-gate D6:	if (action == FIND)		/* Insert if requested */
328*0Sstevel@tonic-gate 		RETURN((ENTRY *) NULL);
329*0Sstevel@tonic-gate 	if (count == (length - 1))	/* Table full? */
330*0Sstevel@tonic-gate 		RETURN((ENTRY *) 0);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate #ifdef BRENT
333*0Sstevel@tonic-gate /*
334*0Sstevel@tonic-gate  * Brent's variation of the open addressing algorithm.  Do extra
335*0Sstevel@tonic-gate  * work during insertion to speed retrieval.  May require switching
336*0Sstevel@tonic-gate  * of previously placed items.  Adapted from Knuth, Volume 3, section
337*0Sstevel@tonic-gate  * 4.6 and Brent's article in CACM, volume 10, #2, February 1973.
338*0Sstevel@tonic-gate  */
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	{
341*0Sstevel@tonic-gate 	unsigned int p0 = HASH(item.key);   /* First probe index */
342*0Sstevel@tonic-gate 	unsigned int c0 = HASH2(item.key);  /* Main branch increment */
343*0Sstevel@tonic-gate 	unsigned int r = prcnt - 1; /* Current minimum distance */
344*0Sstevel@tonic-gate 	unsigned int j;		/* Counts along main branch */
345*0Sstevel@tonic-gate 	unsigned int k;		/* Counts along secondary branch */
346*0Sstevel@tonic-gate 	unsigned int curj;	/* Current best main branch site */
347*0Sstevel@tonic-gate 	unsigned int curpos;	/* Current best table index */
348*0Sstevel@tonic-gate 	unsigned int pj;	/* Main branch indices */
349*0Sstevel@tonic-gate 	unsigned int cj;	/* Secondary branch increment distance */
350*0Sstevel@tonic-gate 	unsigned int pjk;	/* Secondary branch probe indices */
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	if (prcnt >= 3) {
353*0Sstevel@tonic-gate 		for (j = 0; j < prcnt; j++) {   /* Count along main branch */
354*0Sstevel@tonic-gate 			pj = (p0 + j * c0) % length; /* New main branch index */
355*0Sstevel@tonic-gate 			cj = HASH2(table[pj].key); /* Secondary branch incr. */
356*0Sstevel@tonic-gate 			for (k = 1; j+k <= r; k++) {
357*0Sstevel@tonic-gate 					/* Count on secondary branch */
358*0Sstevel@tonic-gate 				pjk = (pj + k * cj) % length;
359*0Sstevel@tonic-gate 					/* Secondary probe */
360*0Sstevel@tonic-gate 				if (table[pjk].key == NULL) {
361*0Sstevel@tonic-gate 					/* Improvement found */
362*0Sstevel@tonic-gate 					r = j + k; /* Decrement upper bound */
363*0Sstevel@tonic-gate 					curj = pj; /* Save main probe index */
364*0Sstevel@tonic-gate 					curpos = pjk;
365*0Sstevel@tonic-gate 						/* Save secondeary index */
366*0Sstevel@tonic-gate 				}
367*0Sstevel@tonic-gate 			}
368*0Sstevel@tonic-gate 		}
369*0Sstevel@tonic-gate 		if (r != prcnt - 1) {	/* If an improvement occurred */
370*0Sstevel@tonic-gate 			table[curpos] = table[curj]; /* Old key to new site */
371*0Sstevel@tonic-gate #ifdef DEBUG
372*0Sstevel@tonic-gate 			printf("Switch curpos = %o, curj = %o, oldi = %o\n",
373*0Sstevel@tonic-gate 				curj, curpos, i);
374*0Sstevel@tonic-gate #endif
375*0Sstevel@tonic-gate 			i = curj;
376*0Sstevel@tonic-gate 		}
377*0Sstevel@tonic-gate 	}
378*0Sstevel@tonic-gate 	}
379*0Sstevel@tonic-gate #endif
380*0Sstevel@tonic-gate 	count++;			/* Increment table occupancy count */
381*0Sstevel@tonic-gate 	table[i] = item;		/* Save item */
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 	lmutex_unlock(&table_lock);
384*0Sstevel@tonic-gate 	return (&table[i]);		/* Address of item is returned */
385*0Sstevel@tonic-gate }
386*0Sstevel@tonic-gate #endif
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate #ifdef USCR
389*0Sstevel@tonic-gate #ifdef DRIVER
390*0Sstevel@tonic-gate static int
391*0Sstevel@tonic-gate compare(a, b)
392*0Sstevel@tonic-gate POINTER a;
393*0Sstevel@tonic-gate POINTER b;
394*0Sstevel@tonic-gate {
395*0Sstevel@tonic-gate     return (strcmp(a, b));
396*0Sstevel@tonic-gate }
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate int (* hcompar)() = compare;
399*0Sstevel@tonic-gate #endif
400*0Sstevel@tonic-gate #endif
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate #ifdef CHAINED
403*0Sstevel@tonic-gate #ifdef SORTUP
404*0Sstevel@tonic-gate #define	STRCMP(A, B) (COMPARE((A), (B)) > 0)
405*0Sstevel@tonic-gate #else
406*0Sstevel@tonic-gate #ifdef SORTDOWN
407*0Sstevel@tonic-gate #define	STRCMP(A, B) (COMPARE((A), (B)) < 0)
408*0Sstevel@tonic-gate #else
409*0Sstevel@tonic-gate #define	STRCMP(A, B) (COMPARE((A), (B)) != 0)
410*0Sstevel@tonic-gate #endif
411*0Sstevel@tonic-gate #endif
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate ENTRY
414*0Sstevel@tonic-gate *hsearch(item, action)	/* Chained search with sorted lists */
415*0Sstevel@tonic-gate ENTRY item;		/* Item to be inserted or found */
416*0Sstevel@tonic-gate ACTION action;		/* FIND or ENTER */
417*0Sstevel@tonic-gate {
418*0Sstevel@tonic-gate 	NODE *p;		/* Searches through the linked list */
419*0Sstevel@tonic-gate 	NODE **q;		/* Where to store the pointer to a new NODE */
420*0Sstevel@tonic-gate 	unsigned int i;		/* Result of hash */
421*0Sstevel@tonic-gate 	int res;		/* Result of string comparison */
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	lmutex_lock(&table_lock);
424*0Sstevel@tonic-gate 	prcnt = 1;
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	i = HASH(item.key);	/* Table[i] contains list head */
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate 	if (table[i] == (NODE*)NULL) { /* List has not yet been begun */
429*0Sstevel@tonic-gate 		if (action == FIND)
430*0Sstevel@tonic-gate 			RETURN((ENTRY *) NULL);
431*0Sstevel@tonic-gate 		else
432*0Sstevel@tonic-gate 			RETURN(build(&table[i], (NODE *) NULL, item));
433*0Sstevel@tonic-gate 	} else {		/* List is not empty */
434*0Sstevel@tonic-gate 		q = &table[i];
435*0Sstevel@tonic-gate 		p = table[i];
436*0Sstevel@tonic-gate 		while (p != NULL && (res = STRCMP(item.key, p->item.key))) {
437*0Sstevel@tonic-gate 			prcnt++;
438*0Sstevel@tonic-gate 			q = &(p->next);
439*0Sstevel@tonic-gate 			p = p->next;
440*0Sstevel@tonic-gate 		}
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 		if (p != NULL && res == 0)	/* Item has been found */
443*0Sstevel@tonic-gate 			RETURN(&(p->item));
444*0Sstevel@tonic-gate 		else {			/* Item is not yet on list */
445*0Sstevel@tonic-gate 			if (action == FIND)
446*0Sstevel@tonic-gate 				RETURN((ENTRY *) NULL);
447*0Sstevel@tonic-gate 			else
448*0Sstevel@tonic-gate #ifdef START
449*0Sstevel@tonic-gate 				RETURN(build(&table[i], table[i], item));
450*0Sstevel@tonic-gate #else
451*0Sstevel@tonic-gate 				RETURN(build(q, p, item));
452*0Sstevel@tonic-gate #endif
453*0Sstevel@tonic-gate 		}
454*0Sstevel@tonic-gate 	}
455*0Sstevel@tonic-gate }
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate static ENTRY
458*0Sstevel@tonic-gate *build(last, next, item)
459*0Sstevel@tonic-gate NODE **last;		/* Where to store in last list item */
460*0Sstevel@tonic-gate NODE *next;		/* Link to next list item */
461*0Sstevel@tonic-gate ENTRY item;		/* Item to be kept in node */
462*0Sstevel@tonic-gate {
463*0Sstevel@tonic-gate 	/*
464*0Sstevel@tonic-gate 	 * This is a locking vs malloc() violation.
465*0Sstevel@tonic-gate 	 * Fortunately, it is not actually compiled.
466*0Sstevel@tonic-gate 	 */
467*0Sstevel@tonic-gate 	NODE *p = (NODE *) malloc(sizeof (NODE));
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	if (p != NULL) {
470*0Sstevel@tonic-gate 		p->item = item;
471*0Sstevel@tonic-gate 		*last = p;
472*0Sstevel@tonic-gate 		p->next = next;
473*0Sstevel@tonic-gate 		return (&(p->item));
474*0Sstevel@tonic-gate 	} else
475*0Sstevel@tonic-gate 		return (NULL);
476*0Sstevel@tonic-gate }
477*0Sstevel@tonic-gate #endif
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate #ifdef DIV
480*0Sstevel@tonic-gate static unsigned int
481*0Sstevel@tonic-gate hashd(key)		/* Division hashing scheme */
482*0Sstevel@tonic-gate POINTER key;		/* Key to be hashed */
483*0Sstevel@tonic-gate {
484*0Sstevel@tonic-gate     return (crunch(key) % length);
485*0Sstevel@tonic-gate }
486*0Sstevel@tonic-gate #else
487*0Sstevel@tonic-gate #ifdef MULT
488*0Sstevel@tonic-gate /*
489*0Sstevel@tonic-gate  *  NOTE: The following algorithm only works on machines where
490*0Sstevel@tonic-gate  *  the results of multiplying two integers is the least
491*0Sstevel@tonic-gate  *  significant part of the double word integer required to hold
492*0Sstevel@tonic-gate  *  the result.  It is adapted from Knuth, Volume 3, section 6.4.
493*0Sstevel@tonic-gate  */
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate static unsigned int
496*0Sstevel@tonic-gate hashm(POINTER key)	/* Multiplication hashing scheme */
497*0Sstevel@tonic-gate 	/* "key" to be hashed */
498*0Sstevel@tonic-gate {
499*0Sstevel@tonic-gate 	return ((int)(((unsigned)(crunch(key) * FACTOR)) >> SHIFT));
500*0Sstevel@tonic-gate }
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate /*
503*0Sstevel@tonic-gate  * Secondary hashing, for use with multiplicitive hashing scheme.
504*0Sstevel@tonic-gate  * Adapted from Knuth, Volume 3, section 6.4.
505*0Sstevel@tonic-gate  */
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate static unsigned int
508*0Sstevel@tonic-gate hash2m(POINTER key)	/* Secondary hashing routine */
509*0Sstevel@tonic-gate 	/* "key" is the string to be hashed */
510*0Sstevel@tonic-gate {
511*0Sstevel@tonic-gate     return (((unsigned int)((crunch(key) * FACTOR) << m) >> SHIFT) | 1);
512*0Sstevel@tonic-gate }
513*0Sstevel@tonic-gate #endif
514*0Sstevel@tonic-gate #endif
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate /* PJ Weinberger's hash function */
517*0Sstevel@tonic-gate static unsigned int
518*0Sstevel@tonic-gate crunch(POINTER key)	/* Convert multicharacter key to unsigned int */
519*0Sstevel@tonic-gate {
520*0Sstevel@tonic-gate 	unsigned int h = 0;
521*0Sstevel@tonic-gate 	unsigned int g;
522*0Sstevel@tonic-gate 	unsigned char *p = (unsigned char *)key;
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	for (; *p; p++) {
525*0Sstevel@tonic-gate 		h = (h << 4) + *p;
526*0Sstevel@tonic-gate 		g = h & 0xf0000000;
527*0Sstevel@tonic-gate 		if (g != 0) {
528*0Sstevel@tonic-gate 			h ^= (g >> 24);
529*0Sstevel@tonic-gate 			h ^= g;
530*0Sstevel@tonic-gate 		}
531*0Sstevel@tonic-gate 	}
532*0Sstevel@tonic-gate 	return (h);
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate #ifdef DRIVER
536*0Sstevel@tonic-gate static void
537*0Sstevel@tonic-gate hdump()			/* Dumps loc, data, probe count, key */
538*0Sstevel@tonic-gate {
539*0Sstevel@tonic-gate 	unsigned int i;	/* Counts table slots */
540*0Sstevel@tonic-gate #ifdef OPEN
541*0Sstevel@tonic-gate 	unsigned int sum = 0;	/* Counts probes */
542*0Sstevel@tonic-gate #else
543*0Sstevel@tonic-gate #ifdef CHAINED
544*0Sstevel@tonic-gate 	NODE *a;		/* Current Node on list */
545*0Sstevel@tonic-gate #endif
546*0Sstevel@tonic-gate #endif
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	for (i = 0; i < length; i++)
549*0Sstevel@tonic-gate #ifdef OPEN
550*0Sstevel@tonic-gate 		if (table[i].key == NULL)
551*0Sstevel@tonic-gate 			printf("%o.\t-,\t-,\t(NULL)\n", i);
552*0Sstevel@tonic-gate 		else {
553*0Sstevel@tonic-gate 			unsigned int oldpr = prcnt;
554*0Sstevel@tonic-gate 				/* Save current probe count */
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 			hsearch(table[i], FIND);
557*0Sstevel@tonic-gate 			sum += prcnt;
558*0Sstevel@tonic-gate 			printf("%o.\t%d,\t%d,\t%s\n", i,
559*0Sstevel@tonic-gate 				*table[i].data, prcnt, table[i].key);
560*0Sstevel@tonic-gate 			prcnt = oldpr;
561*0Sstevel@tonic-gate 		}
562*0Sstevel@tonic-gate 	printf("Total probes = %d\n", sum);
563*0Sstevel@tonic-gate #else
564*0Sstevel@tonic-gate #ifdef CHAINED
565*0Sstevel@tonic-gate 	if (table[i] == NULL)
566*0Sstevel@tonic-gate 	    printf("%o.\t-,\t-,\t(NULL)\n", i);
567*0Sstevel@tonic-gate 	else {
568*0Sstevel@tonic-gate 	    printf("%o.", i);
569*0Sstevel@tonic-gate 	    for (a = table[i]; a != NULL; a = a->next)
570*0Sstevel@tonic-gate 		printf("\t%d,\t%#0.4x,\t%s\n",
571*0Sstevel@tonic-gate 		    *a->item.data, a, a->item.key);
572*0Sstevel@tonic-gate 	}
573*0Sstevel@tonic-gate #endif
574*0Sstevel@tonic-gate #endif
575*0Sstevel@tonic-gate }
576*0Sstevel@tonic-gate #endif
577