14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1985-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 static const char id_hash[] = "\n@(#)$Id: hash (AT&T Research) 1996-08-11 $\0\n"; 314887Schin 324887Schin #include "hashlib.h" 334887Schin 344887Schin Hash_info_t hash_info = { 0 }; 354887Schin 364887Schin /* 374887Schin * create a new hash table 384887Schin */ 394887Schin 404887Schin Hash_table_t* 414887Schin hashalloc(Hash_table_t* ref, ...) 424887Schin { 434887Schin register Hash_table_t* tab; 444887Schin register Hash_table_t* ret = 0; 454887Schin register int internal; 464887Schin int n; 474887Schin va_list ap; 484887Schin va_list va[4]; 494887Schin va_list* vp = va; 504887Schin Hash_region_f region = 0; 514887Schin void* handle; 524887Schin 534887Schin va_start(ap, ref); 544887Schin 554887Schin /* 564887Schin * check for HASH_region which must be first 574887Schin */ 584887Schin 594887Schin n = va_arg(ap, int); 604887Schin if (!ref && n == HASH_region) 614887Schin { 624887Schin region = va_arg(ap, Hash_region_f); 634887Schin handle = va_arg(ap, void*); 644887Schin n = va_arg(ap, int); 654887Schin if (!(tab = (Hash_table_t*)(*region)(handle, NiL, sizeof(Hash_table_t), 0))) 664887Schin goto out; 674887Schin memset(tab, 0, sizeof(Hash_table_t)); 684887Schin } 694887Schin else if (!(tab = newof(0, Hash_table_t, 1, 0))) 704887Schin goto out; 714887Schin tab->bucketsize = (sizeof(Hash_header_t) + sizeof(char*) - 1) / sizeof(char*); 724887Schin if (ref) 734887Schin { 744887Schin tab->flags = ref->flags & ~HASH_RESET; 754887Schin tab->root = ref->root; 764887Schin internal = HASH_INTERNAL; 774887Schin } 784887Schin else 794887Schin { 804887Schin if (region) 814887Schin { 824887Schin if (!(tab->root = (Hash_root_t*)(*region)(handle, NiL, sizeof(Hash_root_t), 0))) 834887Schin goto out; 844887Schin memset(tab->root, 0, sizeof(Hash_root_t)); 854887Schin } 864887Schin else if (!(tab->root = newof(0, Hash_root_t, 1, 0))) 874887Schin goto out; 884887Schin if (!(tab->root->local = newof(0, Hash_local_t, 1, 0))) 894887Schin goto out; 904887Schin if (tab->root->local->region = region) 914887Schin tab->root->local->handle = handle; 924887Schin tab->root->meanchain = HASHMEANCHAIN; 934887Schin internal = 0; 944887Schin } 954887Schin tab->size = HASHMINSIZE; 964887Schin for (;;) 974887Schin { 984887Schin switch (n) 994887Schin { 1004887Schin case HASH_alloc: 1014887Schin if (ref) goto out; 1024887Schin tab->root->local->alloc = va_arg(ap, Hash_alloc_f); 1034887Schin break; 1044887Schin case HASH_bucketsize: 1054887Schin n = (va_arg(ap, int) + sizeof(char*) - 1) / sizeof(char*); 1064887Schin if (n > UCHAR_MAX) goto out; 1074887Schin if (n > tab->bucketsize) tab->bucketsize = n; 1084887Schin break; 1094887Schin case HASH_clear: 1104887Schin tab->flags &= ~(va_arg(ap, int) & ~internal); 1114887Schin break; 1124887Schin case HASH_compare: 1134887Schin if (ref) goto out; 1144887Schin tab->root->local->compare = va_arg(ap, Hash_compare_f); 1154887Schin break; 1164887Schin case HASH_free: 1174887Schin if (ref) goto out; 1184887Schin tab->root->local->free = va_arg(ap, Hash_free_f); 1194887Schin break; 1204887Schin case HASH_hash: 1214887Schin if (ref) goto out; 1224887Schin tab->root->local->hash = va_arg(ap, Hash_hash_f); 1234887Schin break; 1244887Schin case HASH_meanchain: 1254887Schin if (ref) goto out; 1264887Schin tab->root->meanchain = va_arg(ap, int); 1274887Schin break; 1284887Schin case HASH_name: 1294887Schin tab->name = va_arg(ap, char*); 1304887Schin break; 1314887Schin case HASH_namesize: 1324887Schin if (ref) goto out; 1334887Schin tab->root->namesize = va_arg(ap, int); 1344887Schin break; 1354887Schin case HASH_region: 1364887Schin goto out; 1374887Schin case HASH_set: 1384887Schin tab->flags |= (va_arg(ap, int) & ~internal); 1394887Schin break; 1404887Schin case HASH_size: 1414887Schin tab->size = va_arg(ap, int); 1424887Schin if (tab->size & (tab->size - 1)) tab->flags |= HASH_FIXED; 1434887Schin break; 1444887Schin case HASH_table: 1454887Schin tab->table = va_arg(ap, Hash_bucket_t**); 1464887Schin tab->flags |= HASH_STATIC; 1474887Schin break; 1484887Schin case HASH_va_list: 1494887Schin if (vp < &va[elementsof(va)]) 1504887Schin { 1514887Schin va_copy(*vp, ap); 1524887Schin vp++; 1534887Schin } 1544887Schin va_copy(ap, va_listval(va_arg(ap, va_listarg))); 1554887Schin break; 1564887Schin case 0: 1574887Schin if (vp > va) 1584887Schin { 1594887Schin vp--; 1604887Schin va_copy(ap, *vp); 1614887Schin break; 1624887Schin } 1634887Schin if (tab->flags & HASH_SCOPE) 1644887Schin { 1654887Schin if (!(tab->scope = ref)) goto out; 1664887Schin ref->frozen++; 1674887Schin } 1684887Schin if (!tab->table) 1694887Schin { 1704887Schin if (region) 1714887Schin { 1724887Schin if (!(tab->table = (Hash_bucket_t**)(*region)(handle, NiL, sizeof(Hash_bucket_t*) * tab->size, 0))) 1734887Schin goto out; 1744887Schin memset(tab->table, 0, sizeof(Hash_bucket_t*) * tab->size); 1754887Schin } 1764887Schin else if (!(tab->table = newof(0, Hash_bucket_t*, tab->size, 0))) goto out; 1774887Schin } 1784887Schin if (!ref) 1794887Schin { 1804887Schin tab->root->flags = tab->flags & HASH_INTERNAL; 1814887Schin tab->root->next = hash_info.list; 1824887Schin hash_info.list = tab->root; 1834887Schin } 1844887Schin if (!region) 1854887Schin { 1864887Schin tab->next = tab->root->references; 1874887Schin tab->root->references = tab; 1884887Schin } 1894887Schin ret = tab; 1904887Schin goto out; 1914887Schin default: 1924887Schin goto out; 1934887Schin } 1944887Schin n = va_arg(ap, int); 1954887Schin } 1964887Schin out: 1974887Schin va_end(ap); 1984887Schin if (!ret) hashfree(tab); 1994887Schin return(ret); 2004887Schin } 201