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