Dynalib Utils
DynaHashSetImpl.h
Go to the documentation of this file.
1 //
2 // Created by Ken Kopelson on 27/12/17.
3 //
4 
5 #ifndef DYNAHASHSETIMPL_H
6 #define DYNAHASHSETIMPL_H
7 
8 #include <iostream>
9 #include <type_traits>
10 using namespace std;
11 #include "BitManip.h"
12 #include "DynaAllocImpl.h"
13 #include "DynaHashSet.h"
14 #include "CheckForError.h"
15 
16 #define MAKE_SETTYPE_INSTANCE(E, T) \
17  template class DynaHashSet<E>; \
18  typedef DynaHashSet<E> T##Set
19 
20 //===========================================================================
21 // Private/Protected Methods
22 //===========================================================================
23 template <typename V> void DynaHashSet<V>::_init(int size) {
24  _table = new SetEntry<V>*[size];
25  memset((void*)_table, 0, size * sizeof(SetEntry<V>*));
26 }
27 
28 template <typename V> int DynaHashSet<V>::_getHashCode(const V* value) const {
29  int hash = 0;
30  try {
31  hash = value->hashCode();
32  }
33  catch (Exception& e) {
34  hash = 0;
35  }
36  return hash;
37 }
38 
39 template <typename V> void DynaHashSet<V>::_reHash(int newCapacity) {
40  int oldCapacity = _capacity;
41  auto** newTable = new SetEntry<V>*[newCapacity];
42  memset((void*)newTable, 0, newCapacity * sizeof(SetEntry<V>*));
43  for (int idx = 0; idx < oldCapacity; ++idx) {
44  SetEntry<V>* obj = _table[idx];
45  if (obj == nullptr || obj == deletedObject)
46  continue;
47  int hash = _getHashCode(obj->getValue());
48  int index = ( hash & 0x7FFFFFF ) % newCapacity;
49  int offset = 1;
50  while (newTable[index] != nullptr) {
51  index = ((index + offset) & 0x7FFFFFFF) % newCapacity;
52  offset = offset * 2 + 1;
53  if (offset == -1)
54  offset = 2;
55  }
56  newTable[index] = obj;
57  }
58  delete _table;
59  _table = newTable;
60  _capacity = newCapacity;
61  _freeCells = newCapacity - _count;
62 }
63 
64 //===========================================================================
65 // Constructors/Destructor
66 //===========================================================================
74 template <typename V> SetEntry<V>::SetEntry(V* value, bool ownsValue) :
75  _value(value), _ownsValue(ownsValue) {
76 }
77 
78 template <typename V> SetEntry<V>::SetEntry(const SetEntry<V>& other) {
79  _ownsValue = other._ownsValue;
80  if (_ownsValue) {
81  if (other._value != nullptr) {
82  try {
83  _value = (V*) (other._value)->copy();
84  }
85  catch (Exception& e) {
86  _value = other._value;
87  _ownsValue = false;
88  }
89  }
90  }
91  else {
92  _value = other._value;
93  }
94 }
95 
96 template <typename V> SetEntry<V>::~SetEntry() {
97  if (_ownsValue && (_value != DynaHashSet<V>::nullObject)) {
98  delete _value;
99  }
100 }
101 
102 template <typename V> SetEntry<V>* SetEntry<V>::copy() {
103  return new SetEntry(*this);
104 };
105 
106 
112 template <typename V> DynaHashSet<V>::DynaHashSet() :
113  _count(0), _capacity(INITIAL_SIZE), _freeCells(INITIAL_SIZE), _modCount(0), _ownsMembers(true) {
115 }
116 
117 template <typename V> DynaHashSet<V>::DynaHashSet(int size) :
118  _count(0), _capacity(size), _freeCells(size), _modCount(0), _ownsMembers(true) {
119  _init(size);
120 }
121 
122 template <typename V> DynaHashSet<V>::~DynaHashSet() {
123  for (int i = 0; i < _capacity; ++i) {
124  SetEntry<V>* entry = _table[i];
125  if (entry != nullptr) {
126  if (entry != DynaHashSet<V>::deletedObject)
127  delete entry;
128  _table[i] = nullptr;
129  }
130  }
131  delete[] _table;
132 }
133 
134 template <typename V> DynaHashSet<V>::DynaHashSet(const DynaHashSet<V>& other) {
135  SetEntry<V>* entry;
136  _count = other._count;
137  _capacity = other._capacity;
138  _modCount = other._modCount;
139  _freeCells = other._freeCells;
140  _ownsMembers = other._ownsMembers;
141  _table = new SetEntry<V>*[other._capacity];
142  for (int i = 0, len = other._capacity; i < len; ++i) {
143  entry = other._table[i];
144  if (entry != nullptr) {
145  try {
146  _table[i] = entry->copy();
147  }
148  catch (Exception& e) {
149  }
150  }
151  }
152 }
153 
154 template <typename V> DynaHashSet<V>* DynaHashSet<V>::copy() {
155  return new DynaHashSet<V>(*this);
156 };
157 
158 template <typename V> SetIter<V>::SetIter(const DynaHashSet<V>* set, int start) : _curIndex(start), _set(set) {
159  SetEntry<V>** table = _set->_table;
160  for (; hasNext() && (table[_curIndex] == nullptr || table[_curIndex] == _set->deletedObject); ++_curIndex);
161 }
162 
163 template <typename V> int DynaHashSet<V>::_getTableIndex(V* value) {
164  if (value == nullptr)
165  value = nullObject;
166  int hash = _getHashCode(value);
167  int index = ( hash & 0x7FFFFFF ) % _capacity;
168  int offset = 1;
169 
170  SetEntry<V>* entry = _table[index];
171  while ( entry != nullptr &&
172  (entry == deletedObject || !((_getHashCode(entry->getValue()) == hash) && (*(entry->getValue()) == *value)))) {
173  index = ((index + offset) & 0x7FFFFFFF) % _capacity;
174  entry = _table[index];
175  offset = offset * 2 + 1;
176  if (offset == -1)
177  offset = 2;
178  }
179  return index;
180 }
181 
182 
183 //===========================================================================
184 // Public Methods
185 //===========================================================================
192 template <typename V> const V* SetEntry<V>::setValue(V* newValue) {
193  V* oldValue = _value;
194  _value = newValue;
195  return oldValue;
196 }
197 template <typename V> bool SetEntry<V>::operator== (const SetEntry<V>& other) const {
198  V* v1 = getValue();
199  V* v2 = other.getValue();
200  return v1 == v2 || (v1 != nullptr && *v1 == *v2);
201 }
202 
210 template <typename V> SetEntry<V>* DynaHashSet<V>::getEntry(V* value) {
211  int index = _getTableIndex(value);
212  return _table[index];
213 };
214 
215 template <typename V> SetEntry<V>* DynaHashSet<V>::getEntry(V value) {
216  return getEntry(&value);
217 }
218 
219 template <typename V> bool DynaHashSet<V>::add(V* value) {
220  if (value == nullptr)
221  value = nullObject;
222  int hash = _getHashCode(value);
223  int index = ( hash & 0x7FFFFFF ) % _capacity;
224  int offset = 1;
225  int deletedIdx = -1;
226 
227  SetEntry<V>* entry = _table[index];
228  while ( entry != nullptr &&
229  (entry == deletedObject || !((_getHashCode(entry->getValue()) == hash) && (*(entry->getValue()) == *value)))) {
230  if (entry == deletedObject)
231  deletedIdx = index;
232 
233  index = ((index + offset) & 0x7FFFFFFF) % _capacity;
234  entry = _table[index];
235  offset = offset * 2 + 1;
236  if (offset == -1)
237  offset = 2;
238  }
239 
240  if (entry == nullptr) {
241  if (deletedIdx != -1)
242  index = deletedIdx;
243  else
244  --_freeCells;
245  ++_modCount;
246  ++_count;
247  _table[index] = new SetEntry<V>(value, _ownsMembers);
248 
249  if (1 - (_freeCells / (double)_capacity) > LOAD_FACTOR) {
250  _reHash(_capacity);
251  if (1 - (_freeCells / (double)_capacity) > LOAD_FACTOR) {
252  _reHash(_capacity * 2 + 1);
253  }
254  }
255  }
256  else {
257  return false;
258  }
259  return true;
260 }
261 
262 template <typename V> bool DynaHashSet<V>::add(V value) {
263  return add(new V(value));
264 }
265 
266 template <typename V> V* DynaHashSet<V>::remove(V* value) {
267  int index = _getTableIndex(value);
268 
269  if (_table[index] != nullptr && _table[index] != deletedObject) {
270  V* saveValue = _table[index]->getValue();
271  _table[index]->setValue(nullptr); // Prevent the value object from being deleted
272  delete _table[index]; // delete the entry from the table
273  _table[index] = deletedObject; // Mark the table entry as deleted
274  ++_modCount;
275  --_count;
276  return saveValue;
277  }
278  else
279  return nullptr;
280 }
281 
282 template <typename V> V* DynaHashSet<V>::remove(V value) {
283  return remove(&value);
284 }
285 
286 template <typename V> void DynaHashSet<V>::deleteEntry(V* value) {
287  int index = _getTableIndex(value);
288 
289  if (_table[index] != nullptr && _table[index] != deletedObject) {
290  delete _table[index]; // delete the entry from the table
291  _table[index] = deletedObject; // Mark the table entry as deleted
292  ++_modCount;
293  --_count;
294  }
295 }
296 
297 template <typename V> void DynaHashSet<V>::deleteEntry(V value) {
298  return deleteEntry(&value);
299 }
300 
302  if (ent == nullptr)
303  return nullptr;
304  int index = _getTableIndex(ent->getValue());
305 
306  if (_table[index] != nullptr && _table[index] != deletedObject) {
307  SetEntry<V>* saveEntry = _table[index];
308  _table[index] = deletedObject;
309  ++_modCount;
310  --_count;
311  return saveEntry;
312  }
313  else
314  return nullptr;
315 }
316 
317 
318 template <typename V> void DynaHashSet<V>::clear() {
319  for (int idx = 0; idx < _capacity; ++idx) {
320  SetEntry<V>* entry = _table[idx];
321  if (entry != nullptr) {
322  if (entry != DynaHashSet<V>::deletedObject) {
323  delete entry;
324  --_count;
325  }
326  _table[idx] = nullptr;
327  }
328  }
329  _count = 0;
330  _freeCells = _capacity;
331  ++_modCount;
332 }
333 
334 template <typename V> DynaSetIter<V> DynaHashSet<V>::begin() {
335  return DynaSetIter<V>( this, 0 );
336 }
337 
338 template <typename V> DynaSetIter<V> DynaHashSet<V>::end() {
339  return DynaSetIter<V>( this, _capacity );
340 }
341 
342 template <typename V> SetIter<V> DynaHashSet<V>::values() {
343  return SetIter<V>(this);
344 };
345 
346 template <typename V> const SetIter<V>& SetIter<V>::operator++ () {
347  SetEntry<V>** table = _set->_table;
348  for (++_curIndex; hasNext() &&
349  (table[_curIndex] == nullptr || table[_curIndex] == _set->deletedObject); ++_curIndex);
350  return *this;
351 }
352 
353 template <typename V> const SetIter<V>& SetIter<V>::operator-- () {
354  SetEntry<V>** table = _set->_table;
355  for (--_curIndex; hasPrev() &&
356  (table[_curIndex] == nullptr || table[_curIndex] == _set->deletedObject); --_curIndex);
357  return *this;
358 }
359 
360 //===========================================================================
361 // Static Initialization
362 //===========================================================================
363 template <typename V> V DynaHashSet<V>::nullObjectInstance;
364 template <typename V> V* DynaHashSet<V>::nullObject = &nullObjectInstance;
365 
367 template <typename V> SetEntry<V>* DynaHashSet<V>::deletedObject = &deletedObjectInstance;
368 
369 #endif //DYNAHASHSETIMPL_H
int _modCount
Definition: DynaHashSet.h:80
bool hasNext()
Definition: DynaHashSet.h:178
GeneratorWrapper< std::tuple< Ts... > > table(std::initializer_list< std::tuple< typename std::decay< Ts >::type... >> tuples)
Definition: catch.hpp:4058
int _getTableIndex(V *value)
Definition: DynaHashSetImpl.h:163
int _count
Definition: DynaHashSet.h:77
SetIter< V > values()
Definition: DynaHashSetImpl.h:342
virtual ~SetEntry()
Definition: DynaHashSetImpl.h:96
V * getValue() const
Definition: DynaHashSet.h:36
SetEntry< V > * copy() override
Definition: DynaHashSetImpl.h:102
V * remove(V *value)
Definition: DynaHashSetImpl.h:266
void _init(int size)
Definition: DynaHashSetImpl.h:23
int _getHashCode(const V *value) const
Definition: DynaHashSetImpl.h:28
GeneratorWrapper< T > value(T &&value)
Definition: catch.hpp:4005
Definition: DynaHashSet.h:25
void clear()
Definition: DynaHashSetImpl.h:318
bool operator==(const SetEntry< V > &other) const override
Definition: DynaHashSetImpl.h:197
virtual ~DynaHashSet()
Definition: DynaHashSetImpl.h:122
SetEntry(V *value, bool ownsValue)
Definition: DynaHashSetImpl.h:74
SetEntry< V > * removeEntry(SetEntry< V > *entry)
Definition: DynaHashSetImpl.h:301
void _reHash(int newCapacity)
Definition: DynaHashSetImpl.h:39
static constexpr int INITIAL_SIZE
Definition: DynaHashSet.h:70
SetEntry< V > * getEntry(V *value)
Definition: DynaHashSetImpl.h:210
int _capacity
Definition: DynaHashSet.h:78
bool _ownsMembers
Definition: DynaHashSet.h:81
void deleteEntry(V *value)
Definition: DynaHashSetImpl.h:286
Definition: DynaHashSet.h:63
const SetIter< V > & operator++()
Definition: DynaHashSetImpl.h:346
Definition: DynaHashSet.h:61
int add(int code, T value)
Definition: HashCoder.h:34
bool add(V *value)
Definition: DynaHashSetImpl.h:219
DynaSetIter< V > begin()
Definition: DynaHashSetImpl.h:334
DynaSetIter< V > end()
Definition: DynaHashSetImpl.h:338
Definition: Exception.h:13
bool hasPrev()
Definition: DynaHashSet.h:179
Definition: DynaHashSet.h:60
DynaHashSet< V > * copy() override
Definition: DynaHashSetImpl.h:154
DynaHashSet()
Definition: DynaHashSetImpl.h:112
SetIter(const DynaHashSet< V > *set, int start)
Definition: DynaHashSetImpl.h:158
int _freeCells
Definition: DynaHashSet.h:79
SetEntry< V > ** _table
Definition: DynaHashSet.h:76
const SetIter< V > & operator--()
Definition: DynaHashSetImpl.h:353
const V * setValue(V *newValue)
Definition: DynaHashSetImpl.h:192