xref: /onnv-gate/usr/src/lib/libast/common/hash/hashlook.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * hash table library
284887Schin  */
294887Schin 
304887Schin #include "hashlib.h"
314887Schin 
324887Schin /*
334887Schin  * hash table lookup
344887Schin  */
354887Schin 
364887Schin char*
hashlook(register Hash_table_t * tab,const char * name,long flags,const char * value)374887Schin hashlook(register Hash_table_t* tab, const char* name, long flags, const char* value)
384887Schin {
394887Schin 	register Hash_bucket_t*	b;
404887Schin 	register unsigned int	n;
414887Schin 	register Hash_last_t*	last;
424887Schin 	Hash_table_t*		top;
434887Schin 	Hash_bucket_t*		prev;
444887Schin 	unsigned int		i;
454887Schin 
464887Schin 	if ((flags & (HASH_LOOKUP|HASH_INTERNAL)) == (HASH_LOOKUP|HASH_INTERNAL))
474887Schin 	{
484887Schin 		register char*		s1;
494887Schin 		register const char*	s2;
504887Schin 		register int		c;
514887Schin 
524887Schin 		if (flags & HASH_HASHED) n = *((unsigned int*)value);
534887Schin 		else
544887Schin 		{
554887Schin 			s2 = name;
564887Schin 			n = 0;
574887Schin 			while (c = *s2++) HASHPART(n, c);
584887Schin 		}
594887Schin 		i = n;
604887Schin 		for (;;)
614887Schin 		{
624887Schin 			HASHMOD(tab, n);
634887Schin 			for (b = tab->table[n]; b; b = b->next)
644887Schin 			{
654887Schin 				s1 = hashname(b);
664887Schin 				s2 = name;
674887Schin 				while ((c = *s1++) == *s2++)
684887Schin 					if (!c) return((flags & HASH_VALUE) ? b->value : (char*)b);
694887Schin 			}
704887Schin 			if (!(tab = tab->scope) || (flags & HASH_NOSCOPE))
714887Schin 				return(0);
724887Schin 			n = i;
734887Schin 		}
744887Schin 	}
754887Schin 	tab->root->accesses++;
764887Schin 	top = tab;
774887Schin 	last = &tab->root->last;
784887Schin 	if (name)
794887Schin 	{
804887Schin 		last->table = tab;
814887Schin 		if (flags & (HASH_BUCKET|HASH_INSTALL))
824887Schin 		{
834887Schin 			last->bucket = (Hash_bucket_t*)name;
844887Schin 			name = hashname(last->bucket);
854887Schin 		}
864887Schin 		else last->bucket = 0;
874887Schin 		last->name = name;
884887Schin 		if (flags & HASH_BUCKET) n = last->bucket->hash;
894887Schin 		else if (tab->flags & HASH_HASHED)
904887Schin 		{
914887Schin 			n = (unsigned int)integralof(name);
924887Schin 			if (!(flags & HASH_HASHED)) n >>= 3;
934887Schin 		}
944887Schin 		else if (flags & HASH_HASHED) n = *((unsigned int*)value);
954887Schin 		else HASH(tab->root, name, n);
964887Schin 		last->hash = i = HASHVAL(n);
974887Schin 		for (;;)
984887Schin 		{
994887Schin 			HASHMOD(tab, n);
1004887Schin 			for (prev = 0, b = tab->table[n]; b; prev = b, b = b->next)
1014887Schin 			{
1024887Schin 				if (i == HASHVAL(b->hash) && ((b->hash & (HASH_DELETED|HASH_OPAQUED)) != HASH_DELETED || (flags & (HASH_CREATE|HASH_DELETE|HASH_INSTALL|HASH_RENAME))))
1034887Schin 				{
1044887Schin 					if (!tab->root->local->compare)
1054887Schin 					{
1064887Schin 						register char*		s1 = hashname(b);
1074887Schin 						register const char*	s2 = name;
1084887Schin 
1094887Schin 						if (tab->root->namesize)
1104887Schin 						{
1114887Schin 							register char*	s3 = s1 + tab->root->namesize;
1124887Schin 
1134887Schin 							while (*s1++ == *s2++)
1144887Schin 								if (s1 >= s3) goto found;
1154887Schin 						}
1164887Schin 						else while (*s1 == *s2++)
1174887Schin 							if (!*s1++) goto found;
1184887Schin 					}
1194887Schin 					else if (tab->root->namesize)
1204887Schin 					{
1214887Schin 						if (!(*tab->root->local->compare)(hashname(b), name, tab->root->namesize)) goto found;
1224887Schin 					}
1234887Schin 					else if (!(*tab->root->local->compare)(hashname(b), name)) goto found;
1244887Schin 				}
1254887Schin 				tab->root->collisions++;
1264887Schin 			}
1274887Schin 			if (!tab->scope || (flags & (HASH_CREATE|HASH_INSTALL|HASH_NOSCOPE)) == HASH_NOSCOPE) break;
1284887Schin 			tab = tab->scope;
1294887Schin 			n = i;
1304887Schin 		}
1314887Schin 	}
1324887Schin 	else
1334887Schin 	{
1344887Schin 		tab = last->table;
1354887Schin 		name = last->name;
1364887Schin 		n = i = last->hash;
1374887Schin 		prev = 0;
1384887Schin 		HASHMOD(tab, n);
1394887Schin 		if (b = last->bucket)
1404887Schin 		{
1414887Schin 			/*
1424887Schin 			 * found the bucket
1434887Schin 			 */
1444887Schin 
1454887Schin 		found:
1464887Schin 			if (prev && !tab->frozen)
1474887Schin 			{
1484887Schin 				/*
1494887Schin 				 * migrate popular buckets to the front
1504887Schin 				 */
1514887Schin 
1524887Schin 				prev->next = b->next;
1534887Schin 				b->next = tab->table[n];
1544887Schin 				tab->table[n] = b;
1554887Schin 			}
1564887Schin 			switch (flags & (HASH_CREATE|HASH_DELETE|HASH_INSTALL|HASH_RENAME))
1574887Schin 			{
1584887Schin 			case HASH_CREATE:
1594887Schin 			case HASH_CREATE|HASH_INSTALL:
1604887Schin 			case HASH_INSTALL:
1614887Schin 				if (tab != top && !(flags & HASH_SCOPE)) break;
1624887Schin 				if (flags & HASH_OPAQUE) b->hash |= HASH_OPAQUED;
1634887Schin 				goto exists;
1644887Schin 
1654887Schin 			case HASH_DELETE:
1664887Schin 				value = 0;
1674887Schin 				if (tab == top || (flags & HASH_SCOPE))
1684887Schin 				{
1694887Schin 					if (flags & HASH_OPAQUE) b->hash &= ~HASH_OPAQUED;
1704887Schin 					else if (!(tab->root->flags & HASH_BUCKET))
1714887Schin 					{
1724887Schin 						if (tab->root->local->free && b->value)
1734887Schin 						{
1744887Schin 							(*tab->root->local->free)(b->value);
1754887Schin 							b->value = 0;
1764887Schin 						}
1774887Schin 						else if (tab->flags & HASH_VALUE)
1784887Schin 						{
1794887Schin 							value = b->value;
1804887Schin 							b->value = 0;
1814887Schin 						}
1824887Schin 					}
1834887Schin 					tab->buckets--;
1844887Schin 					if (tab->frozen || (b->hash & HASH_OPAQUED)) b->hash |= HASH_DELETED;
1854887Schin 					else
1864887Schin 					{
1874887Schin 						tab->table[n] = b->next;
1884887Schin 						name = (b->hash & HASH_FREENAME) ? (char*)b->name : (char*)0;
1894887Schin 						if (tab->root->local->free && (tab->root->flags & HASH_BUCKET)) (*tab->root->local->free)((char*)b);
1904887Schin 						else if (!(b->hash & HASH_KEEP))
1914887Schin 						{
1924887Schin 							if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, b, 0, 0);
1934887Schin 							else free(b);
1944887Schin 						}
1954887Schin 						if (name)
1964887Schin 						{
1974887Schin 							if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, (char*)name, 0, 0);
1984887Schin 							else free((char*)name);
1994887Schin 						}
2004887Schin 					}
2014887Schin 				}
2024887Schin 				return((char*)value);
2034887Schin 
2044887Schin 			case HASH_RENAME:
2054887Schin 				if (tab != top || tab->frozen || (b->hash & (HASH_KEEP|HASH_OPAQUED)) || hashlook(top, value, (flags&(HASH_HASHED|HASH_INTERNAL))|HASH_LOOKUP, NiL))
2064887Schin 					return(0);
2074887Schin 				name = (char*)b->name;
2084887Schin 				if (!(tab->flags & HASH_ALLOCATE)) b->name = (char*)value;
2094887Schin 				else if (b->name && tab->root->namesize)
2104887Schin 				{
2114887Schin 					memcpy(b->name, value, tab->root->namesize);
2124887Schin 					name = 0;
2134887Schin 				}
2144887Schin 				else
2154887Schin 				{
2164887Schin 					int	m;
2174887Schin 					char*	t;
2184887Schin 
2194887Schin 					if (!(i = tab->bucketsize))
2204887Schin 						i = (sizeof(Hash_bucket_t) + sizeof(char*) - 1) / sizeof(char*);
2214887Schin 					i *= sizeof(char*);
2228462SApril.Chin@Sun.COM 					m = strlen(value);
2238462SApril.Chin@Sun.COM 					if (b->name == ((char*)b + i) && strlen(b->name) <= m)
2244887Schin 					{
2254887Schin 						strcpy(b->name, value);
2264887Schin 						name = 0;
2274887Schin 					}
2284887Schin 					else
2294887Schin 					{
2304887Schin 						 m++;
2314887Schin 						 if (!(t = tab->root->local->region ? (char*)(*tab->root->local->region)(tab->root->local->handle, NiL, m, 0) : (char*)malloc(m)))
2324887Schin 							return(0);
2334887Schin 						b->name = strcpy(t, value);
2344887Schin 					}
2354887Schin 				}
2364887Schin 				if (name && (b->hash & HASH_FREENAME))
2374887Schin 				{
2384887Schin 					b->hash &= ~HASH_FREENAME;
2394887Schin 					if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, (char*)name, 0, 0);
2404887Schin 					else free((char*)name);
2414887Schin 				}
2424887Schin 				tab->buckets--;
2434887Schin 				tab->table[n] = b->next;
2444887Schin 				flags = HASH_CREATE|HASH_INSTALL;
2454887Schin 				last->bucket = b;
2464887Schin 				i = last->hash;
2474887Schin 				goto create;
2484887Schin 
2494887Schin 			default:
2504887Schin 				if (!(b->hash & HASH_DELETED)) goto exists;
2514887Schin 				return(0);
2524887Schin 			}
2534887Schin 		}
2544887Schin 	}
2554887Schin 	if (!(flags & (HASH_CREATE|HASH_INSTALL))) return(0);
2564887Schin 
2574887Schin 	/*
2584887Schin 	 * create a new bucket
2594887Schin 	 */
2604887Schin 
2614887Schin  create:
2624887Schin 	if (tab == top) prev = 0;
2634887Schin 	else
2644887Schin 	{
2654887Schin 		if (prev = b)
2664887Schin 		{
2674887Schin 			name = (b->hash & HASH_HIDES) ? b->name : (char*)b;
2684887Schin 			i |= HASH_HIDES;
2694887Schin 		}
2704887Schin 		if (!(flags & HASH_SCOPE)) tab = top;
2714887Schin 	}
2724887Schin 
2734887Schin 	/*
2744887Schin 	 * check for table expansion
2754887Schin 	 */
2764887Schin 
2774887Schin 	if (!tab->frozen && !(tab->flags & HASH_FIXED) && tab->buckets > tab->root->meanchain * tab->size)
2784887Schin 		hashsize(tab, tab->size << 1);
2794887Schin 	if (flags & HASH_INSTALL)
2804887Schin 	{
2814887Schin 		b = last->bucket;
2824887Schin 		i |= HASH_KEEP;
2834887Schin 	}
2844887Schin 	else
2854887Schin 	{
2864887Schin 		int	m = tab->bucketsize * sizeof(char*);
2874887Schin 
2884887Schin 		if (flags & HASH_VALUE)
2894887Schin 		{
2904887Schin 			tab->flags |= HASH_VALUE;
2914887Schin 			if (m < sizeof(Hash_bucket_t))
2924887Schin 			{
2934887Schin 				tab->bucketsize = (sizeof(Hash_bucket_t) + sizeof(char*) - 1) / sizeof(char*);
2944887Schin 				m = tab->bucketsize * sizeof(char*);
2954887Schin 			}
2964887Schin 			n = m;
2974887Schin 		}
2984887Schin 		else if (!(n = HASH_SIZEOF(flags)))
2994887Schin 		{
3004887Schin 			if (!(flags & HASH_FIXED)) n = m;
3014887Schin 			else if ((n = (int)integralof(value)) < m) n = m;
3024887Schin 		}
3034887Schin 		else if (n < m) n = m;
3044887Schin 		if (!prev && (tab->flags & HASH_ALLOCATE))
3054887Schin 		{
3064887Schin 			m = tab->root->namesize ? tab->root->namesize : strlen(name) + 1;
3074887Schin 			if (tab->root->local->region)
3084887Schin 			{
3094887Schin 				if (!(b = (Hash_bucket_t*)(*tab->root->local->region)(tab->root->local->handle, NiL, n + m, 0)))
3104887Schin 					return(0);
3114887Schin 				memset(b, 0, n + m);
3124887Schin 			}
3134887Schin 			else if (!(b = newof(0, Hash_bucket_t, 0, n + m)))
3144887Schin 				return(0);
3154887Schin 			b->name = (char*)b + n;
3164887Schin 			memcpy(b->name, name, m);
3174887Schin 		}
3184887Schin 		else
3194887Schin 		{
3204887Schin 			if (tab->root->local->region)
3214887Schin 			{
3224887Schin 				if (!(b = (Hash_bucket_t*)(*tab->root->local->region)(tab->root->local->handle, NiL, n, 0)))
3234887Schin 					return(0);
3244887Schin 				memset(b, 0, n);
3254887Schin 			}
3264887Schin 			else if (!(b = newof(0, Hash_bucket_t, 0, n)))
3274887Schin 				return(0);
3284887Schin 			b->name = (char*)name;
3294887Schin 		}
3304887Schin 	}
3314887Schin 	b->hash = n = i;
3324887Schin 	HASHMOD(tab, n);
3334887Schin 	b->next = tab->table[n];
3344887Schin 	tab->table[n] = b;
3354887Schin 	tab->buckets++;
3364887Schin 	if (flags & HASH_OPAQUE)
3374887Schin 	{
3384887Schin 		tab->buckets--;
3394887Schin 		b->hash |= HASH_DELETED|HASH_OPAQUED;
3404887Schin 		return(0);
3414887Schin 	}
3424887Schin 
3434887Schin 	/*
3444887Schin 	 * finally got the bucket
3454887Schin 	 */
3464887Schin 
3474887Schin  exists:
3484887Schin 	if (b->hash & HASH_DELETED)
3494887Schin 	{
3504887Schin 		b->hash &= ~HASH_DELETED;
3514887Schin 		tab->buckets++;
3524887Schin 	}
3534887Schin 	last->bucket = b;
3544887Schin 	last->table = tab;
3554887Schin 	switch (flags & (HASH_CREATE|HASH_VALUE))
3564887Schin 	{
3574887Schin 	case HASH_CREATE|HASH_VALUE:
3584887Schin 		if (tab->root->local->free && !(tab->root->flags & HASH_BUCKET) && b->value) (*tab->root->local->free)(b->value);
3594887Schin 		if (value && tab->root->local->alloc) value = (*tab->root->local->alloc)((unsigned int)integralof(value));
3604887Schin 		b->value = (char*)value;
3614887Schin 		return((char*)hashname(b));
3624887Schin 	case HASH_VALUE:
3634887Schin 		return(b->value);
3644887Schin 	default:
3654887Schin 		return((char*)b);
3664887Schin 	}
3674887Schin }
368