Adding benchmark file for encrypted cloud storage.
[iotcloud.git] / version2 / src / C / hashtable.h
1 /*      Copyright (c) 2015 Regents of the University of California
2  *
3  *      Author: Brian Demsky <bdemsky@uci.edu>
4  *
5  *      This program is free software; you can redistribute it and/or
6  *      modify it under the terms of the GNU General Public License
7  *      version 2 as published by the Free Software Foundation.
8  */
9
10 /** @file hashtable.h
11  *  @brief Hashtable.  Standard chained bucket variety.
12  */
13
14 #ifndef HASHTABLE_H__
15 #define HASHTABLE_H__
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include "common.h"
21 #include "mymemory.h"
22
23 /**
24  * @brief Hashtable node
25  *
26  * @tparam _Key    Type name for the key
27  * @tparam _Val    Type name for the values to be stored
28  */
29 template<typename _Key, typename _Val>
30 struct Hashlistnode {
31         _Key key;
32         _Val val;
33 };
34
35 template<typename _Key, int _Shift, typename _KeyInt>
36 inline unsigned int defaultHashFunction(_Key hash) {
37         return (unsigned int)(((_KeyInt)hash) >> _Shift);
38 }
39
40 template<typename _Key>
41 inline bool defaultEquals(_Key key1, _Key key2) {
42         return key1 == key2;
43 }
44
45 /**
46  * @brief A simple, custom hash table
47  *
48  * By default it is snapshotting, but you can pass in your own allocation
49  * functions. Note that this table does not support the value 0 (NULL) used as
50  * a key and is designed primarily with pointer-based keys in mind. Other
51  * primitive key types are supported only for non-zero values.
52  *
53  * @tparam _Key    Type name for the key
54  * @tparam _Val    Type name for the values to be stored
55  * @tparam _KeyInt int32_t type that is at least as large as _Key. Used for key
56  *                 manipulation and storage.
57  * @tparam _Shift  Logical shift to apply to all keys. Default 0.
58  */
59
60 template<typename _Key, typename _Val, typename _KeyInt = uintptr_t, int _Shift = 0, unsigned int (*hash_function)(_Key) = defaultHashFunction<_Key, _Shift, _KeyInt>, bool (*equals)(_Key, _Key) = defaultEquals<_Key> >
61 class Hashtable {
62 public:
63         /**
64          * @brief Hash table constructor
65          * @param initialcapacity Sets the initial capacity of the hash table.
66          * Default size 1024.
67          * @param factor Sets the percentage full before the hashtable is
68          * resized. Default ratio 0.5.
69          */
70         Hashtable(unsigned int initialcapacity = 16, double factor = 0.5) {
71                 // Allocate space for the hash table
72                 table = (struct Hashlistnode<_Key, _Val> *)ourcalloc(initialcapacity, sizeof(struct Hashlistnode<_Key, _Val>));
73                 zero = NULL;
74                 loadfactor = factor;
75                 capacity = initialcapacity;
76                 capacitymask = initialcapacity - 1;
77
78                 threshold = (unsigned int)(initialcapacity * loadfactor);
79                 Size = 0;                                                       // Initial number of elements in the hash
80         }
81
82         Hashtable<_Key, _Val, _KeyInt, _Shift, hash_function, equals> *clone() {
83                 Hashtable<_Key, _Val, _KeyInt, _Shift, hash_function, equals> *ctable = new Hashtable<_Key, _Val, _KeyInt, _Shift, hash_function, equals> (capacity, loadfactor);
84                 if (zero)
85                         ctable->put(zero->key, zero->val);
86
87                 for(unsigned int i=0; i<capacity; i++) {
88                         struct Hashlistnode<_Key, _Val> ptr = table[i];                 
89                         if (ptr.key && ptr.val)
90                                 ctable->put(ptr.key, ptr.val);
91                 }
92                 return ctable;
93         }
94
95
96         /** @brief Hash table destructor */
97         ~Hashtable() {
98                 ourfree(table);
99                 if (zero)
100                         ourfree(zero);
101         }
102
103         /** Override: new operator */
104         void *operator new(size_t size) {
105                 return ourmalloc(size);
106         }
107
108         /** Override: delete operator */
109         void operator delete(void *p, size_t size) {
110                 ourfree(p);
111         }
112
113         /** Override: new[] operator */
114         void *operator new[](size_t size) {
115                 return ourmalloc(size);
116         }
117
118         /** Override: delete[] operator */
119         void operator delete[](void *p, size_t size) {
120                 ourfree(p);
121         }
122
123         /** @brief Reset the table to its initial state. */
124         void clear() {
125                 memset(table, 0, capacity * sizeof(struct Hashlistnode<_Key, _Val>));
126                 if (zero) {
127                         ourfree(zero);
128                         zero = NULL;
129                 }
130                 Size = 0;
131         }
132
133         /** Doesn't work with zero value */
134         _Val getRandomValue() {
135                 while (true) {
136                         unsigned int index = random() & capacitymask;
137                         struct Hashlistnode<_Key, _Val> *bin = &table[index];
138                         if (bin->key != NULL && bin->val != NULL) {
139                                 return bin->val;
140                         }
141                 }
142         }
143
144         void resetAndDeleteKeys() {
145                 for (unsigned int i = 0; i < capacity; i++) {
146                         struct Hashlistnode<_Key, _Val> *bin = &table[i];
147                         if (bin->key != NULL) {
148                                 delete bin->key;
149                                 bin->key = NULL;
150                                 if (bin->val != NULL) {
151                                         bin->val = NULL;
152                                 }
153                         }
154                 }
155                 if (zero) {
156                         ourfree(zero);
157                         zero = NULL;
158                 }
159                 Size = 0;
160         }
161
162         void resetAndDeleteVals() {
163                 for (unsigned int i = 0; i < capacity; i++) {
164                         struct Hashlistnode<_Key, _Val> *bin = &table[i];
165                         if (bin->key != NULL) {
166                                 bin->key = NULL;
167                                 if (bin->val != NULL) {
168                                         delete bin->val;
169                                         bin->val = NULL;
170                                 }
171                         }
172                 }
173                 if (zero) {
174                         if (zero->val != NULL)
175                                 delete zero->val;
176                         ourfree(zero);
177                         zero = NULL;
178                 }
179                 Size = 0;
180         }
181
182         void resetAndFreeVals() {
183                 for (unsigned int i = 0; i < capacity; i++) {
184                         struct Hashlistnode<_Key, _Val> *bin = &table[i];
185                         if (bin->key != NULL) {
186                                 bin->key = NULL;
187                                 if (bin->val != NULL) {
188                                         ourfree(bin->val);
189                                         bin->val = NULL;
190                                 }
191                         }
192                 }
193                 if (zero) {
194                         if (zero->val != NULL)
195                                 ourfree(zero->val);
196                         ourfree(zero);
197                         zero = NULL;
198                 }
199                 Size = 0;
200         }
201
202         /**
203          * @brief Put a key/value pair into the table
204          * @param key The key for the new value; must not be 0 or NULL
205          * @param val The value to store in the table
206          */
207         _Val put(_Key key, _Val val) {
208                 ASSERT(val);
209                 if (!key) {
210                         _Val oldval;
211                         if (!zero) {
212                                 zero = (struct Hashlistnode<_Key, _Val> *)ourmalloc(sizeof(struct Hashlistnode<_Key, _Val>));
213                                 Size++;
214                                 oldval = (_Val) 0;
215                         } else
216                                 oldval = zero->val;
217                         zero->key = key;
218                         zero->val = val;
219                         return oldval;
220                 }
221
222                 if (Size > threshold)
223                         resize(capacity << 1);
224
225                 struct Hashlistnode<_Key, _Val> *search;
226
227                 unsigned int hashcode = hash_function(key);
228                 unsigned int index = hashcode;
229                 do {
230                         index &= capacitymask;
231                         search = &table[index];
232                         if (!search->key) {
233                                 //key is null, probably done
234                                 break;
235                         }
236                         unsigned int searchhashcode = hash_function(search->key);
237                         if (searchhashcode == hashcode)
238                                 if (equals(search->key, key)) {
239                                         _Val oldval = search->val;
240                                         search->val = val;
241                                         return oldval;
242                                 }
243                         index++;
244                 } while (true);
245
246                 search->key = key;
247                 search->val = val;
248                 Size++;
249                 return (_Val) 0;
250         }
251
252         /**
253          * @brief Lookup the corresponding value for the given key
254          * @param key The key for finding the value; must not be 0 or NULL
255          * @return The value in the table, if the key is found; otherwise 0
256          */
257         _Val get(_Key key) const {
258                 struct Hashlistnode<_Key, _Val> *search;
259
260                 /* Hashtable cannot handle 0 as a key */
261                 if (!key) {
262                         if (zero)
263                                 return zero->val;
264                         else
265                                 return (_Val) 0;
266                 }
267
268                 unsigned int hashcode = hash_function(key);
269                 unsigned int oindex = hashcode & capacitymask;
270                 unsigned int index = oindex;
271                 do {
272                         search = &table[index];
273                         if (!search->key) {
274                                 if (!search->val)
275                                         break;
276                         } else {
277                                 unsigned int searchhashcode = hash_function(search->key);
278                                 if (hashcode == searchhashcode)
279                                         if (equals(search->key, key))
280                                                 return search->val;
281                         }
282                         index++;
283                         index &= capacitymask;
284                         if (index == oindex)
285                                 break;
286                 } while (true);
287                 return (_Val)0;
288         }
289
290         /**
291          * @brief Remove the given key and return the corresponding value
292          * @param key The key for finding the value; must not be 0 or NULL
293          * @return The value in the table, if the key is found; otherwise 0
294          */
295         _Val remove(_Key key) {
296                 struct Hashlistnode<_Key, _Val> *search;
297
298                 if (!key) {
299                         if (!zero) {
300                                 return (_Val)0;
301                         } else {
302                                 _Val v = zero->val;
303
304                                 ourfree(zero);
305                                 zero = NULL;
306                                 Size--;
307                                 return v;
308                         }
309                 }
310
311
312                 unsigned int hashcode = hash_function(key);
313                 unsigned int index = hashcode;
314                 do {
315                         index &= capacitymask;
316                         search = &table[index];
317                         if (!search->key) {
318                                 if (!search->val)
319                                         break;
320                         } else {
321                                 unsigned int searchhashcode = hash_function(search->key);
322                                 if (hashcode == searchhashcode)
323                                         if (equals(search->key, key)) {
324                                                 _Val v = search->val;
325                                                 //empty out this bin
326                                                 search->val = (_Val) 1;
327                                                 search->key = 0;
328                                                 Size--;
329                                                 return v;
330                                         }
331                         }
332                         index++;
333                 } while (true);
334                 return (_Val)0;
335         }
336
337         unsigned int size() const {
338                 return Size;
339         }
340
341
342         /**
343          * @brief Check whether the table contains a value for the given key
344          * @param key The key for finding the value; must not be 0 or NULL
345          * @return True, if the key is found; false otherwise
346          */
347         bool contains(_Key key) const {
348                 struct Hashlistnode<_Key, _Val> *search;
349
350                 /* Hashtable cannot handle 0 as a key */
351                 if (!key) {
352                         return zero != NULL;
353                 }
354
355                 unsigned int index = hash_function(key);
356                 unsigned int hashcode = index;
357                 do {
358                         index &= capacitymask;
359                         search = &table[index];
360                         if (!search->key) {
361                                 if (!search->val)
362                                         break;
363                         } else {
364                                 unsigned int searchhashcode = hash_function(search->key);
365                                 if (hashcode == searchhashcode)
366                                         if (equals(search->key, key))
367                                                 return true;
368                         }
369                         index++;
370                 } while (true);
371                 return false;
372         }
373
374         /**
375          * @brief Resize the table
376          * @param newsize The new size of the table
377          */
378         void resize(unsigned int newsize) {
379                 struct Hashlistnode<_Key, _Val> *oldtable = table;
380                 struct Hashlistnode<_Key, _Val> *newtable;
381                 unsigned int oldcapacity = capacity;
382
383                 if ((newtable = (struct Hashlistnode<_Key, _Val> *)ourcalloc(newsize, sizeof(struct Hashlistnode<_Key, _Val>))) == NULL) {
384                         model_print("calloc error %s %d\n", __FILE__, __LINE__);
385                         exit(EXIT_FAILURE);
386                 }
387
388                 table = newtable;                                                                                       // Update the global hashtable upon resize()
389                 capacity = newsize;
390                 capacitymask = newsize - 1;
391                 threshold = (unsigned int)(newsize * loadfactor);
392
393                 struct Hashlistnode<_Key, _Val> *bin = &oldtable[0];
394                 struct Hashlistnode<_Key, _Val> *lastbin = &oldtable[oldcapacity];
395                 for (; bin < lastbin; bin++) {
396                         _Key key = bin->key;
397
398                         struct Hashlistnode<_Key, _Val> *search;
399                         if (!key)
400                                 continue;
401
402                         unsigned int hashcode = hash_function(bin->key);
403                         unsigned int index = hashcode;
404                         do {
405                                 index &= capacitymask;
406                                 search = &table[index];
407                                 index++;
408                         } while (search->key);
409
410                         search->key = key;
411                         search->val = bin->val;
412                 }
413
414                 ourfree(oldtable);                                                                                              // Free the memory of the old hash table
415         }
416         double getLoadFactor() {return loadfactor;}
417         unsigned int getCapacity() {return capacity;}
418         struct Hashlistnode<_Key, _Val> *table;
419         struct Hashlistnode<_Key, _Val> *zero;
420         unsigned int capacity;
421         unsigned int Size;
422 private:
423         unsigned int capacitymask;
424         unsigned int threshold;
425         double loadfactor;
426 };
427
428 #endif/* __HASHTABLE_H__ */