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
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
)
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;
49 /**************************************************/
52 * rebuild_table() - Create new hash table when old one fills up.
54 * tptr: Pointer to a hash table
56 void rebuild_table(hash_t
*tptr
)
58 hash_node_t
**old_bucket
, *old_hash
, *tmp
;
61 old_bucket
=tptr
->bucket
;
64 /* create a new table and rehash old buckets */
65 hash_init(tptr
, old_size
<<1);
66 for (i
=0; i
<old_size
; i
++)
68 old_hash
=old_bucket
[i
];
72 old_hash
=old_hash
->next
;
73 h
=hash(tptr
, tmp
->key
);
74 tmp
->next
=tptr
->bucket
[h
];
80 /* free memory used by old table */
86 /**************************************************/
89 * hash_init() - Initialize a new hash table.
91 * tptr: Pointer to the hash table to initialize
92 * buckets: The number of initial buckets to create
94 void hash_init(hash_t
*tptr
, int buckets
)
96 /* make sure we allocate something */
97 if (buckets
==0) buckets
=16;
99 /* initialize the table */
105 /* ensure buckets is a power of 2 */
106 while (tptr
->size
<buckets
)
109 tptr
->mask
=(tptr
->mask
<<1)+1;
113 /* allocate memory for table */
114 tptr
->bucket
=(hash_node_t
**) calloc(tptr
->size
, sizeof(hash_node_t
*));
119 /**************************************************/
122 * hash_lookup() - Lookup an entry in the hash table and return a pointer to
123 * it or HASH_FAIL if it wasn't found.
125 * tptr: Pointer to the hash table
126 * key: The key to lookup
128 uintptr_t hash_lookup(const hash_t
*tptr
, const char *key
)
133 /* find the entry in the hash table */
135 for (node
=tptr
->bucket
[h
]; node
!=NULL
; node
=node
->next
)
137 if (!strcmp(node
->key
, key
)) break;
140 /* return the entry if it exists, or HASH_FAIL */
141 return(node
? node
->data
: HASH_FAIL
);
144 /**************************************************/
147 * hash_insert() - Insert an entry into the hash table. If the entry already
148 * exists return a pointer to it, otherwise return HASH_FAIL.
150 * tptr: A pointer to the hash table
151 * key: The key to insert into the hash table
152 * data: A pointer to the data to insert into the hash table
154 uintptr_t hash_insert(hash_t
*tptr
, const char *key
, uintptr_t data
)
160 /* check to see if the entry exists */
161 if ((tmp
=hash_lookup(tptr
, key
)) != HASH_FAIL
) return(tmp
);
163 /* expand the table if needed */
164 while (tptr
->entries
>=HASH_LIMIT
*tptr
->size
)
167 /* insert the new entry */
169 node
=(struct hash_node_t
*) malloc(sizeof(hash_node_t
));
172 node
->next
=tptr
->bucket
[h
];
173 tptr
->bucket
[h
]=node
;
179 /**************************************************/
182 * hash_delete() - Remove an entry from a hash table and return a pointer
183 * to its data or HASH_FAIL if it wasn't found.
185 * tptr: A pointer to the hash table
186 * key: The key to remove from the hash table
188 uintptr_t hash_delete(hash_t
*tptr
, const char *key
)
190 hash_node_t
*node
, *last
;
194 /* find the node to remove */
196 for (node
=tptr
->bucket
[h
]; node
; node
=node
->next
)
198 if (!strcmp(node
->key
, key
)) break;
201 /* Didn't find anything, return HASH_FAIL */
202 if (node
==NULL
) return HASH_FAIL
;
204 /* if node is at head of bucket, we have it easy */
205 if (node
==tptr
->bucket
[h
]) tptr
->bucket
[h
]=node
->next
;
208 /* find the node before the node we want to remove */
209 for (last
=tptr
->bucket
[h
]; last
&& last
->next
; last
=last
->next
)
211 if (last
->next
==node
)
214 last
->next
=node
->next
;
217 /* free memory and return the data */
224 /**************************************************/
227 * hash_destroy() - Delete the entire table, and all remaining entries.
229 void hash_destroy(hash_t
*tptr
)
231 hash_node_t
*node
, *last
;
234 for (i
=0; i
<tptr
->size
; i
++)
236 node
= tptr
->bucket
[i
];
245 /* free the entire array of buckets */
246 if (tptr
->bucket
!= NULL
)
249 memset(tptr
, 0, sizeof(hash_t
));
253 /**************************************************/
256 * alos() - Find the average length of search.
258 * tptr: Pointer to a hash table
260 static float alos(hash_t
*tptr
)
266 for (i
=0; i
<tptr
->size
; i
++)
268 for (node
=tptr
->bucket
[i
], j
=0; node
!=NULL
; node
=node
->next
, j
++);
269 if (j
) alos
+=((j
*(j
+1))>>1);
272 return(tptr
->entries
? alos
/tptr
->entries
: 0);
275 /**************************************************/
278 * hash_stats() - Return a string with stats about a hash table.
280 * tptr: A pointer to the hash table
282 char * hash_stats(hash_t
*tptr
)
284 static char buf
[1024];
286 sprintf(buf
, "%u slots, %u entries, and %1.2f ALOS",(int)tptr
->size
, (int)tptr
->entries
, alos(tptr
));
291 /**************************************************/
294 * hash_print() - Print Keys in FILE *f
297 void hash_print(hash_t
*tptr
,FILE *f
)
299 hash_node_t
*node
, *last
;
302 for (i
=0; i
<tptr
->size
; i
++)
304 node
= tptr
->bucket
[i
];
309 fprintf(f
,"%s\n",last
->key
);