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