-
Notifications
You must be signed in to change notification settings - Fork 6
/
hashmap.hh
348 lines (285 loc) · 10.1 KB
/
hashmap.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/*
* FreeGuard: A Faster Secure Heap Allocator
* Copyright (C) 2017 Sam Silvestro, Hongyu Liu, Corey Crosser,
* Zhiqiang Lin, and Tongping Liu
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @file hashmap.hh: hash map implementation.
* The original design is from kulesh [squiggly] isis.poly.edu
* @author Tongping Liu <http://www.cs.utsa.edu/~tongpingliu/>
* @author Sam Silvestro <[email protected]>
*/
#ifndef __FCHASHMAP_HH__
#define __FCHASHMAP_HH__
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "list.hh"
#include "xdefines.hh"
template <class KeyType, // What is the key? A long or string
class ValueType, // What is the value there?
class SourceHeap> // Where to call malloc
class HashMap {
// Each entry has a lock.
struct HashEntry {
list_t list;
// Each entry has a separate lock
size_t count; // How many _entries in this list
void initialize() {
count = 0;
listInit(&list);
}
void* getFirstEntry() { return (void*)list.next; }
};
struct Entry {
list_t list;
KeyType key;
size_t keylen;
ValueType value;
void initialize(KeyType ikey = 0, int ikeylen = 0, ValueType ivalue = 0) {
listInit(&list);
key = ikey;
keylen = ikeylen;
value = ivalue;
}
void erase() { listRemoveNode(&list); }
struct Entry* nextEntry() { return (struct Entry*)list.next; }
ValueType getValue() { return value; }
KeyType getKey() { return key; }
};
bool _initialized;
struct HashEntry* _entries;
size_t _buckets; // How many buckets in total
size_t _bucketsUsed; // How many buckets in total
typedef bool (*keycmpFuncPtr)(const KeyType, const KeyType, size_t);
typedef size_t (*hashFuncPtr)(const KeyType, size_t);
keycmpFuncPtr _keycmp;
hashFuncPtr _hashfunc;
public:
HashMap() : _initialized(false) {
// printf("RESET hashmap at %p\n", &_initialized);
}
void initialize(hashFuncPtr hfunc, keycmpFuncPtr kcmp, const size_t size = 4096) {
_entries = NULL;
_bucketsUsed = 0;
_buckets = size;
if(hfunc == NULL || kcmp == NULL) {
//PRINF("Hashfunc or kcmp should not be null\n");
abort();
}
// Initialize those functions.
_hashfunc = hfunc;
_keycmp = kcmp;
// Allocated predefined size.
_entries = (struct HashEntry*)SourceHeap::allocate(size * sizeof(struct HashEntry));
// PRINF("hashmap initialization at %p pid %d index %d\n", &_initialized,getpid(),
// getThreadIndex());
// PRINF("hashmap initialization _entries %p\n", _entries);
// Initialize all of these _entries.
struct HashEntry* entry;
for(size_t i = 0; i < size; i++) {
entry = getHashEntry(i);
entry->initialize();
}
_initialized = true;
}
inline struct HashEntry* getHashEntry(size_t index) {
if(index < _buckets) {
return &_entries[index];
} else {
return NULL;
}
}
inline size_t hashIndex(const KeyType& key, size_t keylen) {
size_t hkey = _hashfunc(key, keylen);
return hkey % _buckets;
}
// Look up whether an entry is existing or not.
// If existing, return true. *value should be carried specific value for this key.
// Otherwise, return false.
bool find(const KeyType& key, size_t keylen, ValueType* value) {
assert(_initialized == true);
size_t hindex = hashIndex(key, keylen);
struct HashEntry* first = getHashEntry(hindex);
struct Entry* entry = getEntry(first, key, keylen);
bool isFound = false;
if(entry) {
*value = entry->value;
isFound = true;
}
return isFound;
}
void insert(const KeyType& key, size_t keylen, ValueType value) {
if(_initialized != true) {
//PRINT("process %d index %d: initialized at %p hashmap is not true\n", getpid(),
// getThreadIndex(), &_initialized);
}
assert(_initialized == true);
size_t hindex = hashIndex(key, keylen);
// PRINF("Insert entry: before inserting\n");
struct HashEntry* first = getHashEntry(hindex);
// PRINF("Insert entry: key %p\n", key);
insertEntry(first, key, keylen, value);
}
// Insert a hash table entry if it is not existing.
// If the entry is already existing, return true
bool insertIfAbsent(const KeyType& key, size_t keylen, ValueType value) {
assert(_initialized == true);
size_t hindex = hashIndex(key, keylen);
struct HashEntry* first = getHashEntry(hindex);
struct Entry* entry;
bool isFound = true;
// Check all _entries with the same hindex.
entry = getEntry(first, key, keylen);
if(!entry) {
isFound = false;
insertEntry(first, key, keylen, value);
}
return isFound;
}
// Free an entry with specified
bool erase(const KeyType& key, size_t keylen) {
assert(_initialized == true);
size_t hindex = hashIndex(key, keylen);
struct HashEntry* first = getHashEntry(hindex);
struct Entry* entry;
bool isFound = false;
entry = getEntry(first, key, keylen);
// PRINF("Erapse the entry key %p entry %p\n", key, entry);
if(entry) {
isFound = true;
// Check whether this entry is the first entry.
// Remove this entry if existing.
entry->erase();
SourceHeap::deallocate(entry);
}
first->count--;
return isFound;
}
// Clear all _entries
void clear() {}
private:
// Create a new Entry with specified key and value.
struct Entry* createNewEntry(const KeyType& key, size_t keylen, ValueType value) {
struct Entry* entry = (struct Entry*)SourceHeap::allocate(sizeof(struct Entry));
// Initialize this new entry.
entry->initialize(key, keylen, value);
return entry;
}
void insertEntry(struct HashEntry* head, const KeyType& key, size_t keylen, ValueType value) {
// Check whether the first entry is empty or not.
// Create an entry
struct Entry* entry = createNewEntry(key, keylen, value);
listInsertTail(&entry->list, &head->list);
head->count++;
/*
PRINF("insertEntry entry %p at head %p, headcount %ld\n", entry, head, head->count);
PRINF("insertEntry entry %p, entrynext %p, at head %p hear->list %p headlist->next %p\n", entry,
entry->list.next, head, &head->list, head->list.next);
*/
}
// Search the entry in the corresponding list.
struct Entry* getEntry(struct HashEntry* first, const KeyType& key, size_t keylen) {
struct Entry* entry = (struct Entry*)first->getFirstEntry();
struct Entry* result = NULL;
// Check all _entries with the same hindex.
int count = first->count;
// PRINF("getEntry count is %d\n", count);
while(count > 0) {
if(entry->keylen == keylen && _keycmp(entry->key, key, keylen)) {
result = entry;
break;
}
entry = entry->nextEntry();
count--;
}
return result;
}
public:
class iterator {
friend class HashMap<KeyType, ValueType, SourceHeap>;
struct Entry* _entry; // Which entry in the current hash entry?
size_t _pos; // which bucket at the moment? [0, nbucket-1]
HashMap* _hashmap;
public:
iterator(struct Entry* ientry = NULL, int ipos = 0, HashMap* imap = NULL) {
// cout << "In default constructor of iterator\n";
_pos = ipos;
_entry = ientry;
_hashmap = imap;
}
~iterator() {}
iterator& operator++(int) // in postfix ++ /* parameter? */
{
struct HashEntry* hashentry = _hashmap->getHashEntry(_pos);
// Check whether this entry is the last entry in current hash entry.
if(!isListTail(&_entry->list, &hashentry->list)) {
// If not, then we simply get next entry. No need to change pos.
_entry = _entry->nextEntry();
} else {
// Since current list is empty, we must search next hash entry.
_pos++;
while((hashentry = _hashmap->getHashEntry(_pos)) != NULL) {
if(hashentry->count != 0) {
// Now we can return it.
_entry = (struct Entry*)hashentry->getFirstEntry();
return *this;
}
_pos++;
}
_entry = NULL;
}
return *this;
}
// iterator& operator -- ();
// Iterpreted as a = b is treated as a.operator=(b)
iterator& operator=(const iterator& that) {
_entry = that._entry;
_pos = that._pos;
_hashmap = that._hashmap;
return *this;
}
bool operator==(const iterator& that) const { return _entry == that._entry; }
bool operator!=(const iterator& that) const { return _entry != that._entry; }
ValueType getData() { return _entry->getValue(); }
KeyType getkey() { return _entry->getKey(); }
};
// Acquire the first entry of the hash table
iterator begin() {
size_t pos = 0;
struct HashEntry* head = NULL;
struct Entry* entry;
// PRINF("in the beginiing of begin\n");
// Get the first non-null entry
while(pos < _buckets) {
head = getHashEntry(pos);
// PRINF("begin, head %p pos %ld head->count %ld\n", head, pos, head->count);
if(head->count != 0) {
// Now we can return it.
entry = (struct Entry*)head->getFirstEntry();
// PRINF("In begin() function, head %p, firstentry %p, firstentry next %p\n", head, entry,
//entry->list.next);
return iterator(entry, pos, this);
}
pos++;
}
return end();
}
iterator end() { return iterator(NULL, 0, this); }
};
#endif //__FCHASHMAP_H__