xref: /titanic_50/usr/src/lib/libast/common/cdt/dthash.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #include	"dthdr.h"
23da2e3ebdSchin 
24da2e3ebdSchin /*	Hash table.
25da2e3ebdSchin **	dt:	dictionary
26da2e3ebdSchin **	obj:	what to look for
27da2e3ebdSchin **	type:	type of search
28da2e3ebdSchin **
29da2e3ebdSchin **      Written by Kiem-Phong Vo (05/25/96)
30da2e3ebdSchin */
31da2e3ebdSchin 
32da2e3ebdSchin /* resize the hash table */
33da2e3ebdSchin #if __STD_C
dthtab(Dt_t * dt)34da2e3ebdSchin static void dthtab(Dt_t* dt)
35da2e3ebdSchin #else
36da2e3ebdSchin static void dthtab(dt)
37da2e3ebdSchin Dt_t*	dt;
38da2e3ebdSchin #endif
39da2e3ebdSchin {
40da2e3ebdSchin 	reg Dtlink_t	*t, *r, *p, **s, **hs, **is, **olds;
41da2e3ebdSchin 	int		n, k;
42da2e3ebdSchin 
43da2e3ebdSchin 	if(dt->data->minp > 0 && dt->data->ntab > 0) /* fixed table size */
44da2e3ebdSchin 		return;
45da2e3ebdSchin 	dt->data->minp = 0;
46da2e3ebdSchin 
47da2e3ebdSchin 	n = dt->data->ntab;
48da2e3ebdSchin 	if(dt->disc && dt->disc->eventf &&
49da2e3ebdSchin 	   (*dt->disc->eventf)(dt, DT_HASHSIZE, &n, dt->disc) > 0 )
50da2e3ebdSchin 	{	if(n < 0) /* fix table size */
51da2e3ebdSchin 		{	dt->data->minp = 1;
52da2e3ebdSchin 			if(dt->data->ntab > 0 )
53da2e3ebdSchin 				return;
54da2e3ebdSchin 		}
55da2e3ebdSchin 		else /* set a particular size */
56da2e3ebdSchin 		{	for(k = 2; k < n; k *= 2)
57da2e3ebdSchin 				;
58da2e3ebdSchin 			n = k;
59da2e3ebdSchin 		}
60da2e3ebdSchin 	}
61da2e3ebdSchin 	else	n = 0;
62da2e3ebdSchin 
63da2e3ebdSchin 	/* compute new table size */
64da2e3ebdSchin 	if(n <= 0)
65da2e3ebdSchin 	{	if((n = dt->data->ntab) == 0)
66da2e3ebdSchin 			n = HSLOT;
67da2e3ebdSchin 		while(dt->data->size > HLOAD(n))
68da2e3ebdSchin 			n = HRESIZE(n);
69da2e3ebdSchin 	}
70da2e3ebdSchin 	if(n == dt->data->ntab)
71da2e3ebdSchin 		return;
72da2e3ebdSchin 
73da2e3ebdSchin 	/* allocate new table */
74da2e3ebdSchin 	olds = dt->data->ntab == 0 ? NIL(Dtlink_t**) : dt->data->htab;
75da2e3ebdSchin 	if(!(s = (Dtlink_t**)(*dt->memoryf)(dt,olds,n*sizeof(Dtlink_t*),dt->disc)) )
76da2e3ebdSchin 		return;
77da2e3ebdSchin 	olds = s + dt->data->ntab;
78da2e3ebdSchin 	dt->data->htab = s;
79da2e3ebdSchin 	dt->data->ntab = n;
80da2e3ebdSchin 
81da2e3ebdSchin 	/* rehash elements */
82da2e3ebdSchin 	for(hs = s+n-1; hs >= olds; --hs)
83da2e3ebdSchin 		*hs = NIL(Dtlink_t*);
84da2e3ebdSchin 	for(hs = s; hs < olds; ++hs)
85da2e3ebdSchin 	{	for(p = NIL(Dtlink_t*), t = *hs; t; t = r)
86da2e3ebdSchin 		{	r = t->right;
87da2e3ebdSchin 			if((is = s + HINDEX(n,t->hash)) == hs)
88da2e3ebdSchin 				p = t;
89da2e3ebdSchin 			else	/* move to a new chain */
90da2e3ebdSchin 			{	if(p)
91da2e3ebdSchin 					p->right = r;
92da2e3ebdSchin 				else	*hs = r;
93da2e3ebdSchin 				t->right = *is; *is = t;
94da2e3ebdSchin 			}
95da2e3ebdSchin 		}
96da2e3ebdSchin 	}
97da2e3ebdSchin }
98da2e3ebdSchin 
99da2e3ebdSchin #if __STD_C
dthash(Dt_t * dt,reg Void_t * obj,int type)100da2e3ebdSchin static Void_t* dthash(Dt_t* dt, reg Void_t* obj, int type)
101da2e3ebdSchin #else
102da2e3ebdSchin static Void_t* dthash(dt,obj,type)
103da2e3ebdSchin Dt_t*		dt;
104da2e3ebdSchin reg Void_t*	obj;
105da2e3ebdSchin int		type;
106da2e3ebdSchin #endif
107da2e3ebdSchin {
108da2e3ebdSchin 	reg Dtlink_t	*t, *r, *p;
109da2e3ebdSchin 	reg Void_t	*k, *key;
110da2e3ebdSchin 	reg uint	hsh;
111da2e3ebdSchin 	reg int		lk, sz, ky;
112da2e3ebdSchin 	reg Dtcompar_f	cmpf;
113da2e3ebdSchin 	reg Dtdisc_t*	disc;
114da2e3ebdSchin 	reg Dtlink_t	**s, **ends;
115da2e3ebdSchin 
116da2e3ebdSchin 	UNFLATTEN(dt);
117da2e3ebdSchin 
118da2e3ebdSchin 	/* initialize discipline data */
119da2e3ebdSchin 	disc = dt->disc; _DTDSC(disc,ky,sz,lk,cmpf);
120da2e3ebdSchin 	dt->type &= ~DT_FOUND;
121da2e3ebdSchin 
122da2e3ebdSchin 	if(!obj)
123da2e3ebdSchin 	{	if(type&(DT_NEXT|DT_PREV))
124da2e3ebdSchin 			goto end_walk;
125da2e3ebdSchin 
126da2e3ebdSchin 		if(dt->data->size <= 0 || !(type&(DT_CLEAR|DT_FIRST|DT_LAST)) )
127da2e3ebdSchin 			return NIL(Void_t*);
128da2e3ebdSchin 
129da2e3ebdSchin 		ends = (s = dt->data->htab) + dt->data->ntab;
130da2e3ebdSchin 		if(type&DT_CLEAR)
131da2e3ebdSchin 		{	/* clean out all objects */
132da2e3ebdSchin 			for(; s < ends; ++s)
133da2e3ebdSchin 			{	t = *s;
134da2e3ebdSchin 				*s = NIL(Dtlink_t*);
135da2e3ebdSchin 				if(!disc->freef && disc->link >= 0)
136da2e3ebdSchin 					continue;
137da2e3ebdSchin 				while(t)
138da2e3ebdSchin 				{	r = t->right;
139da2e3ebdSchin 					if(disc->freef)
140da2e3ebdSchin 						(*disc->freef)(dt,_DTOBJ(t,lk),disc);
141da2e3ebdSchin 					if(disc->link < 0)
142da2e3ebdSchin 						(*dt->memoryf)(dt,(Void_t*)t,0,disc);
143da2e3ebdSchin 					t = r;
144da2e3ebdSchin 				}
145da2e3ebdSchin 			}
146da2e3ebdSchin 			dt->data->here = NIL(Dtlink_t*);
147da2e3ebdSchin 			dt->data->size = 0;
148da2e3ebdSchin 			dt->data->loop = 0;
149da2e3ebdSchin 			return NIL(Void_t*);
150da2e3ebdSchin 		}
151da2e3ebdSchin 		else	/* computing the first/last object */
152da2e3ebdSchin 		{	t = NIL(Dtlink_t*);
153da2e3ebdSchin 			while(s < ends && !t )
154da2e3ebdSchin 				t = (type&DT_LAST) ? *--ends : *s++;
155da2e3ebdSchin 			if(t && (type&DT_LAST))
156da2e3ebdSchin 				for(; t->right; t = t->right)
157da2e3ebdSchin 					;
158da2e3ebdSchin 
159da2e3ebdSchin 			dt->data->loop += 1;
160da2e3ebdSchin 			dt->data->here = t;
161da2e3ebdSchin 			return t ? _DTOBJ(t,lk) : NIL(Void_t*);
162da2e3ebdSchin 		}
163da2e3ebdSchin 	}
164da2e3ebdSchin 
165da2e3ebdSchin 	/* allow apps to delete an object "actually" in the dictionary */
166da2e3ebdSchin 	if(dt->meth->type == DT_BAG && (type&(DT_DELETE|DT_DETACH)) )
167da2e3ebdSchin 	{	if(!dtsearch(dt,obj) )
168da2e3ebdSchin 			return NIL(Void_t*);
169da2e3ebdSchin 
170da2e3ebdSchin 		s = dt->data->htab + HINDEX(dt->data->ntab,dt->data->here->hash);
171da2e3ebdSchin 		r = NIL(Dtlink_t*);
172da2e3ebdSchin 		for(p = NIL(Dtlink_t*), t = *s; t; p = t, t = t->right)
173da2e3ebdSchin 		{	if(_DTOBJ(t,lk) == obj) /* delete this specific object */
174da2e3ebdSchin 				goto do_delete;
175da2e3ebdSchin 			if(t == dt->data->here)
176da2e3ebdSchin 				r = p;
177da2e3ebdSchin 		}
178da2e3ebdSchin 
179da2e3ebdSchin 		/* delete some matching object */
180da2e3ebdSchin 		p = r; t = dt->data->here;
181da2e3ebdSchin 		goto do_delete;
182da2e3ebdSchin 	}
183da2e3ebdSchin 
184da2e3ebdSchin 	if(type&(DT_MATCH|DT_SEARCH|DT_INSERT|DT_ATTACH) )
185da2e3ebdSchin 	{	key = (type&DT_MATCH) ? obj : _DTKEY(obj,ky,sz);
186da2e3ebdSchin 		hsh = _DTHSH(dt,key,disc,sz);
187da2e3ebdSchin 		goto do_search;
188da2e3ebdSchin 	}
189da2e3ebdSchin 	else if(type&(DT_RENEW|DT_VSEARCH) )
190da2e3ebdSchin 	{	r = (Dtlink_t*)obj;
191da2e3ebdSchin 		obj = _DTOBJ(r,lk);
192da2e3ebdSchin 		key = _DTKEY(obj,ky,sz);
193da2e3ebdSchin 		hsh = r->hash;
194da2e3ebdSchin 		goto do_search;
195da2e3ebdSchin 	}
196da2e3ebdSchin 	else /*if(type&(DT_DELETE|DT_DETACH|DT_NEXT|DT_PREV))*/
197da2e3ebdSchin 	{	if((t = dt->data->here) && _DTOBJ(t,lk) == obj)
198da2e3ebdSchin 		{	hsh = t->hash;
199da2e3ebdSchin 			s = dt->data->htab + HINDEX(dt->data->ntab,hsh);
200da2e3ebdSchin 			p = NIL(Dtlink_t*);
201da2e3ebdSchin 		}
202da2e3ebdSchin 		else
203da2e3ebdSchin 		{	key = _DTKEY(obj,ky,sz);
204da2e3ebdSchin 			hsh = _DTHSH(dt,key,disc,sz);
205da2e3ebdSchin 		do_search:
206da2e3ebdSchin 			t = dt->data->ntab <= 0 ? NIL(Dtlink_t*) :
207da2e3ebdSchin 			 	*(s = dt->data->htab + HINDEX(dt->data->ntab,hsh));
208da2e3ebdSchin 			for(p = NIL(Dtlink_t*); t; p = t, t = t->right)
209da2e3ebdSchin 			{	if(hsh == t->hash)
210da2e3ebdSchin 				{	k = _DTOBJ(t,lk); k = _DTKEY(k,ky,sz);
211da2e3ebdSchin 					if(_DTCMP(dt,key,k,disc,cmpf,sz) == 0)
212da2e3ebdSchin 						break;
213da2e3ebdSchin 				}
214da2e3ebdSchin 			}
215da2e3ebdSchin 		}
216da2e3ebdSchin 	}
217da2e3ebdSchin 
218da2e3ebdSchin 	if(t) /* found matching object */
219da2e3ebdSchin 		dt->type |= DT_FOUND;
220da2e3ebdSchin 
221da2e3ebdSchin 	if(type&(DT_MATCH|DT_SEARCH|DT_VSEARCH))
222da2e3ebdSchin 	{	if(!t)
223da2e3ebdSchin 			return NIL(Void_t*);
224da2e3ebdSchin 		if(p && (dt->data->type&DT_SET) && dt->data->loop <= 0)
225da2e3ebdSchin 		{	/* move-to-front heuristic */
226da2e3ebdSchin 			p->right = t->right;
227da2e3ebdSchin 			t->right = *s;
228da2e3ebdSchin 			*s = t;
229da2e3ebdSchin 		}
230da2e3ebdSchin 		dt->data->here = t;
231da2e3ebdSchin 		return _DTOBJ(t,lk);
232da2e3ebdSchin 	}
233da2e3ebdSchin 	else if(type&(DT_INSERT|DT_ATTACH))
234da2e3ebdSchin 	{	if(t && (dt->data->type&DT_SET) )
235da2e3ebdSchin 		{	dt->data->here = t;
236da2e3ebdSchin 			return _DTOBJ(t,lk);
237da2e3ebdSchin 		}
238da2e3ebdSchin 
239da2e3ebdSchin 		if(disc->makef && (type&DT_INSERT) &&
240da2e3ebdSchin 		   !(obj = (*disc->makef)(dt,obj,disc)) )
241da2e3ebdSchin 			return NIL(Void_t*);
242da2e3ebdSchin 		if(lk >= 0)
243da2e3ebdSchin 			r = _DTLNK(obj,lk);
244da2e3ebdSchin 		else
245da2e3ebdSchin 		{	r = (Dtlink_t*)(*dt->memoryf)
246da2e3ebdSchin 				(dt,NIL(Void_t*),sizeof(Dthold_t),disc);
247da2e3ebdSchin 			if(r)
248da2e3ebdSchin 				((Dthold_t*)r)->obj = obj;
249da2e3ebdSchin 			else
250da2e3ebdSchin 			{	if(disc->makef && disc->freef && (type&DT_INSERT))
251da2e3ebdSchin 					(*disc->freef)(dt,obj,disc);
252da2e3ebdSchin 				return NIL(Void_t*);
253da2e3ebdSchin 			}
254da2e3ebdSchin 		}
255da2e3ebdSchin 		r->hash = hsh;
256da2e3ebdSchin 
257da2e3ebdSchin 		/* insert object */
258da2e3ebdSchin 	do_insert:
259da2e3ebdSchin 		if((dt->data->size += 1) > HLOAD(dt->data->ntab) && dt->data->loop <= 0 )
260da2e3ebdSchin 			dthtab(dt);
261da2e3ebdSchin 		if(dt->data->ntab == 0)
262da2e3ebdSchin 		{	dt->data->size -= 1;
263da2e3ebdSchin 			if(disc->freef && (type&DT_INSERT))
264da2e3ebdSchin 				(*disc->freef)(dt,obj,disc);
265da2e3ebdSchin 			if(disc->link < 0)
266da2e3ebdSchin 				(*disc->memoryf)(dt,(Void_t*)r,0,disc);
267da2e3ebdSchin 			return NIL(Void_t*);
268da2e3ebdSchin 		}
269da2e3ebdSchin 		s = dt->data->htab + HINDEX(dt->data->ntab,hsh);
270da2e3ebdSchin 		if(t)
271da2e3ebdSchin 		{	r->right = t->right;
272da2e3ebdSchin 			t->right = r;
273da2e3ebdSchin 		}
274da2e3ebdSchin 		else
275da2e3ebdSchin 		{	r->right = *s;
276da2e3ebdSchin 			*s = r;
277da2e3ebdSchin 		}
278da2e3ebdSchin 		dt->data->here = r;
279da2e3ebdSchin 		return obj;
280da2e3ebdSchin 	}
281da2e3ebdSchin 	else if(type&DT_NEXT)
282da2e3ebdSchin 	{	if(t && !(p = t->right) )
283da2e3ebdSchin 		{	for(ends = dt->data->htab+dt->data->ntab, s += 1; s < ends; ++s)
284da2e3ebdSchin 				if((p = *s) )
285da2e3ebdSchin 					break;
286da2e3ebdSchin 		}
287da2e3ebdSchin 		goto done_adj;
288da2e3ebdSchin 	}
289da2e3ebdSchin 	else if(type&DT_PREV)
290da2e3ebdSchin 	{	if(t && !p)
291da2e3ebdSchin 		{	if((p = *s) != t)
292da2e3ebdSchin 			{	while(p->right != t)
293da2e3ebdSchin 					p = p->right;
294da2e3ebdSchin 			}
295da2e3ebdSchin 			else
296da2e3ebdSchin 			{	p = NIL(Dtlink_t*);
297da2e3ebdSchin 				for(s -= 1, ends = dt->data->htab; s >= ends; --s)
298da2e3ebdSchin 				{	if((p = *s) )
299da2e3ebdSchin 					{	while(p->right)
300da2e3ebdSchin 							p = p->right;
301da2e3ebdSchin 						break;
302da2e3ebdSchin 					}
303da2e3ebdSchin 				}
304da2e3ebdSchin 			}
305da2e3ebdSchin 		}
306da2e3ebdSchin 	done_adj:
307da2e3ebdSchin 		if(!(dt->data->here = p) )
308da2e3ebdSchin 		{ end_walk:
309da2e3ebdSchin 			if((dt->data->loop -= 1) < 0)
310da2e3ebdSchin 				dt->data->loop = 0;
311da2e3ebdSchin 			if(dt->data->size > HLOAD(dt->data->ntab) && dt->data->loop <= 0)
312da2e3ebdSchin 				dthtab(dt);
313da2e3ebdSchin 			return NIL(Void_t*);
314da2e3ebdSchin 		}
315da2e3ebdSchin 		else
316da2e3ebdSchin 		{	dt->data->type |= DT_WALK;
317da2e3ebdSchin 			return _DTOBJ(p,lk);
318da2e3ebdSchin 		}
319da2e3ebdSchin 	}
320da2e3ebdSchin 	else if(type&DT_RENEW)
321da2e3ebdSchin 	{	if(!t || (dt->data->type&DT_BAG) )
322da2e3ebdSchin 			goto do_insert;
323da2e3ebdSchin 		else
324da2e3ebdSchin 		{	if(disc->freef)
325da2e3ebdSchin 				(*disc->freef)(dt,obj,disc);
326da2e3ebdSchin 			if(disc->link < 0)
327da2e3ebdSchin 				(*dt->memoryf)(dt,(Void_t*)r,0,disc);
328da2e3ebdSchin 			return t ? _DTOBJ(t,lk) : NIL(Void_t*);
329da2e3ebdSchin 		}
330da2e3ebdSchin 	}
331da2e3ebdSchin 	else /*if(type&(DT_DELETE|DT_DETACH))*/
332da2e3ebdSchin 	{	/* take an element out of the dictionary */
333da2e3ebdSchin 	do_delete:
334da2e3ebdSchin 		if(!t)
335da2e3ebdSchin 			return NIL(Void_t*);
336da2e3ebdSchin 		else if(p)
337da2e3ebdSchin 			p->right = t->right;
338da2e3ebdSchin 		else if((p = *s) == t)
339da2e3ebdSchin 			p = *s = t->right;
340da2e3ebdSchin 		else
341da2e3ebdSchin 		{	while(p->right != t)
342da2e3ebdSchin 				p = p->right;
343da2e3ebdSchin 			p->right = t->right;
344da2e3ebdSchin 		}
345da2e3ebdSchin 		obj = _DTOBJ(t,lk);
346da2e3ebdSchin 		dt->data->size -= 1;
347da2e3ebdSchin 		dt->data->here = p;
348da2e3ebdSchin 		if(disc->freef && (type&DT_DELETE))
349da2e3ebdSchin 			(*disc->freef)(dt,obj,disc);
350da2e3ebdSchin 		if(disc->link < 0)
351da2e3ebdSchin 			(*dt->memoryf)(dt,(Void_t*)t,0,disc);
352da2e3ebdSchin 		return obj;
353da2e3ebdSchin 	}
354da2e3ebdSchin }
355da2e3ebdSchin 
356da2e3ebdSchin static Dtmethod_t	_Dtset = { dthash, DT_SET };
357da2e3ebdSchin static Dtmethod_t	_Dtbag = { dthash, DT_BAG };
358da2e3ebdSchin __DEFINE__(Dtmethod_t*,Dtset,&_Dtset);
359da2e3ebdSchin __DEFINE__(Dtmethod_t*,Dtbag,&_Dtbag);
360da2e3ebdSchin 
361da2e3ebdSchin #ifndef KPVDEL	/* for backward compatibility - remove next time */
362da2e3ebdSchin Dtmethod_t		_Dthash = { dthash, DT_SET };
363da2e3ebdSchin __DEFINE__(Dtmethod_t*,Dthash,&_Dthash);
364da2e3ebdSchin #endif
365da2e3ebdSchin 
366da2e3ebdSchin #ifdef NoF
367da2e3ebdSchin NoF(dthash)
368da2e3ebdSchin #endif
369