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