hash.c revision 1.4 1 1.1 gwr /************************************************************************
2 1.1 gwr Copyright 1988, 1991 by Carnegie Mellon University
3 1.1 gwr
4 1.1 gwr All Rights Reserved
5 1.1 gwr
6 1.1 gwr Permission to use, copy, modify, and distribute this software and its
7 1.1 gwr documentation for any purpose and without fee is hereby granted, provided
8 1.1 gwr that the above copyright notice appear in all copies and that both that
9 1.1 gwr copyright notice and this permission notice appear in supporting
10 1.1 gwr documentation, and that the name of Carnegie Mellon University not be used
11 1.1 gwr in advertising or publicity pertaining to distribution of the software
12 1.1 gwr without specific, written prior permission.
13 1.1 gwr
14 1.1 gwr CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
15 1.1 gwr SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
16 1.1 gwr IN NO EVENT SHALL CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
17 1.1 gwr DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
18 1.1 gwr PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
19 1.1 gwr ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20 1.1 gwr SOFTWARE.
21 1.1 gwr ************************************************************************/
22 1.1 gwr
23 1.4 lukem #include <sys/cdefs.h>
24 1.1 gwr #ifndef lint
25 1.4 lukem __RCSID("$NetBSD: hash.c,v 1.4 1998/03/14 04:39:54 lukem Exp $");
26 1.1 gwr #endif
27 1.1 gwr
28 1.1 gwr
29 1.1 gwr /*
30 1.1 gwr * Generalized hash table ADT
31 1.1 gwr *
32 1.1 gwr * Provides multiple, dynamically-allocated, variable-sized hash tables on
33 1.1 gwr * various data and keys.
34 1.1 gwr *
35 1.1 gwr * This package attempts to follow some of the coding conventions suggested
36 1.1 gwr * by Bob Sidebotham and the AFS Clean Code Committee of the
37 1.1 gwr * Information Technology Center at Carnegie Mellon.
38 1.1 gwr */
39 1.1 gwr
40 1.1 gwr
41 1.1 gwr #include <sys/types.h>
42 1.1 gwr #include <stdlib.h>
43 1.1 gwr
44 1.1 gwr #ifndef USE_BFUNCS
45 1.1 gwr #include <memory.h>
46 1.1 gwr /* Yes, memcpy is OK here (no overlapped copies). */
47 1.1 gwr #define bcopy(a,b,c) memcpy(b,a,c)
48 1.1 gwr #define bzero(p,l) memset(p,0,l)
49 1.1 gwr #define bcmp(a,b,c) memcmp(a,b,c)
50 1.1 gwr #endif
51 1.1 gwr
52 1.1 gwr #include "hash.h"
53 1.1 gwr
54 1.1 gwr #define TRUE 1
55 1.1 gwr #define FALSE 0
56 1.1 gwr #ifndef NULL
57 1.1 gwr #define NULL 0
58 1.1 gwr #endif
59 1.1 gwr
60 1.1 gwr /*
61 1.1 gwr * This can be changed to make internal routines visible to debuggers, etc.
62 1.1 gwr */
63 1.1 gwr #ifndef PRIVATE
64 1.1 gwr #define PRIVATE static
65 1.1 gwr #endif
66 1.1 gwr
67 1.1 gwr #ifdef __STDC__
68 1.1 gwr #define P(args) args
69 1.1 gwr #else
70 1.1 gwr #define P(args) ()
71 1.1 gwr #endif
72 1.1 gwr
73 1.1 gwr PRIVATE void hashi_FreeMembers P((hash_member *, hash_freefp));
74 1.1 gwr
75 1.1 gwr #undef P
76 1.1 gwr
77 1.1 gwr
79 1.1 gwr
80 1.1 gwr /*
81 1.1 gwr * Hash table initialization routine.
82 1.1 gwr *
83 1.1 gwr * This routine creates and intializes a hash table of size "tablesize"
84 1.1 gwr * entries. Successful calls return a pointer to the hash table (which must
85 1.1 gwr * be passed to other hash routines to identify the hash table). Failed
86 1.1 gwr * calls return NULL.
87 1.1 gwr */
88 1.1 gwr
89 1.1 gwr hash_tbl *
90 1.1 gwr hash_Init(tablesize)
91 1.1 gwr unsigned tablesize;
92 1.1 gwr {
93 1.1 gwr register hash_tbl *hashtblptr;
94 1.1 gwr register unsigned totalsize;
95 1.1 gwr
96 1.1 gwr if (tablesize > 0) {
97 1.1 gwr totalsize = sizeof(hash_tbl)
98 1.1 gwr + sizeof(hash_member *) * (tablesize - 1);
99 1.1 gwr hashtblptr = (hash_tbl *) malloc(totalsize);
100 1.1 gwr if (hashtblptr) {
101 1.1 gwr bzero((char *) hashtblptr, totalsize);
102 1.1 gwr hashtblptr->size = tablesize; /* Success! */
103 1.1 gwr hashtblptr->bucketnum = 0;
104 1.1 gwr hashtblptr->member = (hashtblptr->table)[0];
105 1.1 gwr }
106 1.1 gwr } else {
107 1.1 gwr hashtblptr = NULL; /* Disallow zero-length tables */
108 1.1 gwr }
109 1.1 gwr return hashtblptr; /* NULL if failure */
110 1.1 gwr }
111 1.1 gwr
112 1.1 gwr
114 1.1 gwr
115 1.1 gwr /*
116 1.1 gwr * Frees an entire linked list of bucket members (used in the open
117 1.1 gwr * hashing scheme). Does nothing if the passed pointer is NULL.
118 1.1 gwr */
119 1.1 gwr
120 1.1 gwr PRIVATE void
121 1.1 gwr hashi_FreeMembers(bucketptr, free_data)
122 1.1 gwr hash_member *bucketptr;
123 1.1 gwr hash_freefp free_data;
124 1.1 gwr {
125 1.1 gwr hash_member *nextbucket;
126 1.1 gwr while (bucketptr) {
127 1.1 gwr nextbucket = bucketptr->next;
128 1.1 gwr (*free_data) (bucketptr->data);
129 1.1 gwr free((char *) bucketptr);
130 1.1 gwr bucketptr = nextbucket;
131 1.1 gwr }
132 1.1 gwr }
133 1.1 gwr
134 1.1 gwr
135 1.1 gwr
136 1.1 gwr
137 1.1 gwr /*
138 1.1 gwr * This routine re-initializes the hash table. It frees all the allocated
139 1.1 gwr * memory and resets all bucket pointers to NULL.
140 1.1 gwr */
141 1.1 gwr
142 1.1 gwr void
143 1.1 gwr hash_Reset(hashtable, free_data)
144 1.1 gwr hash_tbl *hashtable;
145 1.1 gwr hash_freefp free_data;
146 1.1 gwr {
147 1.1 gwr hash_member **bucketptr;
148 1.1 gwr unsigned i;
149 1.1 gwr
150 1.1 gwr bucketptr = hashtable->table;
151 1.1 gwr for (i = 0; i < hashtable->size; i++) {
152 1.1 gwr hashi_FreeMembers(*bucketptr, free_data);
153 1.1 gwr *bucketptr++ = NULL;
154 1.1 gwr }
155 1.1 gwr hashtable->bucketnum = 0;
156 1.1 gwr hashtable->member = (hashtable->table)[0];
157 1.1 gwr }
158 1.1 gwr
159 1.1 gwr
161 1.1 gwr
162 1.1 gwr /*
163 1.1 gwr * Generic hash function to calculate a hash code from the given string.
164 1.1 gwr *
165 1.1 gwr * For each byte of the string, this function left-shifts the value in an
166 1.1 gwr * accumulator and then adds the byte into the accumulator. The contents of
167 1.1 gwr * the accumulator is returned after the entire string has been processed.
168 1.1 gwr * It is assumed that this result will be used as the "hashcode" parameter in
169 1.1 gwr * calls to other functions in this package. These functions automatically
170 1.1 gwr * adjust the hashcode for the size of each hashtable.
171 1.1 gwr *
172 1.1 gwr * This algorithm probably works best when the hash table size is a prime
173 1.1 gwr * number.
174 1.1 gwr *
175 1.1 gwr * Hopefully, this function is better than the previous one which returned
176 1.1 gwr * the sum of the squares of all the bytes. I'm still open to other
177 1.1 gwr * suggestions for a default hash function. The programmer is more than
178 1.1 gwr * welcome to supply his/her own hash function as that is one of the design
179 1.1 gwr * features of this package.
180 1.1 gwr */
181 1.1 gwr
182 1.1 gwr unsigned
183 1.1 gwr hash_HashFunction(string, len)
184 1.1 gwr unsigned char *string;
185 1.1 gwr register unsigned len;
186 1.1 gwr {
187 1.1 gwr register unsigned accum;
188 1.1 gwr
189 1.1 gwr accum = 0;
190 1.1 gwr for (; len > 0; len--) {
191 1.1 gwr accum <<= 1;
192 1.1 gwr accum += (unsigned) (*string++ & 0xFF);
193 1.1 gwr }
194 1.1 gwr return accum;
195 1.1 gwr }
196 1.1 gwr
197 1.1 gwr
199 1.1 gwr
200 1.1 gwr /*
201 1.1 gwr * Returns TRUE if at least one entry for the given key exists; FALSE
202 1.1 gwr * otherwise.
203 1.1 gwr */
204 1.1 gwr
205 1.1 gwr int
206 1.1 gwr hash_Exists(hashtable, hashcode, compare, key)
207 1.1 gwr hash_tbl *hashtable;
208 1.1 gwr unsigned hashcode;
209 1.1 gwr hash_cmpfp compare;
210 1.1 gwr hash_datum *key;
211 1.1 gwr {
212 1.1 gwr register hash_member *memberptr;
213 1.1 gwr
214 1.1 gwr memberptr = (hashtable->table)[hashcode % (hashtable->size)];
215 1.1 gwr while (memberptr) {
216 1.1 gwr if ((*compare) (key, memberptr->data)) {
217 1.1 gwr return TRUE; /* Entry does exist */
218 1.1 gwr }
219 1.1 gwr memberptr = memberptr->next;
220 1.1 gwr }
221 1.1 gwr return FALSE; /* Entry does not exist */
222 1.1 gwr }
223 1.1 gwr
224 1.1 gwr
226 1.1 gwr
227 1.1 gwr /*
228 1.1 gwr * Insert the data item "element" into the hash table using "hashcode"
229 1.1 gwr * to determine the bucket number, and "compare" and "key" to determine
230 1.1 gwr * its uniqueness.
231 1.1 gwr *
232 1.1 gwr * If the insertion is successful 0 is returned. If a matching entry
233 1.1 gwr * already exists in the given bucket of the hash table, or some other error
234 1.1 gwr * occurs, -1 is returned and the insertion is not done.
235 1.1 gwr */
236 1.1 gwr
237 1.1 gwr int
238 1.1 gwr hash_Insert(hashtable, hashcode, compare, key, element)
239 1.1 gwr hash_tbl *hashtable;
240 1.1 gwr unsigned hashcode;
241 1.1 gwr hash_cmpfp compare;
242 1.1 gwr hash_datum *key, *element;
243 1.1 gwr {
244 1.1 gwr hash_member *temp;
245 1.1 gwr
246 1.1 gwr hashcode %= hashtable->size;
247 1.1 gwr if (hash_Exists(hashtable, hashcode, compare, key)) {
248 1.1 gwr return -1; /* At least one entry already exists */
249 1.1 gwr }
250 1.1 gwr temp = (hash_member *) malloc(sizeof(hash_member));
251 1.1 gwr if (!temp)
252 1.1 gwr return -1; /* malloc failed! */
253 1.1 gwr
254 1.1 gwr temp->data = element;
255 1.1 gwr temp->next = (hashtable->table)[hashcode];
256 1.1 gwr (hashtable->table)[hashcode] = temp;
257 1.1 gwr return 0; /* Success */
258 1.1 gwr }
259 1.1 gwr
260 1.1 gwr
262 1.1 gwr
263 1.1 gwr /*
264 1.1 gwr * Delete all data elements which match the given key. If at least one
265 1.1 gwr * element is found and the deletion is successful, 0 is returned.
266 1.1 gwr * If no matching elements can be found in the hash table, -1 is returned.
267 1.1 gwr */
268 1.1 gwr
269 1.1 gwr int
270 1.1 gwr hash_Delete(hashtable, hashcode, compare, key, free_data)
271 1.1 gwr hash_tbl *hashtable;
272 1.1 gwr unsigned hashcode;
273 1.1 gwr hash_cmpfp compare;
274 1.1 gwr hash_datum *key;
275 1.1 gwr hash_freefp free_data;
276 1.1 gwr {
277 1.1 gwr hash_member *memberptr, *tempptr;
278 1.1 gwr hash_member *previous = NULL;
279 1.1 gwr int retval;
280 1.1 gwr
281 1.1 gwr retval = -1;
282 1.1 gwr hashcode %= hashtable->size;
283 1.1 gwr
284 1.1 gwr /*
285 1.1 gwr * Delete the first member of the list if it matches. Since this moves
286 1.1 gwr * the second member into the first position we have to keep doing this
287 1.1 gwr * over and over until it no longer matches.
288 1.1 gwr */
289 1.1 gwr memberptr = (hashtable->table)[hashcode];
290 1.1 gwr while (memberptr && (*compare) (key, memberptr->data)) {
291 1.1 gwr (hashtable->table)[hashcode] = memberptr->next;
292 1.1 gwr /*
293 1.1 gwr * Stop hashi_FreeMembers() from deleting the whole list!
294 1.1 gwr */
295 1.1 gwr memberptr->next = NULL;
296 1.1 gwr hashi_FreeMembers(memberptr, free_data);
297 1.1 gwr memberptr = (hashtable->table)[hashcode];
298 1.1 gwr retval = 0;
299 1.1 gwr }
300 1.1 gwr
301 1.1 gwr /*
302 1.1 gwr * Now traverse the rest of the list
303 1.1 gwr */
304 1.1 gwr if (memberptr) {
305 1.1 gwr previous = memberptr;
306 1.1 gwr memberptr = memberptr->next;
307 1.1 gwr }
308 1.1 gwr while (memberptr) {
309 1.1 gwr if ((*compare) (key, memberptr->data)) {
310 1.1 gwr tempptr = memberptr;
311 1.1 gwr previous->next = memberptr = memberptr->next;
312 1.1 gwr /*
313 1.1 gwr * Put the brakes on hashi_FreeMembers(). . . .
314 1.1 gwr */
315 1.1 gwr tempptr->next = NULL;
316 1.1 gwr hashi_FreeMembers(tempptr, free_data);
317 1.1 gwr retval = 0;
318 1.1 gwr } else {
319 1.1 gwr previous = memberptr;
320 1.1 gwr memberptr = memberptr->next;
321 1.1 gwr }
322 1.1 gwr }
323 1.1 gwr return retval;
324 1.1 gwr }
325 1.1 gwr
326 1.1 gwr
328 1.1 gwr
329 1.1 gwr /*
330 1.1 gwr * Locate and return the data entry associated with the given key.
331 1.1 gwr *
332 1.1 gwr * If the data entry is found, a pointer to it is returned. Otherwise,
333 1.1 gwr * NULL is returned.
334 1.1 gwr */
335 1.1 gwr
336 1.1 gwr hash_datum *
337 1.1 gwr hash_Lookup(hashtable, hashcode, compare, key)
338 1.1 gwr hash_tbl *hashtable;
339 1.1 gwr unsigned hashcode;
340 1.1 gwr hash_cmpfp compare;
341 1.1 gwr hash_datum *key;
342 1.1 gwr {
343 1.1 gwr hash_member *memberptr;
344 1.1 gwr
345 1.1 gwr memberptr = (hashtable->table)[hashcode % (hashtable->size)];
346 1.1 gwr while (memberptr) {
347 1.1 gwr if ((*compare) (key, memberptr->data)) {
348 1.1 gwr return (memberptr->data);
349 1.1 gwr }
350 1.1 gwr memberptr = memberptr->next;
351 1.1 gwr }
352 1.1 gwr return NULL;
353 1.1 gwr }
354 1.1 gwr
355 1.1 gwr
357 1.1 gwr
358 1.1 gwr /*
359 1.1 gwr * Return the next available entry in the hashtable for a linear search
360 1.1 gwr */
361 1.1 gwr
362 1.1 gwr hash_datum *
363 1.1 gwr hash_NextEntry(hashtable)
364 1.1 gwr hash_tbl *hashtable;
365 1.1 gwr {
366 1.1 gwr register unsigned bucket;
367 1.1 gwr register hash_member *memberptr;
368 1.1 gwr
369 1.1 gwr /*
370 1.1 gwr * First try to pick up where we left off.
371 1.1 gwr */
372 1.1 gwr memberptr = hashtable->member;
373 1.1 gwr if (memberptr) {
374 1.1 gwr hashtable->member = memberptr->next; /* Set up for next call */
375 1.1 gwr return memberptr->data; /* Return the data */
376 1.1 gwr }
377 1.1 gwr /*
378 1.1 gwr * We hit the end of a chain, so look through the array of buckets
379 1.1 gwr * until we find a new chain (non-empty bucket) or run out of buckets.
380 1.1 gwr */
381 1.1 gwr bucket = hashtable->bucketnum + 1;
382 1.1 gwr while ((bucket < hashtable->size) &&
383 1.1 gwr !(memberptr = (hashtable->table)[bucket])) {
384 1.1 gwr bucket++;
385 1.1 gwr }
386 1.1 gwr
387 1.1 gwr /*
388 1.1 gwr * Check to see if we ran out of buckets.
389 1.1 gwr */
390 1.1 gwr if (bucket >= hashtable->size) {
391 1.1 gwr /*
392 1.1 gwr * Reset to top of table for next call.
393 1.1 gwr */
394 1.1 gwr hashtable->bucketnum = 0;
395 1.1 gwr hashtable->member = (hashtable->table)[0];
396 1.1 gwr /*
397 1.1 gwr * But return end-of-table indication to the caller this time.
398 1.1 gwr */
399 1.1 gwr return NULL;
400 1.1 gwr }
401 1.1 gwr /*
402 1.1 gwr * Must have found a non-empty bucket.
403 1.1 gwr */
404 1.1 gwr hashtable->bucketnum = bucket;
405 1.1 gwr hashtable->member = memberptr->next; /* Set up for next call */
406 1.1 gwr return memberptr->data; /* Return the data */
407 1.1 gwr }
408 1.1 gwr
409 1.1 gwr
411 1.1 gwr
412 1.1 gwr /*
413 1.1 gwr * Return the first entry in a hash table for a linear search
414 1.1 gwr */
415 1.1 gwr
416 1.1 gwr hash_datum *
417 1.1 gwr hash_FirstEntry(hashtable)
418 1.1 gwr hash_tbl *hashtable;
419 1.1 gwr {
420 1.1 gwr hashtable->bucketnum = 0;
421 1.1 gwr hashtable->member = (hashtable->table)[0];
422 1.1 gwr return hash_NextEntry(hashtable);
423 1.1 gwr }
424 1.1 gwr
425 1.1 gwr /*
426 1.1 gwr * Local Variables:
427 * tab-width: 4
428 * c-indent-level: 4
429 * c-argdecl-indent: 4
430 * c-continued-statement-offset: 4
431 * c-continued-brace-offset: -4
432 * c-label-offset: -4
433 * c-brace-offset: 0
434 * End:
435 */
436