UYS  0.1
Useful Yet Simple (C libraries collection)
 All Data Structures Files Functions Typedefs Macros Pages
nhash.c
1 /*****************************************************************
2  *
3  * nhash.c
4  *****************************************************************/
5 
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <stdint.h>
12 
13 #include "lookup3.h"
14 #include "list.h"
15 #include "nhash.h"
16 
17 
18 /*****************************************************************
19  * nhash_init.
20  ****************************************************************/
21 int nhash_init(NHash *htbl, int buckets, void (*destroy)(void*data)) {
22  int i;
23 
24  /*****************************************************************
25  * Allocate space for the hash table.
26  ****************************************************************/
27  if ((htbl->table = (List *)malloc(buckets * sizeof(List))) == NULL) {
28  return -1;
29  }
30 
31  /*****************************************************************
32  * Encapsulate the destroy function.
33  ****************************************************************/
34  htbl->destroy = destroy;
35 
36  htbl->buckets = buckets;
37 
38  /*****************************************************************
39  * Initialize the buckets.
40  ****************************************************************/
41  for (i = 0; i < htbl->buckets; i++) {
42  list_init(&htbl->table[i], htbl->destroy);
43  }
44 
45  /*****************************************************************
46  * Initialize the number of elements in the table.
47  ****************************************************************/
48  htbl->size = 0;
49 
50  return 0;
51 }
52 
53 
54 /*****************************************************************
55  * nhash_destroy
56  ****************************************************************/
57 void nhash_destroy(NHash *htbl) {
58  int i;
59 
60  /*****************************************************************
61  * Destroy each bucket.
62  ****************************************************************/
63  for (i = 0; i < htbl->buckets; i++) {
64  list_destroy(&htbl->table[i]);
65  }
66 
67  /*****************************************************************
68  * Free the storage allocated for the hash table.
69  ****************************************************************/
70  free(htbl->table);
71 
72  /*****************************************************************
73  * No operations are allowed now, but clear the structure as a precaution.
74  ****************************************************************/
75  memset(htbl, 0, sizeof(NHash));
76 
77  return;
78 }
79 
80 void nhash_vhash(size_t nk, va_list args, uint32_t *h1, uint32_t *h2) {
81  for (size_t i = 0; i < nk / 2; ++i) {
82  void* data = va_arg(args, void*);
83  size_t len = va_arg(args, size_t);
84  hashlittle2(data, len, h1, h2);
85  }
86 
87  return;
88 }
89 
90 
91 NHashEntry* nhash_create_entry(uint64_t key, const void *val) {
92  NHashEntry *entry = malloc(sizeof(*entry));
93  entry->key = key;
94  entry->val = val;
95 
96  return entry;
97 }
98 
99 
100 /*****************************************************************
101  * nhash_vget
102  ****************************************************************/
103 NHashEntry* nhash_vget(NHash *htbl, size_t nk, va_list args) {
104  NHashEntry *entry;
105  ListElmt *element;
106  int bucket;
107  uint32_t h1,
108  h2;
109 
110  /*****************************************************************
111  * Hash the 32 bit keys.
112  ****************************************************************/
113  h1 = 0;
114  h2 = 0;
115  nhash_vhash(nk, args, &h1, &h2);
116 
117  /*****************************************************************
118  * Hash the 64 bit key.
119  ****************************************************************/
120  uint64_t key = h1 + (((uint64_t)h2)<<32);
121 
122  /*****************************************************************
123  * Find the bucked
124  ****************************************************************/
125  bucket = key % htbl->buckets;
126 
127 
128  /*****************************************************************
129  * Search for the data in the bucket.
130  ****************************************************************/
131  for (element = list_head(&htbl->table[bucket]); element != NULL;
132  element = list_next(element)) {
133 
134  entry = list_data(element);
135  if (entry->key == key) {
136  return entry;
137  }
138  }
139 
140  return NULL;
141 }
142 
143 /*****************************************************************
144  * nhash_get
145  ****************************************************************/
146 NHashEntry* nhash_get(NHash *htbl, size_t nk, ...) {
147  if (nk % 2)
148  exit(EXIT_FAILURE);
149 
150  va_list args; // Declare va_list type variable
151  va_start(args, nk); // Initialise va_list after last regular variable
152  NHashEntry *retval = nhash_vget(htbl, nk, args);
153  va_end(args); //Close the va_list
154 
155  return retval;
156 }
157 
158 
159 /*****************************************************************
160  * nhash_vinsert
161  ****************************************************************/
162 int nhash_vinsert(NHash *htbl, const void *val, size_t nk, va_list args) {
163  NHashEntry *entry;
164  ListElmt *element;
165  int bucket,
166  retval;
167  uint32_t h1,
168  h2;
169 
170  /*****************************************************************
171  * Hash the 32 bit keys.
172  ****************************************************************/
173  h1 = 0;
174  h2 = 0;
175  nhash_vhash(nk, args, &h1, &h2);
176 
177  /*****************************************************************
178  * Hash the 64 bit key.
179  ****************************************************************/
180  uint64_t key = h1 + (((uint64_t)h2)<<32);
181 
182  /*****************************************************************
183  * Find the bucked
184  ****************************************************************/
185  bucket = key % htbl->buckets;
186 
187 
188  /*****************************************************************
189  * Search for the data in the bucket.
190  ****************************************************************/
191  for (element = list_head(&htbl->table[bucket]); element != NULL;
192  element = list_next(element)) {
193 
194  entry = list_data(element);
195  if (entry->key == key) {
196  /*****************************************************************
197  * Update `val` if the `key` is already in the table.
198  ****************************************************************/
199  entry->val = val;
200  return 0;
201  }
202  }
203 
204  /*****************************************************************
205  * Create new entry
206  ****************************************************************/
207  entry = nhash_create_entry(key, val);
208 
209 
210  /*****************************************************************
211  * Insert the entry into the bucket.
212  ****************************************************************/
213  if ((retval = list_ins_next(&htbl->table[bucket], NULL, entry)) == 0) {
214  htbl->size++;
215  if (nhash_loadfactor(htbl) > 2) {
216  nhash_grow(htbl);
217  }
218  }
219 
220  return retval;
221 }
222 
223 
224 /*****************************************************************
225  * nhash_insert
226  ****************************************************************/
227 int nhash_insert(NHash *htbl, const void *val, size_t nk, ...) {
228  if (nk % 2)
229  exit(EXIT_FAILURE);
230 
231  va_list args; // Declare va_list type variable
232  va_start(args, nk); // Initialise va_list after last regular variable
233  int retval = nhash_vinsert(htbl, val, nk, args);
234  va_end(args); //Close the va_list
235 
236 
237  return retval;
238 }
239 
240 
241 /*****************************************************************
242  * nhash_vremove
243  ****************************************************************/
244 void* nhash_vremove(NHash *htbl, size_t nk, va_list args) {
245  void *temp,
246  *val;
247  ListElmt *element,
248  *prev;
249  int bucket;
250  uint32_t h1,
251  h2;
252 
253  /*****************************************************************
254  * Hash the 32 bit keys.
255  ****************************************************************/
256  h1 = 0;
257  h2 = 0;
258  nhash_vhash(nk, args, &h1, &h2);
259 
260  /*****************************************************************
261  * Hash the 64 bit key.
262  ****************************************************************/
263  uint64_t key = h1 + (((uint64_t)h2)<<32);
264 
265  /*****************************************************************
266  * Find the bucked
267  ****************************************************************/
268  bucket = key % htbl->buckets;
269 
270  /*****************************************************************
271  * Search for the data in the bucket.
272  ****************************************************************/
273  prev = NULL;
274  for (element = list_head(&htbl->table[bucket]); element != NULL;
275  element = list_next(element)) {
276  NHashEntry *entry = list_data(element);
277  if (entry->key == key) {
278 
279  /*************************************************************
280  * Remove the data from the bucket.
281  *************************************************************/
282  if (list_rem_next(&htbl->table[bucket], prev,
283  &temp) == 0) {
284  val = (void*)entry->val;
285  free(temp);
286  htbl->size--;
287  return val;
288  }
289  else {
290  return NULL;
291  }
292  }
293  prev = element;
294  }
295 
296  /*****************************************************************
297  * Return that the data was not found.
298  ****************************************************************/
299  return NULL;
300 }
301 
302 
303 /*****************************************************************
304  * nhash_remove
305  ****************************************************************/
306 void* nhash_remove(NHash *htbl, size_t nk, ...) {
307  if (nk % 2) {
308  exit(EXIT_FAILURE);
309  }
310 
311  void* data;
312 
313  va_list args; // Declare va_list type variable
314  va_start(args, nk); // Initialise va_list after last regular variable
315  data = nhash_vremove(htbl, nk, args);
316  va_end(args); //Close the va_list
317 
318  return data;
319 }
320 
321 
322 void* nhash_pop(NHash *htbl) {
323  List *bucket;
324  ListElmt *element;
325 
326  for (int i = 0; i < htbl->buckets; i++) {
327  bucket = &htbl->table[i];
328  element = list_head(bucket);
329  if (element != NULL) {
330  NHashEntry *entry = element->data;
331  return (void*)entry->val;
332  }
333  }
334  return NULL;
335 }
336 
337 /*****************************************************************
338  * nhash_grow
339  ****************************************************************/
340 void nhash_grow(NHash *htbl) {
341  printf("nhash_grow %d -> %d (size %d, load factor %.2f)...",
342  htbl->buckets, htbl->buckets * 2, htbl->size,
343  nhash_loadfactor(htbl));
344 
345  size_t old_size = htbl->buckets;
346  List *old_table = htbl->table;
347  htbl->buckets *= 2;
348 
349  htbl->table = calloc(htbl->buckets, sizeof(List*));
350 
351  /*****************************************************************
352  * Move the buckets.
353  ****************************************************************/
354  for (size_t i = 0; i < old_size; i++) {
355  List *bucket = &old_table[i];
356  if (!list_is_empty(bucket)) {
357  ListElmt *head = list_head(bucket);
358  NHashEntry *entry = head->data;
359  int bucket_index = entry->key % htbl->buckets;
360  htbl->table[bucket_index] = *bucket;
361  }
362  }
363  free(old_table);
364 
365  /*****************************************************************
366  * Initialize the remaining buckets.
367  ****************************************************************/
368  for (int i = 0; i < htbl->buckets; i++) {
369  if (&htbl->table[i] != NULL) {
370  list_init(&htbl->table[i], htbl->destroy);
371  }
372  }
373 
374  return;
375 }
int list_ins_next(List *list, ListElmt *element, const void *data)
Inserts an element just after element on list.
Definition: list.c:78
Interface for the linked list implementation.
void list_destroy(List *list)
Destroys the linked list specified by list.
Definition: list.c:48
#define list_head(list)
evaluates to the element at the head of list.
Definition: list.h:181
void list_init(List *list, void(*destroy)(void *data))
Initializes the linked list specified by list.
Definition: list.c:31
int list_rem_next(List *list, ListElmt *element, void **data)
Removes the element just after element on list.
Definition: list.c:126
#define list_is_empty(list)
determines whether list is empty.
Definition: list.h:263
#define list_next(element)
evaluates to the element following element.
Definition: list.h:250
#define list_data(element)
evaluates to the data stored on element.
Definition: list.h:237
Definition: nhash.h:17
structure for linked lists.
Definition: list.h:56
structure for linked list elements.
Definition: list.h:43