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