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  */
188  HashMap() = default;
189 
190  /*
191  || @constructor
192  || | Initialize this HashMap
193  || #
194  ||
195  || @parameter compare optional function for comparing a key against another (for complex types)
196  */
198  {
199  }
200 
201  /*
202  || @description
203  || | Get the size of this HashMap
204  || #
205  ||
206  || @return The size of this HashMap
207  */
208  unsigned int count() const
209  {
210  return currentIndex;
211  }
212 
213  /*
214  || @description
215  || | Get a key at a specified index
216  || #
217  ||
218  || @parameter idx the index to get the key at
219  ||
220  || @return The key at index idx
221  */
222  const K& keyAt(unsigned int idx) const
223  {
224  if(idx >= count()) {
225  abort();
226  }
227  return keys[idx];
228  }
229 
230  K& keyAt(unsigned int idx)
231  {
232  if(idx >= count()) {
233  abort();
234  }
235  return keys[idx];
236  }
237 
238  /*
239  || @description
240  || | Get a value at a specified index
241  || #
242  ||
243  || @parameter idx the index to get the value at
244  ||
245  || @return The value at index idx
246  */
247  const V& valueAt(unsigned int idx) const
248  {
249  if(idx >= count()) {
250  abort();
251  }
252  return values[idx];
253  }
254 
255  V& valueAt(unsigned int idx)
256  {
257  if(idx >= count()) {
258  abort();
259  }
260  return values[idx];
261  }
262 
263  /*
264  || @description
265  || | An indexer for accessing and assigning a value to a key
266  || | If a key is used that exists, it returns the value for that key
267  || | If there exists no value for that key, a nil value is returned
268  || |
269  || | Note that if the HashMap object is not const, the non-const version
270  || | of this operator will be called which will create a default value
271  || | for this key. If that behaviour is not desired, then check for the
272  || | existence of the key first, using either contains() or indexOf().
273  || #
274  ||
275  || @parameter key the key to get the value for
276  ||
277  || @return The const value for key
278  */
279  const V& operator[](const K& key) const
280  {
281  // Don't create non-existent values
282  auto i = indexOf(key);
283  return (i >= 0) ? values[i] : nil;
284  }
285 
286  /*
287  || @description
288  || | An indexer for accessing and assigning a value to a key
289  || | If a key is used that exists, it returns the value for that key
290  || | If there exists no value for that key, the key is added
291  || #
292  ||
293  || @parameter key the key to get the value for
294  ||
295  || @return The value for key
296  */
297  V& operator[](const K& key);
298 
299  bool allocate(unsigned int newSize)
300  {
301  return keys.allocate(newSize) && values.allocate(newSize);
302  }
303 
308 
309  /*
310  || @description
311  || | Get the index of a key
312  || #
313  ||
314  || @parameter key the key to get the index for
315  ||
316  || @return The index of the key, or -1 if key does not exist
317  */
318  int indexOf(const K& key) const
319  {
320  for(unsigned i = 0; i < currentIndex; i++) {
321  if(cb_comparator) {
322  if(cb_comparator(key, keys[i])) {
323  return i;
324  }
325  } else if(key == keys[i]) {
326  return i;
327  }
328  }
329  return -1;
330  }
331 
332  /*
333  || @description
334  || | Check if a key is contained within this HashMap
335  || #
336  ||
337  || @parameter key the key to check if is contained within this HashMap
338  ||
339  || @return true if it is contained in this HashMap
340  */
341  bool contains(const K& key) const
342  {
343  return indexOf(key) >= 0;
344  }
345 
346  /*
347  || @description
348  || | Remove entry at given index
349  || #
350  ||
351  || @parameter index location to remove from this HashMap
352  */
353  void removeAt(unsigned index)
354  {
355  if(index >= currentIndex) {
356  return;
357  }
358 
359  keys.remove(index);
360  values.remove(index);
361 
362  currentIndex--;
363  }
364 
365  /*
366  || @description
367  || | Remove a key from this HashMap
368  || #
369  ||
370  || @parameter key the key to remove from this HashMap
371  */
372  void remove(const K& key)
373  {
374  int index = indexOf(key);
375  if(index >= 0) {
376  removeAt(index);
377  }
378  }
379 
380  void clear()
381  {
382  keys.clear();
383  values.clear();
384  currentIndex = 0;
385  }
386 
388  {
389  for(auto e : map) {
390  (*this)[e.key()] = e.value();
391  }
392  }
393 
394  void setNullValue(const V& nullv)
395  {
396  nil = nullv;
397  }
398 
400  {
401  return Iterator<false>(*this, 0);
402  }
403 
405  {
406  return Iterator<false>(*this, count());
407  }
408 
410  {
411  return Iterator<true>(*this, 0);
412  }
413 
415  {
416  return Iterator<true>(*this, count());
417  }
418 
419 protected:
422 
426  unsigned currentIndex{0};
427  V nil{};
428 
429 private:
430  HashMap(const HashMap<K, V>& that);
431  HashMap& operator=(const HashMap& that);
432 };
433 
434 template <typename K, typename V> V& HashMap<K, V>::operator[](const K& key)
435 {
436  int i = indexOf(key);
437  if(i >= 0) {
438  return values[i];
439  }
440  if(currentIndex >= values.size) {
441  allocate(currentIndex + ((values.size < 16) ? 4 : 16));
442  }
443  keys[currentIndex] = key;
444  values[currentIndex] = nil;
445  currentIndex++;
446  return values[currentIndex - 1];
447 }
448 
449 template <typename K, typename V> void HashMap<K, V>::sort(SortCompare compare)
450 {
451  auto n = count();
452  for(unsigned i = 0; i < n - 1; ++i) {
453  for(unsigned j = 0; j < n - i - 1; ++j) {
454  HashMap::ElementConst e1{keys[j + 1], values[j + 1]};
455  HashMap::ElementConst e2{keys[j], values[j]};
456  if(compare(e1, e2)) {
457  std::swap(keys[j], keys[j + 1]);
458  std::swap(values[j], values[j + 1]);
459  }
460  }
461  }
462 }
CompareResult compare(JsonVariantConst lhs, const FSTR::String &rhs)
Definition: FlashStringRefAdapter.hpp:23
long map(long x, long in_min, long in_max, long out_min, long out_max)
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:409
Iterator< false > begin()
Definition: WHashMap.h:399
const V & valueAt(unsigned int idx) const
Definition: WHashMap.h:247
void removeAt(unsigned index)
Definition: WHashMap.h:353
bool contains(const K &key) const
Definition: WHashMap.h:341
const K & keyAt(unsigned int idx) const
Definition: WHashMap.h:222
KeyList keys
Definition: WHashMap.h:423
unsigned int count() const
Definition: WHashMap.h:208
ValueList values
Definition: WHashMap.h:424
const V & operator[](const K &key) const
Definition: WHashMap.h:279
unsigned currentIndex
Definition: WHashMap.h:426
void setNullValue(const V &nullv)
Definition: WHashMap.h:394
Comparator cb_comparator
Definition: WHashMap.h:425
wiring_private::List< V > ValueList
Definition: WHashMap.h:421
void remove(const K &key)
Definition: WHashMap.h:372
void sort(SortCompare compare)
Sort map entries.
Definition: WHashMap.h:449
Iterator< true > end() const
Definition: WHashMap.h:414
wiring_private::List< K > KeyList
Definition: WHashMap.h:420
void clear()
Definition: WHashMap.h:380
bool allocate(unsigned int newSize)
Definition: WHashMap.h:299
HashMap()=default
HashMap(Comparator compare)
Definition: WHashMap.h:197
int indexOf(const K &key) const
Definition: WHashMap.h:318
K & keyAt(unsigned int idx)
Definition: WHashMap.h:230
Iterator< false > end()
Definition: WHashMap.h:404
void setMultiple(const HashMap< K, V > &map)
Definition: WHashMap.h:387
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:255
V nil
Definition: WHashMap.h:427
V & operator[](const K &key)
Definition: WHashMap.h:434
Provides formatted output to stream.
Definition: Print.h:37
size_t print(char c)
Prints a single character to output stream.
Definition: Print.h:103
typename std::conditional< std::is_scalar< T >::value, ScalarList< T >, ObjectList< T > >::type List
Definition: WiringList.h:197
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