common: remove excess semicolon
[c11tester.git] / hashtable.h
1 /** @file hashtable.h
2  *  @brief Hashtable.  Standard chained bucket variety.
3  */
4
5 #ifndef HASHTABLE_H
6 #define HASHTABLE_H
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include "mymemory.h"
11
12 /**
13  * Hashtable linked node class, for chained storage of hash table conflicts. By
14  * default it is snapshotting, but you can pass in your own allocation
15  * functions.
16  *
17  * @tparam _Key    Type name for the key
18  * @tparam _Val    Type name for the values to be stored
19  * @tparam _malloc Provide your own 'malloc' for the table, or default to
20  *                 snapshotting.
21  * @tparam _calloc Provide your own 'calloc' for the table, or default to
22  *                 snapshotting.
23  * @tparam _free   Provide your own 'free' for the table, or default to
24  *                 snapshotting.
25  */
26 template<typename _Key, typename _Val, void * (* _malloc)(size_t), void * (* _calloc)(size_t, size_t), void (*_free)(void *)>
27 struct hashlistnode {
28         _Key key;
29         _Val val;
30         struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *next;
31
32         void * operator new(size_t size) {
33                 return _malloc(size);
34         }
35
36         void operator delete(void *p, size_t size) {
37                 _free(p);
38         }
39
40         void * operator new[](size_t size) {
41                 return _malloc(size);
42         }
43
44         void operator delete[](void *p, size_t size) {
45                 _free(p);
46         }
47 };
48
49 /**
50  * Hashtable class. By default it is snapshotting, but you can pass in your own
51  * allocation functions.
52  *
53  * @tparam _Key    Type name for the key
54  * @tparam _Val    Type name for the values to be stored
55  * @tparam _KeyInt Integer 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  * @tparam _malloc Provide your own 'malloc' for the table, or default to
59  *                 snapshotting.
60  * @tparam _calloc Provide your own 'calloc' for the table, or default to
61  *                 snapshotting.
62  * @tparam _free   Provide your own 'free' for the table, or default to
63  *                 snapshotting.
64  */
65 template<typename _Key, typename _Val, typename _KeyInt, int _Shift=0, void * (* _malloc)(size_t)=snapshot_malloc, void * (* _calloc)(size_t, size_t)=snapshot_calloc, void (*_free)(void *)=snapshot_free>
66         class HashTable {
67  public:
68         /**
69          * Constructor
70          * @param initialcapacity Sets the initial capacity of the hash table.
71          * Default size 1024.
72          * @param factor Sets the percentage full before the hashtable is
73          * resized. Default ratio 0.5.
74          */
75         HashTable(unsigned int initialcapacity=1024, double factor=0.5) {
76                 // Allocate space for the hash table
77                 table = (struct hashlistnode<_Key,_Val, _malloc, _calloc,_free> **) _calloc(initialcapacity, sizeof(struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *));
78                 loadfactor = factor;
79                 capacity = initialcapacity;
80                 threshold = (unsigned int) (initialcapacity*loadfactor);
81                 mask = (capacity << _Shift)-1;
82                 size = 0; // Initial number of elements in the hash
83         }
84
85         /** Destructor */
86         ~HashTable() {
87                 for(unsigned int i=0;i<capacity;i++) {
88                         struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> * bin = table[i];
89                         while(bin!=NULL) {
90                                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> * next=bin->next;
91                                 delete bin;
92                                 bin=next;
93                         }
94                 }
95                 _free(table);
96         }
97
98         /** Override: new operator */
99         void * operator new(size_t size) {
100                 return _malloc(size);
101         }
102
103         /** Override: delete operator */
104         void operator delete(void *p, size_t size) {
105                 _free(p);
106         }
107
108         /** Override: new[] operator */
109         void * operator new[](size_t size) {
110                 return _malloc(size);
111         }
112
113         /** Override: delete[] operator */
114         void operator delete[](void *p, size_t size) {
115                 _free(p);
116         }
117
118         /** Reset the table to its initial state. */
119         void reset() {
120                 for(unsigned int i=0;i<capacity;i++) {
121                         struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> * bin = table[i];
122                         while(bin!=NULL) {
123                                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> * next=bin->next;
124                                 delete bin;
125                                 bin=next;
126                         }
127                 }
128                 memset(table, 0, capacity*sizeof(struct hashlistnode<_Key, _Val, _malloc, _calloc, _free> *));
129                 size=0;
130         }
131
132         /** Put a key value pair into the table. */
133         void put(_Key key, _Val val) {
134                 if (size > threshold)
135                         resize(capacity << 1);
136
137                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *ptr = table[(((_KeyInt)key) & mask)>>_Shift];
138                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = ptr;
139
140                 while(search!=NULL) {
141                         if (search->key==key) {
142                                 search->val=val;
143                                 return;
144                         }
145                         search=search->next;
146                 }
147
148                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *newptr=(struct hashlistnode<_Key,_Val,_malloc,_calloc,_free> *)new struct hashlistnode<_Key,_Val, _malloc, _calloc, _free>;
149                 newptr->key=key;
150                 newptr->val=val;
151                 newptr->next=ptr;
152                 table[(((_KeyInt)key)&mask)>>_Shift]=newptr;
153                 size++;
154         }
155
156         /**
157          * @brief Get a valid pointer to a value corresponding to a given key
158          *
159          * Ensure that key is present in the hash table, then return a pointer
160          * to its value bin. This may require either creating a new bin for
161          * this key (with a default-constructed value) or simply locating and
162          * returning a pointer to an existing value.
163          * @param key The key to check
164          * @return A pointer to the value in the table
165          */
166         _Val * get_safe_ptr(_Key key) {
167                 if (size > threshold)
168                         resize(capacity << 1);
169
170                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *ptr = table[(((_KeyInt)key) & mask)>>_Shift];
171                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = ptr;
172
173                 while(search!=NULL) {
174                         if (search->key==key) {
175                                 return &search->val;
176                         }
177                         search=search->next;
178                 }
179
180                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *newptr=(struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *)new struct hashlistnode<_Key,_Val, _malloc, _calloc, _free>;
181                 newptr->key=key;
182                 newptr->next=ptr;
183                 table[(((_KeyInt)key)&mask)>>_Shift]=newptr;
184                 size++;
185                 return &newptr->val;
186         }
187
188         /** Lookup the corresponding value for the given key. */
189         _Val get(_Key key) {
190                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = table[(((_KeyInt)key) & mask)>>_Shift];
191
192                 while(search!=NULL) {
193                         if (search->key==key) {
194                                 return search->val;
195                         }
196                         search=search->next;
197                 }
198                 return (_Val)0;
199         }
200
201         /** Lookup the corresponding value for the given key. */
202         _Val * getptr(_Key key) {
203                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = table[(((_KeyInt)key) & mask)>>_Shift];
204
205                 while(search!=NULL) {
206                         if (search->key==key) {
207                                 return & search->val;
208                         }
209                         search=search->next;
210                 }
211                 return (_Val *) NULL;
212         }
213
214         /** Check whether the table contains a value for the given key. */
215         bool contains(_Key key) {
216                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = table[(((_KeyInt)key) & mask)>>_Shift];
217
218                 while(search!=NULL) {
219                         if (search->key==key) {
220                                 return true;
221                         }
222                         search=search->next;
223                 }
224                 return false;
225         }
226
227         /** Resize the table. */
228         void resize(unsigned int newsize) {
229                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> ** oldtable = table;
230                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> ** newtable;
231                 unsigned int oldcapacity = capacity;
232
233                 if((newtable = (struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> **) _calloc(newsize, sizeof(struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *))) == NULL) {
234                         printf("Calloc error %s %d\n", __FILE__, __LINE__);
235                         exit(-1);
236                 }
237
238                 table = newtable;          //Update the global hashtable upon resize()
239                 capacity = newsize;
240                 threshold = (unsigned int) (newsize * loadfactor);
241                 mask = (newsize << _Shift)-1;
242
243                 for(unsigned int i = 0; i < oldcapacity; i++) {
244                         struct hashlistnode<_Key, _Val, _malloc, _calloc, _free> * bin = oldtable[i];
245
246                         while(bin!=NULL) {
247                                 _Key key=bin->key;
248                                 struct hashlistnode<_Key, _Val, _malloc, _calloc, _free> * next=bin->next;
249
250                                 unsigned int index = (((_KeyInt)key) & mask) >>_Shift;
251                                 struct hashlistnode<_Key, _Val, _malloc, _calloc, _free> * tmp=newtable[index];
252                                 bin->next=tmp;
253                                 newtable[index]=bin;
254                                 bin = next;
255                         }
256                 }
257
258                 _free(oldtable);            //Free the memory of the old hash table
259         }
260
261  private:
262         struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> **table;
263         unsigned int capacity;
264         _KeyInt mask;
265         unsigned int size;
266         unsigned int threshold;
267         double loadfactor;
268 };
269 #endif