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