xref: /onnv-gate/usr/src/lib/libast/common/cdt/dthash.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 #include	"dthdr.h"
234887Schin 
244887Schin /*	Hash table.
254887Schin **	dt:	dictionary
264887Schin **	obj:	what to look for
274887Schin **	type:	type of search
284887Schin **
294887Schin **      Written by Kiem-Phong Vo (05/25/96)
304887Schin */
314887Schin 
324887Schin /* resize the hash table */
334887Schin #if __STD_C
dthtab(Dt_t * dt)344887Schin static void dthtab(Dt_t* dt)
354887Schin #else
364887Schin static void dthtab(dt)
374887Schin Dt_t*	dt;
384887Schin #endif
394887Schin {
404887Schin 	reg Dtlink_t	*t, *r, *p, **s, **hs, **is, **olds;
414887Schin 	int		n, k;
424887Schin 
434887Schin 	if(dt->data->minp > 0 && dt->data->ntab > 0) /* fixed table size */
444887Schin 		return;
454887Schin 	dt->data->minp = 0;
464887Schin 
474887Schin 	n = dt->data->ntab;
484887Schin 	if(dt->disc && dt->disc->eventf &&
494887Schin 	   (*dt->disc->eventf)(dt, DT_HASHSIZE, &n, dt->disc) > 0 )
504887Schin 	{	if(n < 0) /* fix table size */
514887Schin 		{	dt->data->minp = 1;
524887Schin 			if(dt->data->ntab > 0 )
534887Schin 				return;
544887Schin 		}
554887Schin 		else /* set a particular size */
564887Schin 		{	for(k = 2; k < n; k *= 2)
574887Schin 				;
584887Schin 			n = k;
594887Schin 		}
604887Schin 	}
614887Schin 	else	n = 0;
624887Schin 
634887Schin 	/* compute new table size */
644887Schin 	if(n <= 0)
654887Schin 	{	if((n = dt->data->ntab) == 0)
664887Schin 			n = HSLOT;
674887Schin 		while(dt->data->size > HLOAD(n))
684887Schin 			n = HRESIZE(n);
694887Schin 	}
704887Schin 	if(n == dt->data->ntab)
714887Schin 		return;
724887Schin 
734887Schin 	/* allocate new table */
744887Schin 	olds = dt->data->ntab == 0 ? NIL(Dtlink_t**) : dt->data->htab;
754887Schin 	if(!(s = (Dtlink_t**)(*dt->memoryf)(dt,olds,n*sizeof(Dtlink_t*),dt->disc)) )
764887Schin 		return;
774887Schin 	olds = s + dt->data->ntab;
784887Schin 	dt->data->htab = s;
794887Schin 	dt->data->ntab = n;
804887Schin 
814887Schin 	/* rehash elements */
824887Schin 	for(hs = s+n-1; hs >= olds; --hs)
834887Schin 		*hs = NIL(Dtlink_t*);
844887Schin 	for(hs = s; hs < olds; ++hs)
854887Schin 	{	for(p = NIL(Dtlink_t*), t = *hs; t; t = r)
864887Schin 		{	r = t->right;
874887Schin 			if((is = s + HINDEX(n,t->hash)) == hs)
884887Schin 				p = t;
894887Schin 			else	/* move to a new chain */
904887Schin 			{	if(p)
914887Schin 					p->right = r;
924887Schin 				else	*hs = r;
934887Schin 				t->right = *is; *is = t;
944887Schin 			}
954887Schin 		}
964887Schin 	}
974887Schin }
984887Schin 
994887Schin #if __STD_C
dthash(Dt_t * dt,reg Void_t * obj,int type)1004887Schin static Void_t* dthash(Dt_t* dt, reg Void_t* obj, int type)
1014887Schin #else
1024887Schin static Void_t* dthash(dt,obj,type)
1034887Schin Dt_t*		dt;
1044887Schin reg Void_t*	obj;
1054887Schin int		type;
1064887Schin #endif
1074887Schin {
1084887Schin 	reg Dtlink_t	*t, *r, *p;
1094887Schin 	reg Void_t	*k, *key;
1104887Schin 	reg uint	hsh;
1114887Schin 	reg int		lk, sz, ky;
1124887Schin 	reg Dtcompar_f	cmpf;
1134887Schin 	reg Dtdisc_t*	disc;
1144887Schin 	reg Dtlink_t	**s, **ends;
1154887Schin 
1164887Schin 	UNFLATTEN(dt);
1174887Schin 
1184887Schin 	/* initialize discipline data */
1194887Schin 	disc = dt->disc; _DTDSC(disc,ky,sz,lk,cmpf);
1204887Schin 	dt->type &= ~DT_FOUND;
1214887Schin 
1224887Schin 	if(!obj)
1234887Schin 	{	if(type&(DT_NEXT|DT_PREV))
1244887Schin 			goto end_walk;
1254887Schin 
1264887Schin 		if(dt->data->size <= 0 || !(type&(DT_CLEAR|DT_FIRST|DT_LAST)) )
1274887Schin 			return NIL(Void_t*);
1284887Schin 
1294887Schin 		ends = (s = dt->data->htab) + dt->data->ntab;
1304887Schin 		if(type&DT_CLEAR)
1314887Schin 		{	/* clean out all objects */
1324887Schin 			for(; s < ends; ++s)
1334887Schin 			{	t = *s;
1344887Schin 				*s = NIL(Dtlink_t*);
1354887Schin 				if(!disc->freef && disc->link >= 0)
1364887Schin 					continue;
1374887Schin 				while(t)
1384887Schin 				{	r = t->right;
1394887Schin 					if(disc->freef)
1404887Schin 						(*disc->freef)(dt,_DTOBJ(t,lk),disc);
1414887Schin 					if(disc->link < 0)
1424887Schin 						(*dt->memoryf)(dt,(Void_t*)t,0,disc);
1434887Schin 					t = r;
1444887Schin 				}
1454887Schin 			}
1464887Schin 			dt->data->here = NIL(Dtlink_t*);
1474887Schin 			dt->data->size = 0;
1484887Schin 			dt->data->loop = 0;
1494887Schin 			return NIL(Void_t*);
1504887Schin 		}
1514887Schin 		else	/* computing the first/last object */
1524887Schin 		{	t = NIL(Dtlink_t*);
1534887Schin 			while(s < ends && !t )
1544887Schin 				t = (type&DT_LAST) ? *--ends : *s++;
1554887Schin 			if(t && (type&DT_LAST))
1564887Schin 				for(; t->right; t = t->right)
1574887Schin 					;
1584887Schin 
1594887Schin 			dt->data->loop += 1;
1604887Schin 			dt->data->here = t;
1614887Schin 			return t ? _DTOBJ(t,lk) : NIL(Void_t*);
1624887Schin 		}
1634887Schin 	}
1644887Schin 
1654887Schin 	/* allow apps to delete an object "actually" in the dictionary */
1664887Schin 	if(dt->meth->type == DT_BAG && (type&(DT_DELETE|DT_DETACH)) )
1674887Schin 	{	if(!dtsearch(dt,obj) )
1684887Schin 			return NIL(Void_t*);
1694887Schin 
1704887Schin 		s = dt->data->htab + HINDEX(dt->data->ntab,dt->data->here->hash);
1714887Schin 		r = NIL(Dtlink_t*);
1724887Schin 		for(p = NIL(Dtlink_t*), t = *s; t; p = t, t = t->right)
1734887Schin 		{	if(_DTOBJ(t,lk) == obj) /* delete this specific object */
1744887Schin 				goto do_delete;
1754887Schin 			if(t == dt->data->here)
1764887Schin 				r = p;
1774887Schin 		}
1784887Schin 
1794887Schin 		/* delete some matching object */
1804887Schin 		p = r; t = dt->data->here;
1814887Schin 		goto do_delete;
1824887Schin 	}
1834887Schin 
1844887Schin 	if(type&(DT_MATCH|DT_SEARCH|DT_INSERT|DT_ATTACH) )
1854887Schin 	{	key = (type&DT_MATCH) ? obj : _DTKEY(obj,ky,sz);
1864887Schin 		hsh = _DTHSH(dt,key,disc,sz);
1874887Schin 		goto do_search;
1884887Schin 	}
1894887Schin 	else if(type&(DT_RENEW|DT_VSEARCH) )
1904887Schin 	{	r = (Dtlink_t*)obj;
1914887Schin 		obj = _DTOBJ(r,lk);
1924887Schin 		key = _DTKEY(obj,ky,sz);
1934887Schin 		hsh = r->hash;
1944887Schin 		goto do_search;
1954887Schin 	}
1964887Schin 	else /*if(type&(DT_DELETE|DT_DETACH|DT_NEXT|DT_PREV))*/
1974887Schin 	{	if((t = dt->data->here) && _DTOBJ(t,lk) == obj)
1984887Schin 		{	hsh = t->hash;
1994887Schin 			s = dt->data->htab + HINDEX(dt->data->ntab,hsh);
2004887Schin 			p = NIL(Dtlink_t*);
2014887Schin 		}
2024887Schin 		else
2034887Schin 		{	key = _DTKEY(obj,ky,sz);
2044887Schin 			hsh = _DTHSH(dt,key,disc,sz);
2054887Schin 		do_search:
2064887Schin 			t = dt->data->ntab <= 0 ? NIL(Dtlink_t*) :
2074887Schin 			 	*(s = dt->data->htab + HINDEX(dt->data->ntab,hsh));
2084887Schin 			for(p = NIL(Dtlink_t*); t; p = t, t = t->right)
2094887Schin 			{	if(hsh == t->hash)
2104887Schin 				{	k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz);
2114887Schin 					if(_DTCMP(dt,key,k,disc,cmpf,sz) == 0)
2124887Schin 						break;
2134887Schin 				}
2144887Schin 			}
2154887Schin 		}
2164887Schin 	}
2174887Schin 
2184887Schin 	if(t) /* found matching object */
2194887Schin 		dt->type |= DT_FOUND;
2204887Schin 
2214887Schin 	if(type&(DT_MATCH|DT_SEARCH|DT_VSEARCH))
2224887Schin 	{	if(!t)
2234887Schin 			return NIL(Void_t*);
2244887Schin 		if(p && (dt->data->type&DT_SET) && dt->data->loop <= 0)
2254887Schin 		{	/* move-to-front heuristic */
2264887Schin 			p->right = t->right;
2274887Schin 			t->right = *s;
2284887Schin 			*s = t;
2294887Schin 		}
2304887Schin 		dt->data->here = t;
2314887Schin 		return _DTOBJ(t,lk);
2324887Schin 	}
2334887Schin 	else if(type&(DT_INSERT|DT_ATTACH))
2344887Schin 	{	if(t && (dt->data->type&DT_SET) )
2354887Schin 		{	dt->data->here = t;
2364887Schin 			return _DTOBJ(t,lk);
2374887Schin 		}
2384887Schin 
2394887Schin 		if(disc->makef && (type&DT_INSERT) &&
2404887Schin 		   !(obj = (*disc->makef)(dt,obj,disc)) )
2414887Schin 			return NIL(Void_t*);
2424887Schin 		if(lk >= 0)
2434887Schin 			r = _DTLNK(obj,lk);
2444887Schin 		else
2454887Schin 		{	r = (Dtlink_t*)(*dt->memoryf)
2464887Schin 				(dt,NIL(Void_t*),sizeof(Dthold_t),disc);
2474887Schin 			if(r)
2484887Schin 				((Dthold_t*)r)->obj = obj;
2494887Schin 			else
2504887Schin 			{	if(disc->makef && disc->freef && (type&DT_INSERT))
2514887Schin 					(*disc->freef)(dt,obj,disc);
2524887Schin 				return NIL(Void_t*);
2534887Schin 			}
2544887Schin 		}
2554887Schin 		r->hash = hsh;
2564887Schin 
2574887Schin 		/* insert object */
2584887Schin 	do_insert:
2594887Schin 		if((dt->data->size += 1) > HLOAD(dt->data->ntab) && dt->data->loop <= 0 )
2604887Schin 			dthtab(dt);
2614887Schin 		if(dt->data->ntab == 0)
2624887Schin 		{	dt->data->size -= 1;
2634887Schin 			if(disc->freef && (type&DT_INSERT))
2644887Schin 				(*disc->freef)(dt,obj,disc);
2654887Schin 			if(disc->link < 0)
2664887Schin 				(*disc->memoryf)(dt,(Void_t*)r,0,disc);
2674887Schin 			return NIL(Void_t*);
2684887Schin 		}
2694887Schin 		s = dt->data->htab + HINDEX(dt->data->ntab,hsh);
2704887Schin 		if(t)
2714887Schin 		{	r->right = t->right;
2724887Schin 			t->right = r;
2734887Schin 		}
2744887Schin 		else
2754887Schin 		{	r->right = *s;
2764887Schin 			*s = r;
2774887Schin 		}
2784887Schin 		dt->data->here = r;
2794887Schin 		return obj;
2804887Schin 	}
2814887Schin 	else if(type&DT_NEXT)
2824887Schin 	{	if(t && !(p = t->right) )
2834887Schin 		{	for(ends = dt->data->htab+dt->data->ntab, s += 1; s < ends; ++s)
2844887Schin 				if((p = *s) )
2854887Schin 					break;
2864887Schin 		}
2874887Schin 		goto done_adj;
2884887Schin 	}
2894887Schin 	else if(type&DT_PREV)
2904887Schin 	{	if(t && !p)
2914887Schin 		{	if((p = *s) != t)
2924887Schin 			{	while(p->right != t)
2934887Schin 					p = p->right;
2944887Schin 			}
2954887Schin 			else
2964887Schin 			{	p = NIL(Dtlink_t*);
2974887Schin 				for(s -= 1, ends = dt->data->htab; s >= ends; --s)
2984887Schin 				{	if((p = *s) )
2994887Schin 					{	while(p->right)
3004887Schin 							p = p->right;
3014887Schin 						break;
3024887Schin 					}
3034887Schin 				}
3044887Schin 			}
3054887Schin 		}
3064887Schin 	done_adj:
3074887Schin 		if(!(dt->data->here = p) )
3084887Schin 		{ end_walk:
3094887Schin 			if((dt->data->loop -= 1) < 0)
3104887Schin 				dt->data->loop = 0;
3114887Schin 			if(dt->data->size > HLOAD(dt->data->ntab) && dt->data->loop <= 0)
3124887Schin 				dthtab(dt);
3134887Schin 			return NIL(Void_t*);
3144887Schin 		}
3154887Schin 		else
3164887Schin 		{	dt->data->type |= DT_WALK;
3174887Schin 			return _DTOBJ(p,lk);
3184887Schin 		}
3194887Schin 	}
3204887Schin 	else if(type&DT_RENEW)
3214887Schin 	{	if(!t || (dt->data->type&DT_BAG) )
3224887Schin 			goto do_insert;
3234887Schin 		else
3244887Schin 		{	if(disc->freef)
3254887Schin 				(*disc->freef)(dt,obj,disc);
3264887Schin 			if(disc->link < 0)
3274887Schin 				(*dt->memoryf)(dt,(Void_t*)r,0,disc);
3284887Schin 			return t ? _DTOBJ(t,lk) : NIL(Void_t*);
3294887Schin 		}
3304887Schin 	}
3314887Schin 	else /*if(type&(DT_DELETE|DT_DETACH))*/
3324887Schin 	{	/* take an element out of the dictionary */
3334887Schin 	do_delete:
3344887Schin 		if(!t)
3354887Schin 			return NIL(Void_t*);
3364887Schin 		else if(p)
3374887Schin 			p->right = t->right;
3384887Schin 		else if((p = *s) == t)
3394887Schin 			p = *s = t->right;
3404887Schin 		else
3414887Schin 		{	while(p->right != t)
3424887Schin 				p = p->right;
3434887Schin 			p->right = t->right;
3444887Schin 		}
3454887Schin 		obj = _DTOBJ(t,lk);
3464887Schin 		dt->data->size -= 1;
3474887Schin 		dt->data->here = p;
3484887Schin 		if(disc->freef && (type&DT_DELETE))
3494887Schin 			(*disc->freef)(dt,obj,disc);
3504887Schin 		if(disc->link < 0)
3514887Schin 			(*dt->memoryf)(dt,(Void_t*)t,0,disc);
3524887Schin 		return obj;
3534887Schin 	}
3544887Schin }
3554887Schin 
3564887Schin static Dtmethod_t	_Dtset = { dthash, DT_SET };
3574887Schin static Dtmethod_t	_Dtbag = { dthash, DT_BAG };
3584887Schin __DEFINE__(Dtmethod_t*,Dtset,&_Dtset);
3594887Schin __DEFINE__(Dtmethod_t*,Dtbag,&_Dtbag);
3604887Schin 
3614887Schin #ifndef KPVDEL	/* for backward compatibility - remove next time */
3624887Schin Dtmethod_t		_Dthash = { dthash, DT_SET };
3634887Schin __DEFINE__(Dtmethod_t*,Dthash,&_Dthash);
3644887Schin #endif
3654887Schin 
3664887Schin #ifdef NoF
3674887Schin NoF(dthash)
3684887Schin #endif
369