1 /* $XConsortium: hash.c /main/1 1996/04/21 19:23:21 drk $ */
3 * (c) Copyright 1993, 1994 Hewlett-Packard Company
4 * (c) Copyright 1993, 1994 International Business Machines Corp.
5 * (c) Copyright 1993, 1994 Novell, Inc.
6 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
15 void * _DtCmMakeHash(int size)
17 void * _DtCmMakeIHash(int size)
19 void ** _DtCmGetHash(void * tbl, unsigned char * key)
21 void ** _DtCmFindHash(void * tbl,unsigned char * key)
23 void ** _DtCmDelHash(void * tbl, unsigned char * key)
25 int _DtCmOperateHash(void * tbl, void (*op_func)(), void * usr_arg)
27 void _DtCmDestroyHash(void * tbl, int (*des_func)(), void * usr_arg)
32 These routines provide a general purpose hash table facility that
33 supports multiple open hash tables. Each entry in the table consists of a
34 key and a data ptr. The key is a null terminated character string, while
35 the data ptr is opaque. Since all the entries are maintained in a doubly
36 linked lists, deletions and operations on entire table execute very quickly.
37 This make these routines suitable for use when the tables may be very ephemeral.
39 _DtCmMakeHash returns a pointer to the created table. The size argument
40 indicate the number of buckets the routine is to allocate. This should be ~
41 the max number of items expected in the table for maximum performance....
42 but /2 or /3 should still be ok. Note that for maximum efficiency the hash
43 table size should be a prime number (a side effect of the hash alorithm).
45 _DtCmMakeIHash performs the same function as _DtCmMakeHash, except that the hash
46 routines will use the key arguments as arbitrary integers rather than strings.
48 _DtCmGetHash searches the specified hash table tbl for an entry with the
49 specified key. If the entry does not exist, it is created with a NULL data
50 ptr. The routine returns a ptr to the area where the data ptr is (can be)
53 _DtCmFindHash searchs the table for an entry with the specified key. If the
54 entry is found, the address of the data pointer associated with the key is
55 returned. If no such entry exists, the routine returns NULL.
57 _DtCmDelHash deletes the specified table entry and returns the associated data
58 ptr. If the entry did not exist ( or the data ptr was NULL), the routine
61 _DtCmOperateHash calls the routine pointed to by op_func once for each entry
62 in tbl, with three arguments: the data ptr, the usr_arg ptr and a ptr to the
63 key for that entry (which should NOT be altered). This is useful for
64 transversing a hash table quickly and operating on the entries. Note that
65 the order of the traversal of the hash table is the reverse order of
68 _DtCmDestroyHash destroys the specified hash table after operating on it
69 with the specified des_func function as described for _DtCmOperateHash. All storage
70 allocated by the hash routines is reclaimed.
72 Author: Bart Smaalders 1/89
76 #include <EUSCompat.h>
77 #include <stdio.h> /* grab NULL define */
82 static int hash_string();
84 typedef struct hash_entry {
97 enum hash_type { String_Key = 0 , Integer_Key = 1} hash_type;
101 void * _DtCmMakeHash(int size)
105 ptr = (hash *) malloc(sizeof(*ptr));
107 ptr->table = (hash_entry **) malloc( (unsigned) (sizeof(hash_entry *) * size) );
108 (void)memset((char *) ptr->table, (char) 0, sizeof(hash_entry *)*size);
110 ptr->hash_type = String_Key;
114 void ** _DtCmGetHash(void * t, const unsigned char * key)
116 hash * tbl = (hash *) t;
118 register hash_entry * tmp;
121 if(tbl->hash_type == String_Key)
122 tmp = tbl->table[bucket = hash_string(key, tbl->size)];
124 tmp = tbl->table[bucket = abs((long)key) % tbl->size];
126 if(tbl->hash_type == String_Key)
129 if(strcmp((char *)tmp->key, (char *)key)==0)
131 tmp = tmp->next_entry;
138 tmp = tmp->next_entry;
143 insert new entry into bucket...
146 new = (hash_entry *) malloc(sizeof(*new));
147 new->key = (unsigned char *)((tbl->hash_type == String_Key)?(unsigned char *)strdup((char *)key):key);
149 hook into chain from tbl...
151 new->right_entry = NULL;
152 new->left_entry = tbl->start;
155 hook into bucket chain
157 new->next_entry = tbl->table[bucket];
158 tbl->table[bucket] = new;
159 new->data = NULL; /* so we know that it is new */
160 return((void*)& new->data);
163 void ** _DtCmFindHash(void * t, const unsigned char * key)
165 register hash * tbl = (hash *) t;
166 register hash_entry * tmp;
168 if(tbl->hash_type == String_Key)
170 tmp = tbl->table[hash_string(key, tbl->size)];
171 for(;tmp!=NULL; tmp = tmp->next_entry)
172 if(!strcmp((char *)tmp->key, (char *)key))
173 return((void *)&tmp->data);
177 tmp = tbl->table[abs((long)key) % tbl->size];
178 for(;tmp!=NULL; tmp = tmp->next_entry)
180 return((void *)&tmp->data);
186 void _DtCmDestroyHash(void * t, int (*ptr)(), void * usr_arg)
188 hash * tbl = (hash *) t;
189 register hash_entry * tmp = tbl->start, * prev;
194 (*ptr)(tmp->data,usr_arg, tmp->key);
196 if(tbl->hash_type == String_Key)
199 tmp = tmp->left_entry;
202 free((char *)tbl->table);
206 static int hash_string(s,modulo)
210 register unsigned result = 0;
214 result += (*s++ << i++);
216 return(result % modulo);