2
Copyright (c) 1991-1999 Thomas T. Wetmore IV
4
Permission is hereby granted, free of charge, to any person
5
obtaining a copy of this software and associated documentation
6
files (the "Software"), to deal in the Software without
7
restriction, including without limitation the rights to use, copy,
8
modify, merge, publish, distribute, sublicense, and/or sell copies
9
of the Software, and to permit persons to whom the Software is
10
furnished to do so, subject to the following conditions:
12
The above copyright notice and this permission notice shall be
13
included in all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
hashtab contains a simple hash table implementation
27
keys are strings (hash table copies & manages memory itself for keys
28
values (void * pointers, they are client's responsibility to free)
34
/*********************************************
35
* local enums & defines
36
*********************************************/
38
#define MAXHASH_DEF 512
40
/*********************************************
42
*********************************************/
44
/* entry in hash table */
49
struct tag_hashent *enext;
51
typedef struct tag_hashent *HASHENT;
57
INT count; /* #entries */
60
/* typedef struct tag_hashtab *HASHTAB */ /* in hashtab.h */
62
/* hash table iterator */
63
struct tag_hashtab_iter {
70
/*********************************************
71
* local function prototypes
72
*********************************************/
74
static HASHENT create_entry(CNSTRING key, HVALUE val);
75
static HASHENT fndentry(HASHTAB tab, CNSTRING key);
76
static INT hash(HASHTAB tab, CNSTRING key);
78
/*********************************************
80
*********************************************/
82
/* fixed magic strings to verify object identity */
83
static CNSTRING hashtab_magic = "HASHTAB_MAGIC";
84
static CNSTRING hashent_magic = "HASHENT_MAGIC";
85
static CNSTRING hashtab_iter_magic = "HASHTAB_ITER_MAGIC";
87
/*********************************************
88
* local & exported function definitions
90
*********************************************/
92
/*================================
93
* create_hashtab -- Create & return new hash table
94
*==============================*/
98
HASHTAB tab = (HASHTAB)stdalloc(sizeof(*tab));
99
tab->magic = hashtab_magic;
100
tab->maxhash = MAXHASH_DEF;
101
tab->entries = (HASHENT *)stdalloc(tab->maxhash * sizeof(HASHENT));
104
/*================================
105
* destroy_hashtab -- Destroy hash table
106
*==============================*/
108
destroy_hashtab (HASHTAB tab, DELFUNC func)
112
ASSERT(tab->magic == hashtab_magic);
113
for (i=0; i<tab->maxhash; ++i) {
114
HASHENT entry = tab->entries[i];
117
ASSERT(entry->magic == hashent_magic);
122
strfree((STRING *)&entry->ekey);
127
stdfree(tab->entries);
131
/*======================
132
* get_hashtab_count -- Return number of elements currently contained
133
*====================*/
135
get_hashtab_count (HASHTAB tab)
138
ASSERT(tab->magic == hashtab_magic);
142
/*======================
143
* insert_hashtab -- Add new value to hash table
144
* return previous value for this key, if any
145
*====================*/
147
insert_hashtab (HASHTAB tab, CNSTRING key, HVALUE val)
153
ASSERT(tab->magic == hashtab_magic);
155
/* find appropriate has chain */
156
hval = hash(tab, key);
157
if (!tab->entries[hval]) {
158
/* table lacks entry for this key, create it */
159
entry = create_entry(key, val);
160
tab->entries[hval] = entry;
162
return 0; /* no old value */
164
entry = tab->entries[hval];
166
ASSERT(entry->magic == hashent_magic);
167
if (eqstr(key, entry->ekey)) {
168
/* table already has entry for this key, replace it */
169
HVALUE old = entry->val;
174
/* table lacks entry for this key, create it */
175
HASHENT newent = create_entry(key, val);
176
entry->enext = newent;
178
return 0; /* no old value */
180
entry = entry->enext;
183
/*======================
184
* remove_hashtab -- Remove element from table
185
* return old value if found
186
*====================*/
188
remove_hashtab (HASHTAB tab, CNSTRING key)
192
HASHENT preve=0, thise=0;
195
ASSERT(tab->magic == hashtab_magic);
197
hval = hash(tab, key);
198
thise = tab->entries[hval];
199
while (thise && nestr(key, thise->ekey)) {
200
ASSERT(thise->magic == hashent_magic);
202
thise = thise->enext;
204
if (!thise) return 0;
206
preve->enext = thise->enext;
208
tab->entries[hval] = thise->enext;
211
strfree((STRING *)&thise->ekey);
217
/*======================
218
* find_hashtab -- Find and return value
219
* set optional present arg to indicate whether value was found
220
*====================*/
222
find_hashtab (HASHTAB tab, CNSTRING key, BOOLEAN * present)
227
ASSERT(tab->magic == hashtab_magic);
229
entry = fndentry(tab, key);
230
if (present) *present = !!entry;
231
if (!entry) return 0;
233
ASSERT(entry->magic == hashent_magic);
236
/*======================
237
* in_hashtab -- Find and return value
238
*====================*/
240
in_hashtab (HASHTAB tab, CNSTRING key)
245
ASSERT(tab->magic == hashtab_magic);
247
entry = fndentry(tab, key);
250
/*================================
251
* fndentry -- Find entry in table
252
*==============================*/
254
fndentry (HASHTAB tab, CNSTRING key)
257
if (!tab || !key) return NULL;
258
entry = tab->entries[hash(tab, key)];
260
if (eqstr(key, entry->ekey)) return entry;
261
entry = entry->enext;
265
/*======================
266
* hash -- Hash function
267
*====================*/
269
hash (HASHTAB tab, CNSTRING key)
271
const unsigned char *ckey = (const unsigned char *)key;
275
hval %= tab->maxhash;
276
ASSERT(hval>=0 && hval < tab->maxhash);
279
/*================================
280
* create_entry -- Create and return new hash entry
281
*==============================*/
283
create_entry (CNSTRING key, HVALUE val)
285
HASHENT entry = (HASHENT)stdalloc(sizeof(*entry));
286
entry->magic = hashent_magic;
287
entry->ekey = strsave(key);
291
/*================================
292
* begin_hashtab -- Create new iterator for hash table
293
*==============================*/
295
begin_hashtab (HASHTAB tab)
297
HASHTAB_ITER tabit=0;
299
ASSERT(tab->magic == hashtab_magic);
301
tabit = (HASHTAB_ITER)stdalloc(sizeof(*tabit));
302
tabit->magic = hashtab_iter_magic;
303
tabit->hashtab = tab;
304
/* table iterator starts at index=0, enext=0 */
305
/* stdalloc gave us all zero memory */
308
/*================================
309
* next_hashtab -- Advance hash table iterator
310
* If not finished, set pointers and return TRUE
311
* If no more entries, return FALSE
312
*==============================*/
314
next_hashtab (HASHTAB_ITER tabit, CNSTRING *pkey, HVALUE *pval)
318
ASSERT(tabit->magic == hashtab_iter_magic);
320
if (!tabit->hashtab) return FALSE;
321
tab = tabit->hashtab;
323
if (tabit->index == -1 || tab->count == 0)
326
/* continue current hash chain */
328
tabit->enext = tabit->enext->enext;
333
/* find next populated hash chain */
334
for ( ; tabit->index < tab->maxhash; ++tabit->index) {
335
tabit->enext = tab->entries[tabit->index];
339
/* finished (ran out of hash chains) */
346
*pkey = tabit->enext->ekey;
347
*pval = tabit->enext->val;
351
/*================================
352
* end_hashtab -- Release/destroy hash table iterator
353
*==============================*/
355
end_hashtab (HASHTAB_ITER * ptabit)
357
HASHTAB_ITER tabit = *ptabit;
359
ASSERT(tabit->magic == hashtab_iter_magic);
361
memset(tabit, 0, sizeof(*tabit));