WHashMap.h
Go to the documentation of this file.
1 /* $Id: HashMap.h 1198 2011-06-14 21:08:27Z bhagman $
2 ||
3 || @author Alexander Brevig <abrevig@wiring.org.co>
4 || @url http://wiring.org.co/
5 || @url http://alexanderbrevig.com/
6 || @contribution Brett Hagman <bhagman@wiring.org.co>
7 ||
8 || @description
9 || | Implementation of a HashMap data structure.
10 || |
11 || | Wiring Cross-platform Library
12 || #
13 ||
14 || @license Please see cores/Common/License.txt.
15 ||
16 */
17 
18 /*
19  * @author: 3 Oct 2018 - mikee47 <mike@sillyhouse.net>
20  *
21  * Modified to use references (const or otherwise) to avoid object copies when used with classes, e.g. String.
22  *
23  * Note that if the value is a primitive then setNullValue should be called to provide a default value to be
24  * used when adding a new unspecified entry, or if a key value is not present. This should not be necessary
25  * for object values as the default constructor will be used.
26  *
27  */
28 
29 #pragma once
30 
31 #include <cstdint>
32 #include <iterator>
33 
38 template <typename K, typename V> class HashMap
39 {
40 public:
41  using Comparator = bool (*)(const K&, const K&);
42 
43  template <bool is_const> struct BaseElement {
44  public:
45  using Value = typename std::conditional<is_const, const V, V>::type;
46 
47  BaseElement(const K& key, Value& value) : k(key), v(value)
48  {
49  }
50 
51  const K& key() const
52  {
53  return k;
54  }
55 
57  {
58  return v;
59  }
60 
61  const V& value() const
62  {
63  return v;
64  }
65 
67  {
68  v = value;
69  return *this;
70  }
71 
72  private:
73  const K& k;
74  Value& v;
75  };
76 
77  using Element = BaseElement<false>;
78  using ElementConst = BaseElement<true>;
79 
80  template <bool is_const>
81  class Iterator : public std::iterator<std::random_access_iterator_tag, BaseElement<is_const>>
82  {
83  public:
84  using Map = typename std::conditional<is_const, const HashMap, HashMap>::type;
85  using Value = typename std::conditional<is_const, const V, V>::type;
86 
87  Iterator(const Iterator&) = default;
88 
89  Iterator(Map& map, unsigned index) : map(map), index(index)
90  {
91  }
92 
94  {
95  ++index;
96  return *this;
97  }
98 
100  {
101  Iterator tmp(*this);
102  ++index;
103  return tmp;
104  }
105 
106  Iterator operator+=(size_t distance)
107  {
108  Iterator tmp(*this);
109  index += distance;
110  return tmp;
111  }
112 
113  bool operator==(const Iterator& rhs) const
114  {
115  return &map == &rhs.map && index == rhs.index;
116  }
117 
118  bool operator!=(const Iterator& rhs) const
119  {
120  return !operator==(rhs);
121  }
122 
124  {
125  return BaseElement<is_const>{map.keyAt(index), map.valueAt(index)};
126  }
127 
129  {
130  return ElementConst{map.keyAt(index), map.valueAt(index)};
131  }
132 
133  private:
134  Map& map;
135  unsigned index{0};
136  };
137 
138  /*
139  || @constructor
140  || | Default constructor
141  || #
142  */
144  {
145  }
146 
147  /*
148  || @constructor
149  || | Initialize this HashMap
150  || #
151  ||
152  || @parameter compare optional function for comparing a key against another (for complex types)
153  */
154  HashMap(Comparator compare) : cb_comparator(compare)
155  {
156  }
157 
159  {
160  clear();
161  }
162 
163  /*
164  || @description
165  || | Get the size of this HashMap
166  || #
167  ||
168  || @return The size of this HashMap
169  */
170  unsigned int count() const
171  {
172  return currentIndex;
173  }
174 
175  /*
176  || @description
177  || | Get a key at a specified index
178  || #
179  ||
180  || @parameter idx the index to get the key at
181  ||
182  || @return The key at index idx
183  */
184  const K& keyAt(unsigned int idx) const
185  {
186  if(idx >= count()) {
187  abort();
188  }
189  return *keys[idx];
190  }
191 
192  K& keyAt(unsigned int idx)
193  {
194  if(idx >= count()) {
195  abort();
196  }
197  return *keys[idx];
198  }
199 
200  /*
201  || @description
202  || | Get a value at a specified index
203  || #
204  ||
205  || @parameter idx the index to get the value at
206  ||
207  || @return The value at index idx
208  */
209  const V& valueAt(unsigned int idx) const
210  {
211  if(idx >= count()) {
212  abort();
213  }
214  return *values[idx];
215  }
216 
217  V& valueAt(unsigned int idx)
218  {
219  if(idx >= count()) {
220  abort();
221  }
222  return *values[idx];
223  }
224 
225  /*
226  || @description
227  || | An indexer for accessing and assigning a value to a key
228  || | If a key is used that exists, it returns the value for that key
229  || | If there exists no value for that key, a nil value is returned
230  || |
231  || | Note that if the HashMap object is not const, the non-const version
232  || | of this operator will be called which will create a default value
233  || | for this key. If that behaviour is not desired, then check for the
234  || | existence of the key first, using either contains() or indexOf().
235  || #
236  ||
237  || @parameter key the key to get the value for
238  ||
239  || @return The const value for key
240  */
241  const V& operator[](const K& key) const
242  {
243  // Don't create non-existent values
244  auto i = indexOf(key);
245  return (i >= 0) ? *values[i] : nil;
246  }
247 
248  /*
249  || @description
250  || | An indexer for accessing and assigning a value to a key
251  || | If a key is used that exists, it returns the value for that key
252  || | If there exists no value for that key, the key is added
253  || #
254  ||
255  || @parameter key the key to get the value for
256  ||
257  || @return The value for key
258  */
259  V& operator[](const K& key);
260 
261  void allocate(unsigned int newSize);
262 
263  /*
264  || @description
265  || | Get the index of a key
266  || #
267  ||
268  || @parameter key the key to get the index for
269  ||
270  || @return The index of the key, or -1 if key does not exist
271  */
272  int indexOf(const K& key) const;
273 
274  /*
275  || @description
276  || | Check if a key is contained within this HashMap
277  || #
278  ||
279  || @parameter key the key to check if is contained within this HashMap
280  ||
281  || @return true if it is contained in this HashMap
282  */
283  bool contains(const K& key) const
284  {
285  return indexOf(key) >= 0;
286  }
287 
288  /*
289  || @description
290  || | Remove entry at given index
291  || #
292  ||
293  || @parameter index location to remove from this HashMap
294  */
295  void removeAt(unsigned index);
296 
297  /*
298  || @description
299  || | Remove a key from this HashMap
300  || #
301  ||
302  || @parameter key the key to remove from this HashMap
303  */
304  void remove(const K& key)
305  {
306  int index = indexOf(key);
307  if(index >= 0) {
308  removeAt(index);
309  }
310  }
311 
312  void clear();
313 
314  void setMultiple(const HashMap<K, V>& map);
315 
316  void setNullValue(const V& nullv)
317  {
318  nil = nullv;
319  }
320 
321  Iterator<false> begin()
322  {
323  return Iterator<false>(*this, 0);
324  }
325 
326  Iterator<false> end()
327  {
328  return Iterator<false>(*this, count());
329  }
330 
331  Iterator<true> begin() const
332  {
333  return Iterator<true>(*this, 0);
334  }
335 
336  Iterator<true> end() const
337  {
338  return Iterator<true>(*this, count());
339  }
340 
341 protected:
342  K** keys = nullptr;
343  V** values = nullptr;
344  V nil;
348 
349 private:
350  HashMap(const HashMap<K, V>& that);
351 };
352 
353 template <typename K, typename V> V& HashMap<K, V>::operator[](const K& key)
354 {
355  int i = indexOf(key);
356  if(i >= 0) {
357  return *values[i];
358  }
359  if(currentIndex >= size) {
360  allocate(currentIndex + 1);
361  }
362  *keys[currentIndex] = key;
363  *values[currentIndex] = nil;
364  currentIndex++;
365  return *values[currentIndex - 1];
366 }
367 
368 template <typename K, typename V> void HashMap<K, V>::allocate(unsigned int newSize)
369 {
370  if(newSize <= size)
371  return;
372 
373  K** nkeys = new K*[newSize];
374  V** nvalues = new V*[newSize];
375 
376  if(keys != nullptr) {
377  for(unsigned i = 0; i < size; i++) {
378  nkeys[i] = keys[i];
379  nvalues[i] = values[i];
380  }
381 
382  delete[] keys;
383  delete[] values;
384  }
385  for(unsigned i = size; i < newSize; i++) {
386  nkeys[i] = new K();
387  nvalues[i] = new V();
388  }
389 
390  keys = nkeys;
391  values = nvalues;
392  size = newSize;
393 }
394 
395 template <typename K, typename V> int HashMap<K, V>::indexOf(const K& key) const
396 {
397  for(unsigned i = 0; i < currentIndex; i++) {
398  if(cb_comparator) {
399  if(cb_comparator(key, *keys[i])) {
400  return i;
401  }
402  } else {
403  if(key == *keys[i]) {
404  return i;
405  }
406  }
407  }
408  return -1;
409 }
410 
411 template <typename K, typename V> void HashMap<K, V>::removeAt(unsigned index)
412 {
413  if(index >= currentIndex)
414  return;
415 
416  for(unsigned i = index + 1; i < size; i++) {
417  *keys[i - 1] = *keys[i];
418  *values[i - 1] = *values[i];
419  }
420 
421  currentIndex--;
422 }
423 
424 template <typename K, typename V> void HashMap<K, V>::clear()
425 {
426  if(keys != nullptr) {
427  for(unsigned i = 0; i < size; i++) {
428  delete keys[i];
429  delete values[i];
430  }
431  delete[] keys;
432  delete[] values;
433  keys = nullptr;
434  values = nullptr;
435  }
436  currentIndex = 0;
437  size = 0;
438 }
439 
440 template <typename K, typename V> void HashMap<K, V>::setMultiple(const HashMap<K, V>& map)
441 {
442  for(unsigned i = 0; i < map.count(); i++) {
443  (*this)[map.keyAt(i)] = *(map.values)[i];
444  }
445 }
Iterator(Map &map, unsigned index)
Definition: WHashMap.h:89
bool operator==(const Iterator &rhs) const
Definition: WHashMap.h:113
void allocate(unsigned int newSize)
Definition: WHashMap.h:368
const V & operator[](const K &key) const
Definition: WHashMap.h:241
Iterator< true > end() const
Definition: WHashMap.h:336
HashMap class template.
Definition: WHashMap.h:38
typename std::conditional< is_const, const HashMap, HashMap >::type Map
Definition: WHashMap.h:84
BaseElement< false > Element
Definition: WHashMap.h:77
void clear()
Definition: WHashMap.h:424
const K & keyAt(unsigned int idx) const
Definition: WHashMap.h:184
ElementConst operator*() const
Definition: WHashMap.h:128
Iterator & operator++()
Definition: WHashMap.h:93
long map(long, long, long, long, long)
BaseElement(const K &key, Value &value)
Definition: WHashMap.h:47
Iterator< true > begin() const
Definition: WHashMap.h:331
const V & valueAt(unsigned int idx) const
Definition: WHashMap.h:209
Iterator< false > end()
Definition: WHashMap.h:326
Value & value()
Definition: WHashMap.h:56
Iterator< false > begin()
Definition: WHashMap.h:321
const V & value() const
Definition: WHashMap.h:61
~HashMap()
Definition: WHashMap.h:158
Comparator cb_comparator
Definition: WHashMap.h:347
void setNullValue(const V &nullv)
Definition: WHashMap.h:316
Iterator operator+=(size_t distance)
Definition: WHashMap.h:106
const K & key() const
Definition: WHashMap.h:51
uint16_t size
Definition: WHashMap.h:346
typename std::conditional< is_const, const V, V >::type Value
Definition: WHashMap.h:85
V nil
Definition: WHashMap.h:344
uint16_t currentIndex
Definition: WHashMap.h:345
BaseElement & operator=(const V &value)
Definition: WHashMap.h:66
K & keyAt(unsigned int idx)
Definition: WHashMap.h:192
Definition: WHashMap.h:43
void setMultiple(const HashMap< K, V > &map)
Definition: WHashMap.h:440
Iterator operator++(int)
Definition: WHashMap.h:99
typename std::conditional< is_const, const V, V >::type Value
Definition: WHashMap.h:45
K ** keys
Definition: WHashMap.h:342
BaseElement< is_const > operator*()
Definition: WHashMap.h:123
bool operator!=(const Iterator &rhs) const
Definition: WHashMap.h:118
V & valueAt(unsigned int idx)
Definition: WHashMap.h:217
HashMap()
Definition: WHashMap.h:143
Definition: WHashMap.h:81
int indexOf(const K &key) const
Definition: WHashMap.h:395
BaseElement< true > ElementConst
Definition: WHashMap.h:78
V ** values
Definition: WHashMap.h:343
bool contains(const K &key) const
Definition: WHashMap.h:283
void removeAt(unsigned index)
Definition: WHashMap.h:411
HashMap(Comparator compare)
Definition: WHashMap.h:154
bool(*)(const mqtt_type_t &, const mqtt_type_t &) Comparator
Definition: WHashMap.h:41
unsigned int count() const
Definition: WHashMap.h:170