xref: /onnv-gate/usr/src/lib/libast/common/hash/hashlook.c (revision 4887:feebf9260c2e)
1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
18*4887Schin *                  David Korn <dgk@research.att.com>                   *
19*4887Schin *                   Phong Vo <kpv@research.att.com>                    *
20*4887Schin *                                                                      *
21*4887Schin ***********************************************************************/
22*4887Schin #pragma prototyped
23*4887Schin /*
24*4887Schin  * Glenn Fowler
25*4887Schin  * AT&T Research
26*4887Schin  *
27*4887Schin  * hash table library
28*4887Schin  */
29*4887Schin 
30*4887Schin #include "hashlib.h"
31*4887Schin 
32*4887Schin /*
33*4887Schin  * hash table lookup
34*4887Schin  */
35*4887Schin 
36*4887Schin char*
37*4887Schin hashlook(register Hash_table_t* tab, const char* name, long flags, const char* value)
38*4887Schin {
39*4887Schin 	register Hash_bucket_t*	b;
40*4887Schin 	register unsigned int	n;
41*4887Schin 	register Hash_last_t*	last;
42*4887Schin 	Hash_table_t*		top;
43*4887Schin 	Hash_bucket_t*		prev;
44*4887Schin 	unsigned int		i;
45*4887Schin 
46*4887Schin 	if ((flags & (HASH_LOOKUP|HASH_INTERNAL)) == (HASH_LOOKUP|HASH_INTERNAL))
47*4887Schin 	{
48*4887Schin 		register char*		s1;
49*4887Schin 		register const char*	s2;
50*4887Schin 		register int		c;
51*4887Schin 
52*4887Schin 		if (flags & HASH_HASHED) n = *((unsigned int*)value);
53*4887Schin 		else
54*4887Schin 		{
55*4887Schin 			s2 = name;
56*4887Schin 			n = 0;
57*4887Schin 			while (c = *s2++) HASHPART(n, c);
58*4887Schin 		}
59*4887Schin 		i = n;
60*4887Schin 		for (;;)
61*4887Schin 		{
62*4887Schin 			HASHMOD(tab, n);
63*4887Schin 			for (b = tab->table[n]; b; b = b->next)
64*4887Schin 			{
65*4887Schin 				s1 = hashname(b);
66*4887Schin 				s2 = name;
67*4887Schin 				while ((c = *s1++) == *s2++)
68*4887Schin 					if (!c) return((flags & HASH_VALUE) ? b->value : (char*)b);
69*4887Schin 			}
70*4887Schin 			if (!(tab = tab->scope) || (flags & HASH_NOSCOPE))
71*4887Schin 				return(0);
72*4887Schin 			n = i;
73*4887Schin 		}
74*4887Schin 	}
75*4887Schin 	tab->root->accesses++;
76*4887Schin 	top = tab;
77*4887Schin 	last = &tab->root->last;
78*4887Schin 	if (name)
79*4887Schin 	{
80*4887Schin 		last->table = tab;
81*4887Schin 		if (flags & (HASH_BUCKET|HASH_INSTALL))
82*4887Schin 		{
83*4887Schin 			last->bucket = (Hash_bucket_t*)name;
84*4887Schin 			name = hashname(last->bucket);
85*4887Schin 		}
86*4887Schin 		else last->bucket = 0;
87*4887Schin 		last->name = name;
88*4887Schin 		if (flags & HASH_BUCKET) n = last->bucket->hash;
89*4887Schin 		else if (tab->flags & HASH_HASHED)
90*4887Schin 		{
91*4887Schin 			n = (unsigned int)integralof(name);
92*4887Schin 			if (!(flags & HASH_HASHED)) n >>= 3;
93*4887Schin 		}
94*4887Schin 		else if (flags & HASH_HASHED) n = *((unsigned int*)value);
95*4887Schin 		else HASH(tab->root, name, n);
96*4887Schin 		last->hash = i = HASHVAL(n);
97*4887Schin 		for (;;)
98*4887Schin 		{
99*4887Schin 			HASHMOD(tab, n);
100*4887Schin 			for (prev = 0, b = tab->table[n]; b; prev = b, b = b->next)
101*4887Schin 			{
102*4887Schin 				if (i == HASHVAL(b->hash) && ((b->hash & (HASH_DELETED|HASH_OPAQUED)) != HASH_DELETED || (flags & (HASH_CREATE|HASH_DELETE|HASH_INSTALL|HASH_RENAME))))
103*4887Schin 				{
104*4887Schin 					if (!tab->root->local->compare)
105*4887Schin 					{
106*4887Schin 						register char*		s1 = hashname(b);
107*4887Schin 						register const char*	s2 = name;
108*4887Schin 
109*4887Schin 						if (tab->root->namesize)
110*4887Schin 						{
111*4887Schin 							register char*	s3 = s1 + tab->root->namesize;
112*4887Schin 
113*4887Schin 							while (*s1++ == *s2++)
114*4887Schin 								if (s1 >= s3) goto found;
115*4887Schin 						}
116*4887Schin 						else while (*s1 == *s2++)
117*4887Schin 							if (!*s1++) goto found;
118*4887Schin 					}
119*4887Schin 					else if (tab->root->namesize)
120*4887Schin 					{
121*4887Schin 						if (!(*tab->root->local->compare)(hashname(b), name, tab->root->namesize)) goto found;
122*4887Schin 					}
123*4887Schin 					else if (!(*tab->root->local->compare)(hashname(b), name)) goto found;
124*4887Schin 				}
125*4887Schin 				tab->root->collisions++;
126*4887Schin 			}
127*4887Schin 			if (!tab->scope || (flags & (HASH_CREATE|HASH_INSTALL|HASH_NOSCOPE)) == HASH_NOSCOPE) break;
128*4887Schin 			tab = tab->scope;
129*4887Schin 			n = i;
130*4887Schin 		}
131*4887Schin 	}
132*4887Schin 	else
133*4887Schin 	{
134*4887Schin 		tab = last->table;
135*4887Schin 		name = last->name;
136*4887Schin 		n = i = last->hash;
137*4887Schin 		prev = 0;
138*4887Schin 		HASHMOD(tab, n);
139*4887Schin 		if (b = last->bucket)
140*4887Schin 		{
141*4887Schin 			/*
142*4887Schin 			 * found the bucket
143*4887Schin 			 */
144*4887Schin 
145*4887Schin 		found:
146*4887Schin 			if (prev && !tab->frozen)
147*4887Schin 			{
148*4887Schin 				/*
149*4887Schin 				 * migrate popular buckets to the front
150*4887Schin 				 */
151*4887Schin 
152*4887Schin 				prev->next = b->next;
153*4887Schin 				b->next = tab->table[n];
154*4887Schin 				tab->table[n] = b;
155*4887Schin 			}
156*4887Schin 			switch (flags & (HASH_CREATE|HASH_DELETE|HASH_INSTALL|HASH_RENAME))
157*4887Schin 			{
158*4887Schin 			case HASH_CREATE:
159*4887Schin 			case HASH_CREATE|HASH_INSTALL:
160*4887Schin 			case HASH_INSTALL:
161*4887Schin 				if (tab != top && !(flags & HASH_SCOPE)) break;
162*4887Schin 				if (flags & HASH_OPAQUE) b->hash |= HASH_OPAQUED;
163*4887Schin 				goto exists;
164*4887Schin 
165*4887Schin 			case HASH_DELETE:
166*4887Schin 				value = 0;
167*4887Schin 				if (tab == top || (flags & HASH_SCOPE))
168*4887Schin 				{
169*4887Schin 					if (flags & HASH_OPAQUE) b->hash &= ~HASH_OPAQUED;
170*4887Schin 					else if (!(tab->root->flags & HASH_BUCKET))
171*4887Schin 					{
172*4887Schin 						if (tab->root->local->free && b->value)
173*4887Schin 						{
174*4887Schin 							(*tab->root->local->free)(b->value);
175*4887Schin 							b->value = 0;
176*4887Schin 						}
177*4887Schin 						else if (tab->flags & HASH_VALUE)
178*4887Schin 						{
179*4887Schin 							value = b->value;
180*4887Schin 							b->value = 0;
181*4887Schin 						}
182*4887Schin 					}
183*4887Schin 					tab->buckets--;
184*4887Schin 					if (tab->frozen || (b->hash & HASH_OPAQUED)) b->hash |= HASH_DELETED;
185*4887Schin 					else
186*4887Schin 					{
187*4887Schin 						tab->table[n] = b->next;
188*4887Schin 						name = (b->hash & HASH_FREENAME) ? (char*)b->name : (char*)0;
189*4887Schin 						if (tab->root->local->free && (tab->root->flags & HASH_BUCKET)) (*tab->root->local->free)((char*)b);
190*4887Schin 						else if (!(b->hash & HASH_KEEP))
191*4887Schin 						{
192*4887Schin 							if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, b, 0, 0);
193*4887Schin 							else free(b);
194*4887Schin 						}
195*4887Schin 						if (name)
196*4887Schin 						{
197*4887Schin 							if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, (char*)name, 0, 0);
198*4887Schin 							else free((char*)name);
199*4887Schin 						}
200*4887Schin 					}
201*4887Schin 				}
202*4887Schin 				return((char*)value);
203*4887Schin 
204*4887Schin 			case HASH_RENAME:
205*4887Schin 				if (tab != top || tab->frozen || (b->hash & (HASH_KEEP|HASH_OPAQUED)) || hashlook(top, value, (flags&(HASH_HASHED|HASH_INTERNAL))|HASH_LOOKUP, NiL))
206*4887Schin 					return(0);
207*4887Schin 				name = (char*)b->name;
208*4887Schin 				if (!(tab->flags & HASH_ALLOCATE)) b->name = (char*)value;
209*4887Schin 				else if (b->name && tab->root->namesize)
210*4887Schin 				{
211*4887Schin 					memcpy(b->name, value, tab->root->namesize);
212*4887Schin 					name = 0;
213*4887Schin 				}
214*4887Schin 				else
215*4887Schin 				{
216*4887Schin 					int	m;
217*4887Schin 					char*	t;
218*4887Schin 
219*4887Schin 					if (!(i = tab->bucketsize))
220*4887Schin 						i = (sizeof(Hash_bucket_t) + sizeof(char*) - 1) / sizeof(char*);
221*4887Schin 					i *= sizeof(char*);
222*4887Schin 					if (b->name == ((char*)b + i) && strlen(b->name) <= (m = strlen(value)))
223*4887Schin 					{
224*4887Schin 						strcpy(b->name, value);
225*4887Schin 						name = 0;
226*4887Schin 					}
227*4887Schin 					else
228*4887Schin 					{
229*4887Schin 						 m++;
230*4887Schin 						 if (!(t = tab->root->local->region ? (char*)(*tab->root->local->region)(tab->root->local->handle, NiL, m, 0) : (char*)malloc(m)))
231*4887Schin 							return(0);
232*4887Schin 						b->name = strcpy(t, value);
233*4887Schin 					}
234*4887Schin 				}
235*4887Schin 				if (name && (b->hash & HASH_FREENAME))
236*4887Schin 				{
237*4887Schin 					b->hash &= ~HASH_FREENAME;
238*4887Schin 					if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, (char*)name, 0, 0);
239*4887Schin 					else free((char*)name);
240*4887Schin 				}
241*4887Schin 				tab->buckets--;
242*4887Schin 				tab->table[n] = b->next;
243*4887Schin 				flags = HASH_CREATE|HASH_INSTALL;
244*4887Schin 				last->bucket = b;
245*4887Schin 				i = last->hash;
246*4887Schin 				goto create;
247*4887Schin 
248*4887Schin 			default:
249*4887Schin 				if (!(b->hash & HASH_DELETED)) goto exists;
250*4887Schin 				return(0);
251*4887Schin 			}
252*4887Schin 		}
253*4887Schin 	}
254*4887Schin 	if (!(flags & (HASH_CREATE|HASH_INSTALL))) return(0);
255*4887Schin 
256*4887Schin 	/*
257*4887Schin 	 * create a new bucket
258*4887Schin 	 */
259*4887Schin 
260*4887Schin  create:
261*4887Schin 	if (tab == top) prev = 0;
262*4887Schin 	else
263*4887Schin 	{
264*4887Schin 		if (prev = b)
265*4887Schin 		{
266*4887Schin 			name = (b->hash & HASH_HIDES) ? b->name : (char*)b;
267*4887Schin 			i |= HASH_HIDES;
268*4887Schin 		}
269*4887Schin 		if (!(flags & HASH_SCOPE)) tab = top;
270*4887Schin 	}
271*4887Schin 
272*4887Schin 	/*
273*4887Schin 	 * check for table expansion
274*4887Schin 	 */
275*4887Schin 
276*4887Schin 	if (!tab->frozen && !(tab->flags & HASH_FIXED) && tab->buckets > tab->root->meanchain * tab->size)
277*4887Schin 		hashsize(tab, tab->size << 1);
278*4887Schin 	if (flags & HASH_INSTALL)
279*4887Schin 	{
280*4887Schin 		b = last->bucket;
281*4887Schin 		i |= HASH_KEEP;
282*4887Schin 	}
283*4887Schin 	else
284*4887Schin 	{
285*4887Schin 		int	m = tab->bucketsize * sizeof(char*);
286*4887Schin 
287*4887Schin 		if (flags & HASH_VALUE)
288*4887Schin 		{
289*4887Schin 			tab->flags |= HASH_VALUE;
290*4887Schin 			if (m < sizeof(Hash_bucket_t))
291*4887Schin 			{
292*4887Schin 				tab->bucketsize = (sizeof(Hash_bucket_t) + sizeof(char*) - 1) / sizeof(char*);
293*4887Schin 				m = tab->bucketsize * sizeof(char*);
294*4887Schin 			}
295*4887Schin 			n = m;
296*4887Schin 		}
297*4887Schin 		else if (!(n = HASH_SIZEOF(flags)))
298*4887Schin 		{
299*4887Schin 			if (!(flags & HASH_FIXED)) n = m;
300*4887Schin 			else if ((n = (int)integralof(value)) < m) n = m;
301*4887Schin 		}
302*4887Schin 		else if (n < m) n = m;
303*4887Schin 		if (!prev && (tab->flags & HASH_ALLOCATE))
304*4887Schin 		{
305*4887Schin 			m = tab->root->namesize ? tab->root->namesize : strlen(name) + 1;
306*4887Schin 			if (tab->root->local->region)
307*4887Schin 			{
308*4887Schin 				if (!(b = (Hash_bucket_t*)(*tab->root->local->region)(tab->root->local->handle, NiL, n + m, 0)))
309*4887Schin 					return(0);
310*4887Schin 				memset(b, 0, n + m);
311*4887Schin 			}
312*4887Schin 			else if (!(b = newof(0, Hash_bucket_t, 0, n + m)))
313*4887Schin 				return(0);
314*4887Schin 			b->name = (char*)b + n;
315*4887Schin 			memcpy(b->name, name, m);
316*4887Schin 		}
317*4887Schin 		else
318*4887Schin 		{
319*4887Schin 			if (tab->root->local->region)
320*4887Schin 			{
321*4887Schin 				if (!(b = (Hash_bucket_t*)(*tab->root->local->region)(tab->root->local->handle, NiL, n, 0)))
322*4887Schin 					return(0);
323*4887Schin 				memset(b, 0, n);
324*4887Schin 			}
325*4887Schin 			else if (!(b = newof(0, Hash_bucket_t, 0, n)))
326*4887Schin 				return(0);
327*4887Schin 			b->name = (char*)name;
328*4887Schin 		}
329*4887Schin 	}
330*4887Schin 	b->hash = n = i;
331*4887Schin 	HASHMOD(tab, n);
332*4887Schin 	b->next = tab->table[n];
333*4887Schin 	tab->table[n] = b;
334*4887Schin 	tab->buckets++;
335*4887Schin 	if (flags & HASH_OPAQUE)
336*4887Schin 	{
337*4887Schin 		tab->buckets--;
338*4887Schin 		b->hash |= HASH_DELETED|HASH_OPAQUED;
339*4887Schin 		return(0);
340*4887Schin 	}
341*4887Schin 
342*4887Schin 	/*
343*4887Schin 	 * finally got the bucket
344*4887Schin 	 */
345*4887Schin 
346*4887Schin  exists:
347*4887Schin 	if (b->hash & HASH_DELETED)
348*4887Schin 	{
349*4887Schin 		b->hash &= ~HASH_DELETED;
350*4887Schin 		tab->buckets++;
351*4887Schin 	}
352*4887Schin 	last->bucket = b;
353*4887Schin 	last->table = tab;
354*4887Schin 	switch (flags & (HASH_CREATE|HASH_VALUE))
355*4887Schin 	{
356*4887Schin 	case HASH_CREATE|HASH_VALUE:
357*4887Schin 		if (tab->root->local->free && !(tab->root->flags & HASH_BUCKET) && b->value) (*tab->root->local->free)(b->value);
358*4887Schin 		if (value && tab->root->local->alloc) value = (*tab->root->local->alloc)((unsigned int)integralof(value));
359*4887Schin 		b->value = (char*)value;
360*4887Schin 		return((char*)hashname(b));
361*4887Schin 	case HASH_VALUE:
362*4887Schin 		return(b->value);
363*4887Schin 	default:
364*4887Schin 		return((char*)b);
365*4887Schin 	}
366*4887Schin }
367