Reordered files
[svmtool++.git] / src / hash.cc
blobeac6e5b6d85784c0d54a2e63d34d0f115bed02cb
1 /*
2 * Copyright (C) 2004 Jesus Gimenez, Lluis Marquez and Senen Moya
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include "hash.h"
24 /**************************************************/
26 #define HASH_LIMIT 0.5
28 /**************************************************/
31 * hash() - Hash function returns a hash number for a given key.
33 * tptr: Pointer to a hash table
34 * key: The key to create a hash number for
36 static int hash(const hash_t *tptr, const char *key)
38 int i=0;
39 int hashvalue;
41 if (key) while (*key != '\0') i=(i<<3)+(*key++ - '0');
43 hashvalue = (((i*1103515249)>>tptr->downshift) & tptr->mask);
44 if (hashvalue < 0) hashvalue = 0;
46 return hashvalue;
50 /**************************************************/
53 * rebuild_table() - Create new hash table when old one fills up.
55 * tptr: Pointer to a hash table
57 void rebuild_table(hash_t *tptr)
59 hash_node_t **old_bucket, *old_hash, *tmp;
60 int old_size, h, i;
62 old_bucket=tptr->bucket;
63 old_size=tptr->size;
65 /* create a new table and rehash old buckets */
66 hash_init(tptr, old_size<<1);
67 for (i=0; i<old_size; i++)
69 old_hash=old_bucket[i];
70 while(old_hash)
72 tmp=old_hash;
73 old_hash=old_hash->next;
74 h=hash(tptr, tmp->key);
75 tmp->next=tptr->bucket[h];
76 tptr->bucket[h]=tmp;
77 tptr->entries++;
78 } /* while */
79 } /* for */
81 /* free memory used by old table */
82 free(old_bucket);
84 return;
88 /**************************************************/
91 * hash_init() - Initialize a new hash table.
93 * tptr: Pointer to the hash table to initialize
94 * buckets: The number of initial buckets to create
96 void hash_init(hash_t *tptr, int buckets)
98 /* make sure we allocate something */
99 if (buckets==0) buckets=16;
101 /* initialize the table */
102 tptr->entries=0;
103 tptr->size=2;
104 tptr->mask=1;
105 tptr->downshift=29;
107 /* ensure buckets is a power of 2 */
108 while (tptr->size<buckets)
110 tptr->size<<=1;
111 tptr->mask=(tptr->mask<<1)+1;
112 tptr->downshift--;
113 } /* while */
115 /* allocate memory for table */
116 tptr->bucket=(hash_node_t **) calloc(tptr->size, sizeof(hash_node_t *));
118 return;
122 /**************************************************/
125 * hash_lookup() - Lookup an entry in the hash table and return a pointer to
126 * it or HASH_FAIL if it wasn't found.
128 * tptr: Pointer to the hash table
129 * key: The key to lookup
131 uintptr_t hash_lookup(const hash_t *tptr, const char *key)
133 int h;
134 hash_node_t *node;
136 /* find the entry in the hash table */
137 h=hash(tptr, key);
138 for (node=tptr->bucket[h]; node!=NULL; node=node->next)
140 if (!strcmp(node->key, key)) break;
143 /* return the entry if it exists, or HASH_FAIL */
144 return(node ? node->data : HASH_FAIL);
148 /**************************************************/
151 * hash_insert() - Insert an entry into the hash table. If the entry already
152 * exists return a pointer to it, otherwise return HASH_FAIL.
154 * tptr: A pointer to the hash table
155 * key: The key to insert into the hash table
156 * data: A pointer to the data to insert into the hash table
158 uintptr_t hash_insert(hash_t *tptr, const char *key, uintptr_t data)
160 uintptr_t tmp;
161 hash_node_t *node;
162 int h;
164 /* check to see if the entry exists */
165 if ((tmp=hash_lookup(tptr, key)) != HASH_FAIL) return(tmp);
167 /* expand the table if needed */
168 while (tptr->entries>=HASH_LIMIT*tptr->size)
169 rebuild_table(tptr);
171 /* insert the new entry */
172 h=hash(tptr, key);
173 node=(struct hash_node_t *) malloc(sizeof(hash_node_t));
174 node->data=data;
175 node->key=key;
176 node->next=tptr->bucket[h];
177 tptr->bucket[h]=node;
178 tptr->entries++;
180 return HASH_FAIL;
184 /**************************************************/
187 * hash_delete() - Remove an entry from a hash table and return a pointer
188 * to its data or HASH_FAIL if it wasn't found.
190 * tptr: A pointer to the hash table
191 * key: The key to remove from the hash table
193 uintptr_t hash_delete(hash_t *tptr, const char *key)
195 hash_node_t *node, *last;
196 uintptr_t data;
197 int h;
199 /* find the node to remove */
200 h=hash(tptr, key);
201 for (node=tptr->bucket[h]; node; node=node->next)
203 if (!strcmp(node->key, key)) break;
206 /* Didn't find anything, return HASH_FAIL */
207 if (node==NULL) return HASH_FAIL;
209 /* if node is at head of bucket, we have it easy */
210 if (node==tptr->bucket[h]) tptr->bucket[h]=node->next;
211 else
213 /* find the node before the node we want to remove */
214 for (last=tptr->bucket[h]; last && last->next; last=last->next)
216 if (last->next==node)
217 break;
219 last->next=node->next;
222 /* free memory and return the data */
223 data=node->data;
224 free(node);
226 return(data);
230 /**************************************************/
233 * hash_destroy() - Delete the entire table, and all remaining entries.
235 void hash_destroy(hash_t *tptr)
237 hash_node_t *node, *last;
238 int i;
240 for (i=0; i<tptr->size; i++)
242 node = tptr->bucket[i];
243 while (node != NULL)
245 last = node;
246 node = node->next;
247 free(last);
251 /* free the entire array of buckets */
252 if (tptr->bucket != NULL)
254 free(tptr->bucket);
255 memset(tptr, 0, sizeof(hash_t));
260 /**************************************************/
263 * alos() - Find the average length of search.
265 * tptr: Pointer to a hash table
267 static float alos(hash_t *tptr)
269 int i,j;
270 float alos=0;
271 hash_node_t *node;
273 for (i=0; i<tptr->size; i++)
275 for (node=tptr->bucket[i], j=0; node!=NULL; node=node->next, j++);
276 if (j) alos+=((j*(j+1))>>1);
277 } /* for */
279 return(tptr->entries ? alos/tptr->entries : 0);
283 /**************************************************/
286 * hash_stats() - Return a string with stats about a hash table.
288 * tptr: A pointer to the hash table
290 char * hash_stats(hash_t *tptr)
292 static char buf[1024];
294 sprintf(buf, "%u slots, %u entries, and %1.2f ALOS",(int)tptr->size, (int)tptr->entries, alos(tptr));
296 return(buf);
300 /**************************************************/
303 * hash_print() - Print Keys in FILE *f
306 void hash_print(hash_t *tptr,FILE *f)
308 hash_node_t *node, *last;
309 int i;
311 for (i=0; i<tptr->size; i++)
313 node = tptr->bucket[i];
314 while (node != NULL)
316 last = node;
317 node = node->next;
318 fprintf(f,"%s\n",last->key);