hashtable: add some documentation
[model-checker.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(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
135                         unsigned int newsize = capacity << 1;
136                         resize(newsize);
137                 }
138
139                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *ptr = table[(((_KeyInt)key) & mask)>>_Shift];
140                 size++;
141                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = ptr;
142
143                 while(search!=NULL) {
144                         if (search->key==key) {
145                                 search->val=val;
146                                 return;
147                         }
148                         search=search->next;
149                 }
150
151                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *newptr=(struct hashlistnode<_Key,_Val,_malloc,_calloc,_free> *)new struct hashlistnode<_Key,_Val, _malloc, _calloc, _free>;
152                 newptr->key=key;
153                 newptr->val=val;
154                 newptr->next=ptr;
155                 table[(((_KeyInt)key)&mask)>>_Shift]=newptr;
156         }
157
158         /** Put a key entry into the table. */
159         _Val * ensureptr(_Key key) {
160                 if (size > threshold) {
161                         //Resize
162                         unsigned int newsize = capacity << 1;
163                         resize(newsize);
164                 }
165
166                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *ptr = table[(((_KeyInt)key) & mask)>>_Shift];
167                 size++;
168                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = ptr;
169
170                 while(search!=NULL) {
171                         if (search->key==key) {
172                                 return &search->val;
173                         }
174                         search=search->next;
175                 }
176
177                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *newptr=(struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *)new struct hashlistnode<_Key,_Val, _malloc, _calloc, _free>;
178                 newptr->key=key;
179                 newptr->next=ptr;
180                 table[(((_KeyInt)key)&mask)>>_Shift]=newptr;
181                 return &newptr->val;
182         }
183
184         /** Lookup the corresponding value for the given key. */
185         _Val get(_Key key) {
186                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = table[(((_KeyInt)key) & mask)>>_Shift];
187
188                 while(search!=NULL) {
189                         if (search->key==key) {
190                                 return search->val;
191                         }
192                         search=search->next;
193                 }
194                 return (_Val)0;
195         }
196
197         /** Lookup the corresponding value for the given key. */
198         _Val * getptr(_Key key) {
199                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = table[(((_KeyInt)key) & mask)>>_Shift];
200
201                 while(search!=NULL) {
202                         if (search->key==key) {
203                                 return & search->val;
204                         }
205                         search=search->next;
206                 }
207                 return (_Val *) NULL;
208         }
209
210         /** Check whether the table contains a value for the given key. */
211         bool contains(_Key key) {
212                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *search = table[(((_KeyInt)key) & mask)>>_Shift];
213
214                 while(search!=NULL) {
215                         if (search->key==key) {
216                                 return true;
217                         }
218                         search=search->next;
219                 }
220                 return false;
221         }
222
223         /** Resize the table. */
224         void resize(unsigned int newsize) {
225                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> ** oldtable = table;
226                 struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> ** newtable;
227                 unsigned int oldcapacity = capacity;
228
229                 if((newtable = (struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> **) _calloc(newsize, sizeof(struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> *))) == NULL) {
230                         printf("Calloc error %s %d\n", __FILE__, __LINE__);
231                         exit(-1);
232                 }
233
234                 table = newtable;          //Update the global hashtable upon resize()
235                 capacity = newsize;
236                 threshold = (unsigned int) (newsize * loadfactor);
237                 mask = (newsize << _Shift)-1;
238
239                 for(unsigned int i = 0; i < oldcapacity; i++) {
240                         struct hashlistnode<_Key, _Val, _malloc, _calloc, _free> * bin = oldtable[i];
241
242                         while(bin!=NULL) {
243                                 _Key key=bin->key;
244                                 struct hashlistnode<_Key, _Val, _malloc, _calloc, _free> * next=bin->next;
245
246                                 unsigned int index = (((_KeyInt)key) & mask) >>_Shift;
247                                 struct hashlistnode<_Key, _Val, _malloc, _calloc, _free> * tmp=newtable[index];
248                                 bin->next=tmp;
249                                 newtable[index]=bin;
250                                 bin = next;
251                         }
252                 }
253
254                 _free(oldtable);            //Free the memory of the old hash table
255         }
256
257  private:
258         struct hashlistnode<_Key,_Val, _malloc, _calloc, _free> **table;
259         unsigned int capacity;
260         _KeyInt mask;
261         unsigned int size;
262         unsigned int threshold;
263         double loadfactor;
264 };
265 #endif