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 #include <cstdlib>
34 #include "WiringList.h"
35 #include "Print.h"
36 
41 template <typename K, typename V> class HashMap
42 {
43 public:
44  template <bool is_const> struct BaseElement {
45  public:
46  using Value = typename std::conditional<is_const, const V, V>::type;
47 
48  BaseElement(const K& key, Value& value) : k(key), v(value)
49  {
50  }
51 
52  const K& key() const
53  {
54  return k;
55  }
56 
58  {
59  return v;
60  }
61 
62  const V& value() const
63  {
64  return v;
65  }
66 
68  {
69  v = value;
70  return *this;
71  }
72 
74  {
75  return v;
76  }
77 
78  const Value& operator*() const
79  {
80  return v;
81  }
82 
84  {
85  return &v;
86  }
87 
88  const Value* operator->() const
89  {
90  return &v;
91  }
92 
93  size_t printTo(Print& p) const
94  {
95  size_t n{0};
96  n += p.print(k);
97  n += p.print(" = ");
98  n += p.print(v);
99  return n;
100  }
101 
102  private:
103  const K& k;
104  Value& v;
105  };
106 
109 
110  template <bool is_const> class Iterator
111  {
112  public:
113  using iterator_category = std::random_access_iterator_tag;
115  using difference_type = std::ptrdiff_t;
118 
119  using Map = typename std::conditional<is_const, const HashMap, HashMap>::type;
120  using Value = typename std::conditional<is_const, const V, V>::type;
121 
122  Iterator(const Iterator&) = default;
123 
124  Iterator(Map& map, unsigned index) : map(map), index(index)
125  {
126  }
127 
129  {
130  ++index;
131  return *this;
132  }
133 
135  {
136  Iterator tmp(*this);
137  ++index;
138  return tmp;
139  }
140 
141  Iterator operator+=(size_t distance)
142  {
143  Iterator tmp(*this);
144  index += distance;
145  return tmp;
146  }
147 
148  bool operator==(const Iterator& rhs) const
149  {
150  return &map == &rhs.map && index == rhs.index;
151  }
152 
153  bool operator!=(const Iterator& rhs) const
154  {
155  return !operator==(rhs);
156  }
157 
159  {
160  return BaseElement<is_const>{map.keyAt(index), map.valueAt(index)};
161  }
162 
164  {
165  return ElementConst{map.keyAt(index), map.valueAt(index)};
166  }
167 
168  protected:
170  unsigned index{0};
171  };
172 
176  using Comparator = bool (*)(const K&, const K&);
177 
181  using SortCompare = bool (*)(const ElementConst& e1, const ElementConst& e2);
182 
183  /*
184  || @constructor
185  || | Default constructor
186  || #
187  */
189  {
190  }
191 
192  /*
193  || @constructor
194  || | Initialize this HashMap
195  || #
196  ||
197  || @parameter compare optional function for comparing a key against another (for complex types)
198  */
199  HashMap(Comparator compare) : cb_comparator(compare)
200  {
201  }
202 
203  /*
204  || @description
205  || | Get the size of this HashMap
206  || #
207  ||
208  || @return The size of this HashMap
209  */
210  unsigned int count() const
211  {
212  return currentIndex;
213  }
214 
215  /*
216  || @description
217  || | Get a key at a specified index
218  || #
219  ||
220  || @parameter idx the index to get the key at
221  ||
222  || @return The key at index idx
223  */
224  const K& keyAt(unsigned int idx) const
225  {
226  if(idx >= count()) {
227  abort();
228  }
229  return keys[idx];
230  }
231 
232  K& keyAt(unsigned int idx)
233  {
234  if(idx >= count()) {
235  abort();
236  }
237  return keys[idx];
238  }
239 
240  /*
241  || @description
242  || | Get a value at a specified index
243  || #
244  ||
245  || @parameter idx the index to get the value at
246  ||
247  || @return The value at index idx
248  */
249  const V& valueAt(unsigned int idx) const
250  {
251  if(idx >= count()) {
252  abort();
253  }
254  return values[idx];
255  }
256 
257  V& valueAt(unsigned int idx)
258  {
259  if(idx >= count()) {
260  abort();
261  }
262  return values[idx];
263  }
264 
265  /*
266  || @description
267  || | An indexer for accessing and assigning a value to a key
268  || | If a key is used that exists, it returns the value for that key
269  || | If there exists no value for that key, a nil value is returned
270  || |
271  || | Note that if the HashMap object is not const, the non-const version
272  || | of this operator will be called which will create a default value
273  || | for this key. If that behaviour is not desired, then check for the
274  || | existence of the key first, using either contains() or indexOf().
275  || #
276  ||
277  || @parameter key the key to get the value for
278  ||
279  || @return The const value for key
280  */
281  const V& operator[](const K& key) const
282  {
283  // Don't create non-existent values
284  auto i = indexOf(key);
285  return (i >= 0) ? values[i] : nil;
286  }
287 
288  /*
289  || @description
290  || | An indexer for accessing and assigning a value to a key
291  || | If a key is used that exists, it returns the value for that key
292  || | If there exists no value for that key, the key is added
293  || #
294  ||
295  || @parameter key the key to get the value for
296  ||
297  || @return The value for key
298  */
299  V& operator[](const K& key);
300 
301  bool allocate(unsigned int newSize)
302  {
303  return keys.allocate(newSize) && values.allocate(newSize);
304  }
305 
309  void sort(SortCompare compare);
310 
311  /*
312  || @description
313  || | Get the index of a key
314  || #
315  ||
316  || @parameter key the key to get the index for
317  ||
318  || @return The index of the key, or -1 if key does not exist
319  */
320  int indexOf(const K& key) const
321  {
322  for(unsigned i = 0; i < currentIndex; i++) {
323  if(cb_comparator) {
324  if(cb_comparator(key, keys[i])) {
325  return i;
326  }
327  } else if(key == keys[i]) {
328  return i;
329  }
330  }
331  return -1;
332  }
333 
334  /*
335  || @description
336  || | Check if a key is contained within this HashMap
337  || #
338  ||
339  || @parameter key the key to check if is contained within this HashMap
340  ||
341  || @return true if it is contained in this HashMap
342  */
343  bool contains(const K& key) const
344  {
345  return indexOf(key) >= 0;
346  }
347 
348  /*
349  || @description
350  || | Remove entry at given index
351  || #
352  ||
353  || @parameter index location to remove from this HashMap
354  */
355  void removeAt(unsigned index)
356  {
357  if(index >= currentIndex) {
358  return;
359  }
360 
361  keys.remove(index);
362  values.remove(index);
363 
364  currentIndex--;
365  }
366 
367  /*
368  || @description
369  || | Remove a key from this HashMap
370  || #
371  ||
372  || @parameter key the key to remove from this HashMap
373  */
374  void remove(const K& key)
375  {
376  int index = indexOf(key);
377  if(index >= 0) {
378  removeAt(index);
379  }
380  }
381 
382  void clear()
383  {
384  keys.clear();
385  values.clear();
386  currentIndex = 0;
387  }
388 
390  {
391  for(auto e : map) {
392  (*this)[e.key()] = e.value();
393  }
394  }
395 
396  void setNullValue(const V& nullv)
397  {
398  nil = nullv;
399  }
400 
402  {
403  return Iterator<false>(*this, 0);
404  }
405 
407  {
408  return Iterator<false>(*this, count());
409  }
410 
412  {
413  return Iterator<true>(*this, 0);
414  }
415 
417  {
418  return Iterator<true>(*this, count());
419  }
420 
421 protected:
424 
428  unsigned currentIndex{0};
429  V nil{};
430 
431 private:
432  HashMap(const HashMap<K, V>& that);
433  HashMap& operator=(const HashMap& that);
434 };
435 
436 template <typename K, typename V> V& HashMap<K, V>::operator[](const K& key)
437 {
438  int i = indexOf(key);
439  if(i >= 0) {
440  return values[i];
441  }
442  if(currentIndex >= values.size) {
443  allocate(currentIndex + ((values.size < 16) ? 4 : 16));
444  }
445  keys[currentIndex] = key;
446  values[currentIndex] = nil;
447  currentIndex++;
448  return values[currentIndex - 1];
449 }
450 
451 template <typename K, typename V> void HashMap<K, V>::sort(SortCompare compare)
452 {
453  auto n = count();
454  for(unsigned i = 0; i < n - 1; ++i) {
455  for(unsigned j = 0; j < n - i - 1; ++j) {
456  HashMap::ElementConst e1{keys[j + 1], values[j + 1]};
457  HashMap::ElementConst e2{keys[j], values[j]};
458  if(compare(e1, e2)) {
459  std::swap(keys[j], keys[j + 1]);
460  std::swap(values[j], values[j + 1]);
461  }
462  }
463  }
464 }
long map(long, long, long, long, long)
void size_t const void * key
Definition: blake2s.h:33
Definition: WHashMap.h:111
std::random_access_iterator_tag iterator_category
Definition: WHashMap.h:113
ElementConst operator*() const
Definition: WHashMap.h:163
unsigned index
Definition: WHashMap.h:170
Iterator & operator++()
Definition: WHashMap.h:128
BaseElement< is_const > operator*()
Definition: WHashMap.h:158
std::ptrdiff_t difference_type
Definition: WHashMap.h:115
Iterator(Map &map, unsigned index)
Definition: WHashMap.h:124
bool operator==(const Iterator &rhs) const
Definition: WHashMap.h:148
Iterator operator++(int)
Definition: WHashMap.h:134
Iterator operator+=(size_t distance)
Definition: WHashMap.h:141
bool operator!=(const Iterator &rhs) const
Definition: WHashMap.h:153
Map & map
Definition: WHashMap.h:169
Iterator(const Iterator &)=default
typename std::conditional< is_const, const V, V >::type Value
Definition: WHashMap.h:120
typename std::conditional< is_const, const HashMap, HashMap >::type Map
Definition: WHashMap.h:119
HashMap class template.
Definition: WHashMap.h:42
Iterator< true > begin() const
Definition: WHashMap.h:411
Iterator< false > begin()
Definition: WHashMap.h:401
const V & valueAt(unsigned int idx) const
Definition: WHashMap.h:249
void removeAt(unsigned index)
Definition: WHashMap.h:355
bool contains(const K &key) const
Definition: WHashMap.h:343
const K & keyAt(unsigned int idx) const
Definition: WHashMap.h:224
KeyList keys
Definition: WHashMap.h:425
unsigned int count() const
Definition: WHashMap.h:210
ValueList values
Definition: WHashMap.h:426
const V & operator[](const K &key) const
Definition: WHashMap.h:281
unsigned currentIndex
Definition: WHashMap.h:428
void setNullValue(const V &nullv)
Definition: WHashMap.h:396
Comparator cb_comparator
Definition: WHashMap.h:427
wiring_private::List< V > ValueList
Definition: WHashMap.h:423
void remove(const K &key)
Definition: WHashMap.h:374
void sort(SortCompare compare)
Sort map entries.
Definition: WHashMap.h:451
Iterator< true > end() const
Definition: WHashMap.h:416
wiring_private::List< K > KeyList
Definition: WHashMap.h:422
HashMap()
Definition: WHashMap.h:188
void clear()
Definition: WHashMap.h:382
bool allocate(unsigned int newSize)
Definition: WHashMap.h:301
HashMap(Comparator compare)
Definition: WHashMap.h:199
int indexOf(const K &key) const
Definition: WHashMap.h:320
K & keyAt(unsigned int idx)
Definition: WHashMap.h:232
Iterator< false > end()
Definition: WHashMap.h:406
void setMultiple(const HashMap< K, V > &map)
Definition: WHashMap.h:389
bool(*)(const K &, const K &) Comparator
Compare two keys for equality.
Definition: WHashMap.h:176
bool(*)(const ElementConst &e1, const ElementConst &e2) SortCompare
Return true if key1 < key2.
Definition: WHashMap.h:181
V & valueAt(unsigned int idx)
Definition: WHashMap.h:257
V nil
Definition: WHashMap.h:429
V & operator[](const K &key)
Definition: WHashMap.h:436
Provides formatted output to stream.
Definition: Print.h:37
size_t print(char c)
Prints a single character to output stream.
Definition: Print.h:97
typename std::conditional< std::is_scalar< T >::value, ScalarList< T >, ObjectList< T > >::type List
Definition: WiringList.h:182
Definition: WHashMap.h:44
BaseElement & operator=(const V &value)
Definition: WHashMap.h:67
BaseElement(const K &key, Value &value)
Definition: WHashMap.h:48
const V & value() const
Definition: WHashMap.h:62
Value & value()
Definition: WHashMap.h:57
const K & key() const
Definition: WHashMap.h:52
Value * operator->()
Definition: WHashMap.h:83
typename std::conditional< is_const, const V, V >::type Value
Definition: WHashMap.h:46
const Value * operator->() const
Definition: WHashMap.h:88
size_t printTo(Print &p) const
Definition: WHashMap.h:93
Value & operator*()
Definition: WHashMap.h:73
const Value & operator*() const
Definition: WHashMap.h:78