1*4887Schin /*********************************************************************** 2*4887Schin * * 3*4887Schin * This software is part of the ast package * 4*4887Schin * Copyright (c) 1985-2007 AT&T Knowledge Ventures * 5*4887Schin * and is licensed under the * 6*4887Schin * Common Public License, Version 1.0 * 7*4887Schin * by AT&T Knowledge Ventures * 8*4887Schin * * 9*4887Schin * A copy of the License is available at * 10*4887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 11*4887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*4887Schin * * 13*4887Schin * Information and Software Systems Research * 14*4887Schin * AT&T Research * 15*4887Schin * Florham Park NJ * 16*4887Schin * * 17*4887Schin * Glenn Fowler <gsf@research.att.com> * 18*4887Schin * David Korn <dgk@research.att.com> * 19*4887Schin * Phong Vo <kpv@research.att.com> * 20*4887Schin * * 21*4887Schin ***********************************************************************/ 22*4887Schin #pragma prototyped 23*4887Schin /* 24*4887Schin * Glenn Fowler 25*4887Schin * AT&T Research 26*4887Schin * 27*4887Schin * hash table library 28*4887Schin */ 29*4887Schin 30*4887Schin #include "hashlib.h" 31*4887Schin 32*4887Schin /* 33*4887Schin * hash table lookup 34*4887Schin */ 35*4887Schin 36*4887Schin char* 37*4887Schin hashlook(register Hash_table_t* tab, const char* name, long flags, const char* value) 38*4887Schin { 39*4887Schin register Hash_bucket_t* b; 40*4887Schin register unsigned int n; 41*4887Schin register Hash_last_t* last; 42*4887Schin Hash_table_t* top; 43*4887Schin Hash_bucket_t* prev; 44*4887Schin unsigned int i; 45*4887Schin 46*4887Schin if ((flags & (HASH_LOOKUP|HASH_INTERNAL)) == (HASH_LOOKUP|HASH_INTERNAL)) 47*4887Schin { 48*4887Schin register char* s1; 49*4887Schin register const char* s2; 50*4887Schin register int c; 51*4887Schin 52*4887Schin if (flags & HASH_HASHED) n = *((unsigned int*)value); 53*4887Schin else 54*4887Schin { 55*4887Schin s2 = name; 56*4887Schin n = 0; 57*4887Schin while (c = *s2++) HASHPART(n, c); 58*4887Schin } 59*4887Schin i = n; 60*4887Schin for (;;) 61*4887Schin { 62*4887Schin HASHMOD(tab, n); 63*4887Schin for (b = tab->table[n]; b; b = b->next) 64*4887Schin { 65*4887Schin s1 = hashname(b); 66*4887Schin s2 = name; 67*4887Schin while ((c = *s1++) == *s2++) 68*4887Schin if (!c) return((flags & HASH_VALUE) ? b->value : (char*)b); 69*4887Schin } 70*4887Schin if (!(tab = tab->scope) || (flags & HASH_NOSCOPE)) 71*4887Schin return(0); 72*4887Schin n = i; 73*4887Schin } 74*4887Schin } 75*4887Schin tab->root->accesses++; 76*4887Schin top = tab; 77*4887Schin last = &tab->root->last; 78*4887Schin if (name) 79*4887Schin { 80*4887Schin last->table = tab; 81*4887Schin if (flags & (HASH_BUCKET|HASH_INSTALL)) 82*4887Schin { 83*4887Schin last->bucket = (Hash_bucket_t*)name; 84*4887Schin name = hashname(last->bucket); 85*4887Schin } 86*4887Schin else last->bucket = 0; 87*4887Schin last->name = name; 88*4887Schin if (flags & HASH_BUCKET) n = last->bucket->hash; 89*4887Schin else if (tab->flags & HASH_HASHED) 90*4887Schin { 91*4887Schin n = (unsigned int)integralof(name); 92*4887Schin if (!(flags & HASH_HASHED)) n >>= 3; 93*4887Schin } 94*4887Schin else if (flags & HASH_HASHED) n = *((unsigned int*)value); 95*4887Schin else HASH(tab->root, name, n); 96*4887Schin last->hash = i = HASHVAL(n); 97*4887Schin for (;;) 98*4887Schin { 99*4887Schin HASHMOD(tab, n); 100*4887Schin for (prev = 0, b = tab->table[n]; b; prev = b, b = b->next) 101*4887Schin { 102*4887Schin if (i == HASHVAL(b->hash) && ((b->hash & (HASH_DELETED|HASH_OPAQUED)) != HASH_DELETED || (flags & (HASH_CREATE|HASH_DELETE|HASH_INSTALL|HASH_RENAME)))) 103*4887Schin { 104*4887Schin if (!tab->root->local->compare) 105*4887Schin { 106*4887Schin register char* s1 = hashname(b); 107*4887Schin register const char* s2 = name; 108*4887Schin 109*4887Schin if (tab->root->namesize) 110*4887Schin { 111*4887Schin register char* s3 = s1 + tab->root->namesize; 112*4887Schin 113*4887Schin while (*s1++ == *s2++) 114*4887Schin if (s1 >= s3) goto found; 115*4887Schin } 116*4887Schin else while (*s1 == *s2++) 117*4887Schin if (!*s1++) goto found; 118*4887Schin } 119*4887Schin else if (tab->root->namesize) 120*4887Schin { 121*4887Schin if (!(*tab->root->local->compare)(hashname(b), name, tab->root->namesize)) goto found; 122*4887Schin } 123*4887Schin else if (!(*tab->root->local->compare)(hashname(b), name)) goto found; 124*4887Schin } 125*4887Schin tab->root->collisions++; 126*4887Schin } 127*4887Schin if (!tab->scope || (flags & (HASH_CREATE|HASH_INSTALL|HASH_NOSCOPE)) == HASH_NOSCOPE) break; 128*4887Schin tab = tab->scope; 129*4887Schin n = i; 130*4887Schin } 131*4887Schin } 132*4887Schin else 133*4887Schin { 134*4887Schin tab = last->table; 135*4887Schin name = last->name; 136*4887Schin n = i = last->hash; 137*4887Schin prev = 0; 138*4887Schin HASHMOD(tab, n); 139*4887Schin if (b = last->bucket) 140*4887Schin { 141*4887Schin /* 142*4887Schin * found the bucket 143*4887Schin */ 144*4887Schin 145*4887Schin found: 146*4887Schin if (prev && !tab->frozen) 147*4887Schin { 148*4887Schin /* 149*4887Schin * migrate popular buckets to the front 150*4887Schin */ 151*4887Schin 152*4887Schin prev->next = b->next; 153*4887Schin b->next = tab->table[n]; 154*4887Schin tab->table[n] = b; 155*4887Schin } 156*4887Schin switch (flags & (HASH_CREATE|HASH_DELETE|HASH_INSTALL|HASH_RENAME)) 157*4887Schin { 158*4887Schin case HASH_CREATE: 159*4887Schin case HASH_CREATE|HASH_INSTALL: 160*4887Schin case HASH_INSTALL: 161*4887Schin if (tab != top && !(flags & HASH_SCOPE)) break; 162*4887Schin if (flags & HASH_OPAQUE) b->hash |= HASH_OPAQUED; 163*4887Schin goto exists; 164*4887Schin 165*4887Schin case HASH_DELETE: 166*4887Schin value = 0; 167*4887Schin if (tab == top || (flags & HASH_SCOPE)) 168*4887Schin { 169*4887Schin if (flags & HASH_OPAQUE) b->hash &= ~HASH_OPAQUED; 170*4887Schin else if (!(tab->root->flags & HASH_BUCKET)) 171*4887Schin { 172*4887Schin if (tab->root->local->free && b->value) 173*4887Schin { 174*4887Schin (*tab->root->local->free)(b->value); 175*4887Schin b->value = 0; 176*4887Schin } 177*4887Schin else if (tab->flags & HASH_VALUE) 178*4887Schin { 179*4887Schin value = b->value; 180*4887Schin b->value = 0; 181*4887Schin } 182*4887Schin } 183*4887Schin tab->buckets--; 184*4887Schin if (tab->frozen || (b->hash & HASH_OPAQUED)) b->hash |= HASH_DELETED; 185*4887Schin else 186*4887Schin { 187*4887Schin tab->table[n] = b->next; 188*4887Schin name = (b->hash & HASH_FREENAME) ? (char*)b->name : (char*)0; 189*4887Schin if (tab->root->local->free && (tab->root->flags & HASH_BUCKET)) (*tab->root->local->free)((char*)b); 190*4887Schin else if (!(b->hash & HASH_KEEP)) 191*4887Schin { 192*4887Schin if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, b, 0, 0); 193*4887Schin else free(b); 194*4887Schin } 195*4887Schin if (name) 196*4887Schin { 197*4887Schin if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, (char*)name, 0, 0); 198*4887Schin else free((char*)name); 199*4887Schin } 200*4887Schin } 201*4887Schin } 202*4887Schin return((char*)value); 203*4887Schin 204*4887Schin case HASH_RENAME: 205*4887Schin if (tab != top || tab->frozen || (b->hash & (HASH_KEEP|HASH_OPAQUED)) || hashlook(top, value, (flags&(HASH_HASHED|HASH_INTERNAL))|HASH_LOOKUP, NiL)) 206*4887Schin return(0); 207*4887Schin name = (char*)b->name; 208*4887Schin if (!(tab->flags & HASH_ALLOCATE)) b->name = (char*)value; 209*4887Schin else if (b->name && tab->root->namesize) 210*4887Schin { 211*4887Schin memcpy(b->name, value, tab->root->namesize); 212*4887Schin name = 0; 213*4887Schin } 214*4887Schin else 215*4887Schin { 216*4887Schin int m; 217*4887Schin char* t; 218*4887Schin 219*4887Schin if (!(i = tab->bucketsize)) 220*4887Schin i = (sizeof(Hash_bucket_t) + sizeof(char*) - 1) / sizeof(char*); 221*4887Schin i *= sizeof(char*); 222*4887Schin if (b->name == ((char*)b + i) && strlen(b->name) <= (m = strlen(value))) 223*4887Schin { 224*4887Schin strcpy(b->name, value); 225*4887Schin name = 0; 226*4887Schin } 227*4887Schin else 228*4887Schin { 229*4887Schin m++; 230*4887Schin if (!(t = tab->root->local->region ? (char*)(*tab->root->local->region)(tab->root->local->handle, NiL, m, 0) : (char*)malloc(m))) 231*4887Schin return(0); 232*4887Schin b->name = strcpy(t, value); 233*4887Schin } 234*4887Schin } 235*4887Schin if (name && (b->hash & HASH_FREENAME)) 236*4887Schin { 237*4887Schin b->hash &= ~HASH_FREENAME; 238*4887Schin if (tab->root->local->region) (*tab->root->local->region)(tab->root->local->handle, (char*)name, 0, 0); 239*4887Schin else free((char*)name); 240*4887Schin } 241*4887Schin tab->buckets--; 242*4887Schin tab->table[n] = b->next; 243*4887Schin flags = HASH_CREATE|HASH_INSTALL; 244*4887Schin last->bucket = b; 245*4887Schin i = last->hash; 246*4887Schin goto create; 247*4887Schin 248*4887Schin default: 249*4887Schin if (!(b->hash & HASH_DELETED)) goto exists; 250*4887Schin return(0); 251*4887Schin } 252*4887Schin } 253*4887Schin } 254*4887Schin if (!(flags & (HASH_CREATE|HASH_INSTALL))) return(0); 255*4887Schin 256*4887Schin /* 257*4887Schin * create a new bucket 258*4887Schin */ 259*4887Schin 260*4887Schin create: 261*4887Schin if (tab == top) prev = 0; 262*4887Schin else 263*4887Schin { 264*4887Schin if (prev = b) 265*4887Schin { 266*4887Schin name = (b->hash & HASH_HIDES) ? b->name : (char*)b; 267*4887Schin i |= HASH_HIDES; 268*4887Schin } 269*4887Schin if (!(flags & HASH_SCOPE)) tab = top; 270*4887Schin } 271*4887Schin 272*4887Schin /* 273*4887Schin * check for table expansion 274*4887Schin */ 275*4887Schin 276*4887Schin if (!tab->frozen && !(tab->flags & HASH_FIXED) && tab->buckets > tab->root->meanchain * tab->size) 277*4887Schin hashsize(tab, tab->size << 1); 278*4887Schin if (flags & HASH_INSTALL) 279*4887Schin { 280*4887Schin b = last->bucket; 281*4887Schin i |= HASH_KEEP; 282*4887Schin } 283*4887Schin else 284*4887Schin { 285*4887Schin int m = tab->bucketsize * sizeof(char*); 286*4887Schin 287*4887Schin if (flags & HASH_VALUE) 288*4887Schin { 289*4887Schin tab->flags |= HASH_VALUE; 290*4887Schin if (m < sizeof(Hash_bucket_t)) 291*4887Schin { 292*4887Schin tab->bucketsize = (sizeof(Hash_bucket_t) + sizeof(char*) - 1) / sizeof(char*); 293*4887Schin m = tab->bucketsize * sizeof(char*); 294*4887Schin } 295*4887Schin n = m; 296*4887Schin } 297*4887Schin else if (!(n = HASH_SIZEOF(flags))) 298*4887Schin { 299*4887Schin if (!(flags & HASH_FIXED)) n = m; 300*4887Schin else if ((n = (int)integralof(value)) < m) n = m; 301*4887Schin } 302*4887Schin else if (n < m) n = m; 303*4887Schin if (!prev && (tab->flags & HASH_ALLOCATE)) 304*4887Schin { 305*4887Schin m = tab->root->namesize ? tab->root->namesize : strlen(name) + 1; 306*4887Schin if (tab->root->local->region) 307*4887Schin { 308*4887Schin if (!(b = (Hash_bucket_t*)(*tab->root->local->region)(tab->root->local->handle, NiL, n + m, 0))) 309*4887Schin return(0); 310*4887Schin memset(b, 0, n + m); 311*4887Schin } 312*4887Schin else if (!(b = newof(0, Hash_bucket_t, 0, n + m))) 313*4887Schin return(0); 314*4887Schin b->name = (char*)b + n; 315*4887Schin memcpy(b->name, name, m); 316*4887Schin } 317*4887Schin else 318*4887Schin { 319*4887Schin if (tab->root->local->region) 320*4887Schin { 321*4887Schin if (!(b = (Hash_bucket_t*)(*tab->root->local->region)(tab->root->local->handle, NiL, n, 0))) 322*4887Schin return(0); 323*4887Schin memset(b, 0, n); 324*4887Schin } 325*4887Schin else if (!(b = newof(0, Hash_bucket_t, 0, n))) 326*4887Schin return(0); 327*4887Schin b->name = (char*)name; 328*4887Schin } 329*4887Schin } 330*4887Schin b->hash = n = i; 331*4887Schin HASHMOD(tab, n); 332*4887Schin b->next = tab->table[n]; 333*4887Schin tab->table[n] = b; 334*4887Schin tab->buckets++; 335*4887Schin if (flags & HASH_OPAQUE) 336*4887Schin { 337*4887Schin tab->buckets--; 338*4887Schin b->hash |= HASH_DELETED|HASH_OPAQUED; 339*4887Schin return(0); 340*4887Schin } 341*4887Schin 342*4887Schin /* 343*4887Schin * finally got the bucket 344*4887Schin */ 345*4887Schin 346*4887Schin exists: 347*4887Schin if (b->hash & HASH_DELETED) 348*4887Schin { 349*4887Schin b->hash &= ~HASH_DELETED; 350*4887Schin tab->buckets++; 351*4887Schin } 352*4887Schin last->bucket = b; 353*4887Schin last->table = tab; 354*4887Schin switch (flags & (HASH_CREATE|HASH_VALUE)) 355*4887Schin { 356*4887Schin case HASH_CREATE|HASH_VALUE: 357*4887Schin if (tab->root->local->free && !(tab->root->flags & HASH_BUCKET) && b->value) (*tab->root->local->free)(b->value); 358*4887Schin if (value && tab->root->local->alloc) value = (*tab->root->local->alloc)((unsigned int)integralof(value)); 359*4887Schin b->value = (char*)value; 360*4887Schin return((char*)hashname(b)); 361*4887Schin case HASH_VALUE: 362*4887Schin return(b->value); 363*4887Schin default: 364*4887Schin return((char*)b); 365*4887Schin } 366*4887Schin } 367