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