5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 /* Implementation of collision resistant hash table. */
23 #include "silcincludes.h"
24 #include "silchashtable.h"
26 /* Default size of the hash table (index to prime table) */
27 #define SILC_HASH_TABLE_SIZE 3
29 /* Produce the index by hashing the key */
30 #define SILC_HASH_TABLE_HASH (ht->hash(key) % primesize[ht->table_size])
32 /* One entry in the hash table. Includes the key and the associated
33 context. The `next' pointer is non-NULL if two (or more) different
34 keys hashed to same value. The pointer is the pointer to the next
36 typedef struct SilcHashTableEntryStruct {
39 struct SilcHashTableEntryStruct *next;
40 } *SilcHashTableEntry;
43 struct SilcHashTableStruct {
44 SilcHashTableEntry *table;
46 SilcHashFunction hash;
47 SilcHashCompare compare;
48 SilcHashDestructor destructor;
51 /* Prime sizes for the hash table. The size of the table will always
53 const uint32 primesize[42] =
55 1, 3, 5, 11, 17, 37, 67, 109, 131, 163, 257, 367, 521, 823, 1031,
56 1237, 2053, 2777, 4099, 6247, 8209, 14057, 16411, 21089, 32771, 47431,
57 65537, 106721, 131101, 262147, 360163, 524309, 810343, 1048583, 2097169,
58 4194319, 6153409, 8388617, 13845163, 16777259, 33554467, 67108879
61 /* Find appropriate size for the hash table. The size will be a prime. */
63 static uint32 silc_hash_table_primesize(uint32 size, uint32 *index)
67 for (i = 0; i < sizeof(primesize); i++)
68 if (primesize[i] >= size) {
74 return primesize[i - 1];
77 /* Internal routine to find entry in the hash table by `key'. */
79 static inline SilcHashTableEntry *
80 silc_hash_table_find_internal(SilcHashTable ht, void *key,
81 SilcHashTableEntry *prev_entry)
83 SilcHashTableEntry *entry, prev = NULL;
85 entry = &ht->table[SILC_HASH_TABLE_HASH];
87 while (*entry && ht->compare((*entry)->key, key) == FALSE) {
89 entry = &(*entry)->next;
92 while (*entry && (*entry)->key != key) {
94 entry = &(*entry)->next;
102 /* Allocates new hash table and returns it. If the `table_size' is not
103 zero then the hash table size is the size provided. If zero then the
104 default size will be used. Note that if the `table_size' is provided
105 it should be a prime. The `hash', `compare' and `destructor' are
106 the hash function, the key comparison function and key and context
107 destructor function, respectively. The `hash' is mandatory, the others
110 SilcHashTable silc_hash_table_alloc(uint32 table_size,
111 SilcHashFunction hash,
112 SilcHashCompare compare,
113 SilcHashDestructor destructor)
116 uint32 size_index = SILC_HASH_TABLE_SIZE;
121 ht = silc_calloc(1, sizeof(*ht));
122 ht->table = silc_calloc(table_size ? silc_hash_table_primesize(table_size,
124 primesize[SILC_HASH_TABLE_SIZE],
126 ht->table_size = size_index;
128 ht->compare = compare;
129 ht->destructor = destructor;
134 /* Frees the hash table. The destructor function provided in the
135 silc_hash_table_alloc will be called for all keys in the hash table. */
137 void silc_hash_table_free(SilcHashTable ht)
141 for (i = 0; i < primesize[ht->table_size]; i++)
144 ht->destructor(ht->table[i]->key, ht->table[i]->context);
145 silc_free(ht->table[i]);
148 silc_free(ht->table);
152 /* Returns the size of the hash table */
154 uint32 silc_hash_table_size(SilcHashTable ht)
156 return primesize[ht->table_size];
159 /* Adds new entry to the hash table. The `key' is hashed using the
160 hash function and the both `key' and `context' will be saved to the
161 hash table. This function quarantees that the entry is always added
162 to the hash table reliably (it is collision resistant). */
164 void silc_hash_table_add(SilcHashTable ht, void *key, void *context)
166 SilcHashTableEntry *entry;
167 uint32 index = SILC_HASH_TABLE_HASH;
169 entry = &ht->table[index];
171 /* The entry exists already. We have a collision, add it to the
172 list to avoid collision. */
173 SilcHashTableEntry e, tmp;
182 e->next = silc_calloc(1, sizeof(*e->next));
184 e->next->context = context;
187 *entry = silc_calloc(1, sizeof(**entry));
189 (*entry)->context = context;
193 /* Same as above but if the `key' already exists in the hash table
194 the old key and the old context will be replace with the `key' and
195 the `context. The destructor function will be called for the
196 replaced key and context. */
198 void silc_hash_table_replace(SilcHashTable ht, void *key, void *context)
200 SilcHashTableEntry *entry;
201 uint32 index = SILC_HASH_TABLE_HASH;
203 entry = &ht->table[index];
205 /* The entry exists already. We have a collision, replace the old
208 ht->destructor((*entry)->key, (*entry)->context);
211 *entry = silc_calloc(1, sizeof(**entry));
215 (*entry)->context = context;
218 /* Removes the entry from the hash table by the provided `key'. This will
219 call the destructor funtion for the found entry. Return TRUE if the
220 entry was removed successfully and FALSE otherwise. */
222 bool silc_hash_table_del(SilcHashTable ht, void *key)
224 SilcHashTableEntry *entry, prev, e;
226 entry = silc_hash_table_find_internal(ht, key, &prev);
232 if (!prev && e->next)
234 if (!prev && e->next == NULL)
239 prev->next = e->next;
242 ht->destructor(e->key, e->context);
248 /* Finds the entry in the hash table by the provided `key' as fast as
249 possible. Return TRUE if the entry was found and FALSE otherwise.
250 The found entry is returned to the `ret_key' and `ret_context',
251 respectively. If the `ret_key and `ret_context' are NULL then this
252 maybe used only to check whether given key exists in the table. */
254 bool silc_hash_table_find(SilcHashTable ht, void *key,
255 void **ret_key, void **ret_context)
257 SilcHashTableEntry *entry, prev;
259 entry = silc_hash_table_find_internal(ht, key, &prev);
264 *ret_key = (*entry)->key;
266 *ret_context = (*entry)->context;
271 /* Rehashs the hash table. The size of the new hash table is provided
272 as `new_size'. If the `new_size' is zero then this routine will make
273 the new table of a suitable size. Note that this operation may be
276 void silc_hash_table_rehash(SilcHashTable ht, uint32 new_size)