ordered-map
ordered_map.h
Go to the documentation of this file.
1 /**
2  * MIT License
3  *
4  * Copyright (c) 2017 Tessil
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #ifndef TSL_ORDERED_MAP_H
25 #define TSL_ORDERED_MAP_H
26 
27 
28 #include <cstddef>
29 #include <cstdint>
30 #include <deque>
31 #include <functional>
32 #include <initializer_list>
33 #include <memory>
34 #include <type_traits>
35 #include <utility>
36 #include <vector>
37 #include "ordered_hash.h"
38 
39 
40 namespace tsl {
41 
42 
43 /**
44  * Implementation of an hash map using open adressing with robin hood with backshift delete to resolve collisions.
45  *
46  * The particularity of this hash map is that it remembers the order in which the elements were added and
47  * provide a way to access the structure which stores these values through the 'values_container()' method.
48  * The used container is defined by ValueTypeContainer, by default a std::deque is used (grows faster) but
49  * a std::vector may be used. In this case the map provides a 'data()' method which give a direct access
50  * to the memory used to store the values (which can be usefull to communicate with C API's).
51  *
52  * The Key and T must be copy constructible and/or move constructible. To use `unordered_erase` they both
53  * must be swappable.
54  *
55  * The behaviour of the hash map is undefinded if the destructor of Key or T throws an exception.
56  *
57  * By default the maximum size of a map is limited to 2^32 - 1 values, if needed this can be changed through
58  * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each
59  * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values.
60  *
61  * Iterators invalidation:
62  * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()).
63  * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer
64  * and if size() < capacity(), only end().
65  * Otherwise all the iterators are invalidated if an insert occurs.
66  * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of
67  * the erased element and all the ones after the erased element (including end()).
68  * Otherwise all the iterators are invalidated if an erase occurs.
69  */
70 template<class Key,
71  class T,
72  class Hash = std::hash<Key>,
73  class KeyEqual = std::equal_to<Key>,
74  class Allocator = std::allocator<std::pair<Key, T>>,
75  class ValueTypeContainer = std::deque<std::pair<Key, T>, Allocator>,
76  class IndexType = std::uint_least32_t>
77 class ordered_map {
78 private:
79  template<typename U>
80  using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent<U>;
81 
82  class KeySelect {
83  public:
84  using key_type = Key;
85 
86  const key_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
87  return key_value.first;
88  }
89 
90  key_type& operator()(std::pair<Key, T>& key_value) noexcept {
91  return key_value.first;
92  }
93  };
94 
95  class ValueSelect {
96  public:
97  using value_type = T;
98 
99  const value_type& operator()(const std::pair<Key, T>& key_value) const noexcept {
100  return key_value.second;
101  }
102 
103  value_type& operator()(std::pair<Key, T>& key_value) noexcept {
104  return key_value.second;
105  }
106  };
107 
108  using ht = detail_ordered_hash::ordered_hash<std::pair<Key, T>, KeySelect, ValueSelect,
109  Hash, KeyEqual, Allocator, ValueTypeContainer, IndexType>;
110 
111 public:
112  using key_type = typename ht::key_type;
113  using mapped_type = T;
114  using value_type = typename ht::value_type;
115  using size_type = typename ht::size_type;
116  using difference_type = typename ht::difference_type;
117  using hasher = typename ht::hasher;
118  using key_equal = typename ht::key_equal;
119  using allocator_type = typename ht::allocator_type;
120  using reference = typename ht::reference;
121  using const_reference = typename ht::const_reference;
122  using pointer = typename ht::pointer;
123  using const_pointer = typename ht::const_pointer;
124  using iterator = typename ht::iterator;
125  using const_iterator = typename ht::const_iterator;
126  using reverse_iterator = typename ht::reverse_iterator;
127  using const_reverse_iterator = typename ht::const_reverse_iterator;
128 
129  using values_container_type = typename ht::values_container_type;
130 
131 
132  /*
133  * Constructors
134  */
135  ordered_map(): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {
136  }
137 
138  explicit ordered_map(size_type bucket_count,
139  const Hash& hash = Hash(),
140  const KeyEqual& equal = KeyEqual(),
141  const Allocator& alloc = Allocator()):
142  m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
143  {
144  }
145 
146  ordered_map(size_type bucket_count,
147  const Allocator& alloc): ordered_map(bucket_count, Hash(), KeyEqual(), alloc)
148  {
149  }
150 
151  ordered_map(size_type bucket_count,
152  const Hash& hash,
153  const Allocator& alloc): ordered_map(bucket_count, hash, KeyEqual(), alloc)
154  {
155  }
156 
157  explicit ordered_map(const Allocator& alloc): ordered_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
158  }
159 
160  template<class InputIt>
161  ordered_map(InputIt first, InputIt last,
162  size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
163  const Hash& hash = Hash(),
164  const KeyEqual& equal = KeyEqual(),
165  const Allocator& alloc = Allocator()): ordered_map(bucket_count, hash, equal, alloc)
166  {
167  insert(first, last);
168  }
169 
170  template<class InputIt>
171  ordered_map(InputIt first, InputIt last,
172  size_type bucket_count,
173  const Allocator& alloc): ordered_map(first, last, bucket_count, Hash(), KeyEqual(), alloc)
174  {
175  }
176 
177  template<class InputIt>
178  ordered_map(InputIt first, InputIt last,
179  size_type bucket_count,
180  const Hash& hash,
181  const Allocator& alloc): ordered_map(first, last, bucket_count, hash, KeyEqual(), alloc)
182  {
183  }
184 
185  ordered_map(std::initializer_list<value_type> init,
186  size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
187  const Hash& hash = Hash(),
188  const KeyEqual& equal = KeyEqual(),
189  const Allocator& alloc = Allocator()):
190  ordered_map(init.begin(), init.end(), bucket_count, hash, equal, alloc)
191  {
192  }
193 
194  ordered_map(std::initializer_list<value_type> init,
195  size_type bucket_count,
196  const Allocator& alloc):
197  ordered_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
198  {
199  }
200 
201  ordered_map(std::initializer_list<value_type> init,
202  size_type bucket_count,
203  const Hash& hash,
204  const Allocator& alloc):
205  ordered_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
206  {
207  }
208 
209 
210  ordered_map& operator=(std::initializer_list<value_type> ilist) {
211  m_ht.clear();
212 
213  m_ht.reserve(ilist.size());
214  m_ht.insert(ilist.begin(), ilist.end());
215 
216  return *this;
217  }
218 
219  allocator_type get_allocator() const { return m_ht.get_allocator(); }
220 
221 
222 
223  /*
224  * Iterators
225  */
226  iterator begin() noexcept { return m_ht.begin(); }
227  const_iterator begin() const noexcept { return m_ht.begin(); }
228  const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
229 
230  iterator end() noexcept { return m_ht.end(); }
231  const_iterator end() const noexcept { return m_ht.end(); }
232  const_iterator cend() const noexcept { return m_ht.cend(); }
233 
234  reverse_iterator rbegin() noexcept { return m_ht.rbegin(); }
235  const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); }
236  const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); }
237 
238  reverse_iterator rend() noexcept { return m_ht.rend(); }
239  const_reverse_iterator rend() const noexcept { return m_ht.rend(); }
240  const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); }
241 
242 
243  /*
244  * Capacity
245  */
246  bool empty() const noexcept { return m_ht.empty(); }
247  size_type size() const noexcept { return m_ht.size(); }
248  size_type max_size() const noexcept { return m_ht.max_size(); }
249 
250  /*
251  * Modifiers
252  */
253  void clear() noexcept { m_ht.clear(); }
254 
255 
256 
257  std::pair<iterator, bool> insert(const value_type& value) { return m_ht.insert(value); }
258 
259  template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
260  std::pair<iterator, bool> insert(P&& value) { return m_ht.emplace(std::forward<P>(value)); }
261 
262  std::pair<iterator, bool> insert(value_type&& value) { return m_ht.insert(std::move(value)); }
263 
264 
265  iterator insert(const_iterator hint, const value_type& value) {
266  return m_ht.insert_hint(hint, value);
267  }
268 
269  template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
270  iterator insert(const_iterator hint, P&& value) {
271  return m_ht.emplace_hint(hint, std::forward<P>(value));
272  }
273 
274  iterator insert(const_iterator hint, value_type&& value) {
275  return m_ht.insert_hint(hint, std::move(value));
276  }
277 
278 
279  template<class InputIt>
280  void insert(InputIt first, InputIt last) { m_ht.insert(first, last); }
281  void insert(std::initializer_list<value_type> ilist) { m_ht.insert(ilist.begin(), ilist.end()); }
282 
283 
284 
285 
286  template<class M>
287  std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) {
288  return m_ht.insert_or_assign(k, std::forward<M>(obj));
289  }
290 
291  template<class M>
292  std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) {
293  return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj));
294  }
295 
296 
297  template<class M>
298  iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
299  return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
300  }
301 
302  template<class M>
303  iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
304  return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
305  }
306 
307  /**
308  * Due to the way elements are stored, emplace will need to move or copy the key-value once.
309  * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
310  *
311  * Mainly here for compatibility with the std::unordered_map interface.
312  */
313  template<class... Args>
314  std::pair<iterator, bool> emplace(Args&&... args) { return m_ht.emplace(std::forward<Args>(args)...); }
315 
316  /**
317  * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
318  * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
319  *
320  * Mainly here for compatibility with the std::unordered_map interface.
321  */
322  template <class... Args>
323  iterator emplace_hint(const_iterator hint, Args&&... args) {
324  return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
325  }
326 
327 
328 
329 
330  template<class... Args>
331  std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) {
332  return m_ht.try_emplace(k, std::forward<Args>(args)...);
333  }
334 
335  template<class... Args>
336  std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
337  return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
338  }
339 
340  template<class... Args>
341  iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
342  return m_ht.try_emplace_hint(hint, k, std::forward<Args>(args)...);
343  }
344 
345  template<class... Args>
346  iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
347  return m_ht.try_emplace_hint(hint, std::move(k), std::forward<Args>(args)...);
348  }
349 
350 
351 
352 
353  /**
354  * When erasing an element, the insert order will be preserved and no holes will be present in the container
355  * returned by 'values_container()'.
356  *
357  * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1)
358  * average complexity.
359  */
360  iterator erase(iterator pos) { return m_ht.erase(pos); }
361 
362  /**
363  * @copydoc erase(iterator pos)
364  */
365  iterator erase(const_iterator pos) { return m_ht.erase(pos); }
366 
367  /**
368  * @copydoc erase(iterator pos)
369  */
370  iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
371 
372  /**
373  * @copydoc erase(iterator pos)
374  */
375  size_type erase(const key_type& key) { return m_ht.erase(key); }
376 
377  /**
378  * @copydoc erase(iterator pos)
379  *
380  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
381  * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
382  */
383  size_type erase(const key_type& key, std::size_t precalculated_hash) {
384  return m_ht.erase(key, precalculated_hash);
385  }
386 
387  /**
388  * @copydoc erase(iterator pos)
389  *
390  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
391  * If so, K must be hashable and comparable to Key.
392  */
393  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
394  size_type erase(const K& key) { return m_ht.erase(key); }
395 
396  /**
397  * @copydoc erase(const key_type& key, std::size_t precalculated_hash)
398  *
399  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
400  * If so, K must be hashable and comparable to Key.
401  */
402  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
403  size_type erase(const K& key, std::size_t precalculated_hash) {
404  return m_ht.erase(key, precalculated_hash);
405  }
406 
407 
408 
409  void swap(ordered_map& other) { other.m_ht.swap(m_ht); }
410 
411  /*
412  * Lookup
413  */
414  T& at(const Key& key) { return m_ht.at(key); }
415 
416  /**
417  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
418  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
419  */
420  T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
421 
422 
423  const T& at(const Key& key) const { return m_ht.at(key); }
424 
425  /**
426  * @copydoc at(const Key& key, std::size_t precalculated_hash)
427  */
428  const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
429 
430 
431  /**
432  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
433  * If so, K must be hashable and comparable to Key.
434  */
435  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
436  T& at(const K& key) { return m_ht.at(key); }
437 
438  /**
439  * @copydoc at(const K& key)
440  *
441  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
442  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
443  */
444  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
445  T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
446 
447  /**
448  * @copydoc at(const K& key)
449  */
450  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
451  const T& at(const K& key) const { return m_ht.at(key); }
452 
453  /**
454  * @copydoc at(const K& key, std::size_t precalculated_hash)
455  */
456  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
457  const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
458 
459 
460 
461  T& operator[](const Key& key) { return m_ht[key]; }
462  T& operator[](Key&& key) { return m_ht[std::move(key)]; }
463 
464 
465 
466  size_type count(const Key& key) const { return m_ht.count(key); }
467 
468  /**
469  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
470  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
471  */
472  size_type count(const Key& key, std::size_t precalculated_hash) const {
473  return m_ht.count(key, precalculated_hash);
474  }
475 
476  /**
477  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
478  * If so, K must be hashable and comparable to Key.
479  */
480  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
481  size_type count(const K& key) const { return m_ht.count(key); }
482 
483  /**
484  * @copydoc count(const K& key) const
485  *
486  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
487  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
488  */
489  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
490  size_type count(const K& key, std::size_t precalculated_hash) const {
491  return m_ht.count(key, precalculated_hash);
492  }
493 
494 
495 
496  iterator find(const Key& key) { return m_ht.find(key); }
497 
498  /**
499  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
500  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
501  */
502  iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
503 
504  const_iterator find(const Key& key) const { return m_ht.find(key); }
505 
506  /**
507  * @copydoc find(const Key& key, std::size_t precalculated_hash)
508  */
509  const_iterator find(const Key& key, std::size_t precalculated_hash) const {
510  return m_ht.find(key, precalculated_hash);
511  }
512 
513  /**
514  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
515  * If so, K must be hashable and comparable to Key.
516  */
517  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
518  iterator find(const K& key) { return m_ht.find(key); }
519 
520  /**
521  * @copydoc find(const K& key)
522  *
523  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
524  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
525  */
526  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
527  iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
528 
529  /**
530  * @copydoc find(const K& key)
531  */
532  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
533  const_iterator find(const K& key) const { return m_ht.find(key); }
534 
535  /**
536  * @copydoc find(const K& key)
537  *
538  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
539  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
540  */
541  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
542  const_iterator find(const K& key, std::size_t precalculated_hash) const {
543  return m_ht.find(key, precalculated_hash);
544  }
545 
546 
547 
548  std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
549 
550  /**
551  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
552  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
553  */
554  std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) {
555  return m_ht.equal_range(key, precalculated_hash);
556  }
557 
558  std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
559 
560  /**
561  * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
562  */
563  std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const {
564  return m_ht.equal_range(key, precalculated_hash);
565  }
566 
567  /**
568  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
569  * If so, K must be hashable and comparable to Key.
570  */
571  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
572  std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
573 
574  /**
575  * @copydoc equal_range(const K& key)
576  *
577  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
578  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
579  */
580  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
581  std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) {
582  return m_ht.equal_range(key, precalculated_hash);
583  }
584 
585  /**
586  * @copydoc equal_range(const K& key)
587  */
588  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
589  std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
590 
591  /**
592  * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
593  */
594  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
595  std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const {
596  return m_ht.equal_range(key, precalculated_hash);
597  }
598 
599 
600 
601  /*
602  * Bucket interface
603  */
604  size_type bucket_count() const { return m_ht.bucket_count(); }
605  size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
606 
607 
608  /*
609  * Hash policy
610  */
611  float load_factor() const { return m_ht.load_factor(); }
612  float max_load_factor() const { return m_ht.max_load_factor(); }
613  void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
614 
615  void rehash(size_type count) { m_ht.rehash(count); }
616  void reserve(size_type count) { m_ht.reserve(count); }
617 
618 
619  /*
620  * Observers
621  */
622  hasher hash_function() const { return m_ht.hash_function(); }
623  key_equal key_eq() const { return m_ht.key_eq(); }
624 
625 
626 
627  /*
628  * Other
629  */
630 
631  /**
632  * Convert a const_iterator to an iterator.
633  */
634  iterator mutable_iterator(const_iterator pos) {
635  return m_ht.mutable_iterator(pos);
636  }
637 
638  /**
639  * Requires index <= size().
640  *
641  * Return an iterator to the element at index. Return end() if index == size().
642  */
643  iterator nth(size_type index) { return m_ht.nth(index); }
644 
645  /**
646  * @copydoc nth(size_type index)
647  */
648  const_iterator nth(size_type index) const { return m_ht.nth(index); }
649 
650 
651  /**
652  * Return const_reference to the first element. Requires the container to not be empty.
653  */
654  const_reference front() const { return m_ht.front(); }
655 
656  /**
657  * Return const_reference to the last element. Requires the container to not be empty.
658  */
659  const_reference back() const { return m_ht.back(); }
660 
661 
662  /**
663  * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'.
664  */
665  template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>
666  const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); }
667 
668  /**
669  * Return the container in which the values are stored. The values are in the same order as the insertion order
670  * and are contiguous in the structure, no holes (size() == values_container().size()).
671  */
672  const values_container_type& values_container() const noexcept { return m_ht.values_container(); }
673 
674  template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>
675  size_type capacity() const noexcept { return m_ht.capacity(); }
676 
677  void shrink_to_fit() { m_ht.shrink_to_fit(); }
678 
679 
680 
681  /**
682  * Insert the value before pos shifting all the elements on the right of pos (including pos) one position
683  * to the right.
684  *
685  * Amortized linear time-complexity in the distance between pos and end().
686  */
687  std::pair<iterator, bool> insert_at_position(const_iterator pos, const value_type& value) {
688  return m_ht.insert_at_position(pos, value);
689  }
690 
691  /**
692  * @copydoc insert_at_position(const_iterator pos, const value_type& value)
693  */
694  std::pair<iterator, bool> insert_at_position(const_iterator pos, value_type&& value) {
695  return m_ht.insert_at_position(pos, std::move(value));
696  }
697 
698  /**
699  * @copydoc insert_at_position(const_iterator pos, const value_type& value)
700  *
701  * Same as insert_at_position(pos, value_type(std::forward<Args>(args)...), mainly
702  * here for coherence.
703  */
704  template<class... Args>
705  std::pair<iterator, bool> emplace_at_position(const_iterator pos, Args&&... args) {
706  return m_ht.emplace_at_position(pos, std::forward<Args>(args)...);
707  }
708 
709  /**
710  * @copydoc insert_at_position(const_iterator pos, const value_type& value)
711  */
712  template<class... Args>
713  std::pair<iterator, bool> try_emplace_at_position(const_iterator pos, const key_type& k, Args&&... args) {
714  return m_ht.try_emplace_at_position(pos, k, std::forward<Args>(args)...);
715  }
716 
717  /**
718  * @copydoc insert_at_position(const_iterator pos, const value_type& value)
719  */
720  template<class... Args>
721  std::pair<iterator, bool> try_emplace_at_position(const_iterator pos, key_type&& k, Args&&... args) {
722  return m_ht.try_emplace_at_position(pos, std::move(k), std::forward<Args>(args)...);
723  }
724 
725 
726 
727  void pop_back() { m_ht.pop_back(); }
728 
729  /**
730  * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order.
731  *
732  * If an erasure occurs, the last element of the map will take the place of the erased element.
733  */
734  iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); }
735 
736  /**
737  * @copydoc unordered_erase(iterator pos)
738  */
739  iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); }
740 
741  /**
742  * @copydoc unordered_erase(iterator pos)
743  */
744  size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); }
745 
746  /**
747  * @copydoc unordered_erase(iterator pos)
748  *
749  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
750  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
751  */
752  size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) {
753  return m_ht.unordered_erase(key, precalculated_hash);
754  }
755 
756  /**
757  * @copydoc unordered_erase(iterator pos)
758  *
759  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
760  * If so, K must be hashable and comparable to Key.
761  */
762  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
763  size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); }
764 
765  /**
766  * @copydoc unordered_erase(const K& key)
767  *
768  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
769  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
770  */
771  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
772  size_type unordered_erase(const K& key, std::size_t precalculated_hash) {
773  return m_ht.unordered_erase(key, precalculated_hash);
774  }
775 
776  /**
777  * Serialize the map through the `serializer` parameter.
778  *
779  * The `serializer` parameter must be a function object that supports the following call:
780  * - `template<typename U> void operator()(const U& value);` where the types `std::uint64_t`, `float` and `std::pair<Key, T>` must be supported for U.
781  *
782  * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
783  * in the hands of the `Serializer` function object if compatibilty is required.
784  */
785  template<class Serializer>
786  void serialize(Serializer& serializer) const {
787  m_ht.serialize(serializer);
788  }
789 
790  /**
791  * Deserialize a previouly serialized map through the `deserializer` parameter.
792  *
793  * The `deserializer` parameter must be a function object that supports the following calls:
794  * - `template<typename U> U operator()();` where the types `std::uint64_t`, `float` and `std::pair<Key, T>` must be supported for U.
795  *
796  * If the deserialized hash map type is hash compatible with the serialized map, the deserialization process can be
797  * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way
798  * than the ones used on the serialized map. The `std::size_t` must also be of the same size as the one on the platform used
799  * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with
800  * `hash_compatible` sets to true.
801  *
802  * The behaviour is undefined if the type `Key` and `T` of the `ordered_map` are not the same as the
803  * types used during serialization.
804  *
805  * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it
806  * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
807  */
808  template<class Deserializer>
809  static ordered_map deserialize(Deserializer& deserializer, bool hash_compatible = false) {
810  ordered_map map(0);
811  map.m_ht.deserialize(deserializer, hash_compatible);
812 
813  return map;
814  }
815 
816 
817 
818  friend bool operator==(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht == rhs.m_ht; }
819  friend bool operator!=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht != rhs.m_ht; }
820  friend bool operator<(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht < rhs.m_ht; }
821  friend bool operator<=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht <= rhs.m_ht; }
822  friend bool operator>(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht > rhs.m_ht; }
823  friend bool operator>=(const ordered_map& lhs, const ordered_map& rhs) { return lhs.m_ht >= rhs.m_ht; }
824 
825  friend void swap(ordered_map& lhs, ordered_map& rhs) { lhs.swap(rhs); }
826 
827 private:
828  ht m_ht;
829 };
830 
831 } // end namespace tsl
832 
833 #endif
std::pair< const_iterator, const_iterator > equal_range(const Key &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:563
size_type unordered_erase(const key_type &key, std::size_t precalculated_hash)
Definition: ordered_map.h:752
iterator find(const Key &key, std::size_t precalculated_hash)
Definition: ordered_map.h:502
size_type unordered_erase(const K &key, std::size_t precalculated_hash)
Definition: ordered_map.h:772
const_iterator nth(size_type index) const
Definition: ordered_map.h:648
size_type unordered_erase(const K &key)
Definition: ordered_map.h:763
ordered_map(InputIt first, InputIt last, size_type bucket_count, const Allocator &alloc)
Definition: ordered_map.h:171
void reserve(size_type count)
Definition: ordered_map.h:616
friend bool operator>(const ordered_map &lhs, const ordered_map &rhs)
Definition: ordered_map.h:822
const_reverse_iterator rend() const noexcept
Definition: ordered_map.h:239
Definition: ordered_hash.h:279
iterator insert(const_iterator hint, P &&value)
Definition: ordered_map.h:270
const_reverse_iterator rcbegin() const noexcept
Definition: ordered_map.h:236
ordered_map & operator=(std::initializer_list< value_type > ilist)
Definition: ordered_map.h:210
T & at(const K &key, std::size_t precalculated_hash)
Definition: ordered_map.h:445
size_type count(const Key &key) const
Definition: ordered_map.h:466
const T & at(const K &key) const
Definition: ordered_map.h:451
T & operator[](const Key &key)
Definition: ordered_map.h:461
void rehash(size_type count)
Definition: ordered_map.h:615
const_iterator find(const Key &key) const
Definition: ordered_map.h:504
friend bool operator==(const ordered_map &lhs, const ordered_map &rhs)
Definition: ordered_map.h:818
Definition: ordered_hash.h:82
Definition: ordered_hash.h:80
iterator end() noexcept
Definition: ordered_map.h:230
iterator erase(iterator pos)
Definition: ordered_map.h:360
iterator insert(const_iterator hint, value_type &&value)
Definition: ordered_map.h:274
size_type count(const Key &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:472
std::pair< iterator, iterator > equal_range(const K &key, std::size_t precalculated_hash)
Definition: ordered_map.h:581
iterator begin() noexcept
Definition: ordered_map.h:226
ordered_map(std::initializer_list< value_type > init, size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: ordered_map.h:201
size_type max_size() const noexcept
Definition: ordered_map.h:248
const values_container_type::value_type * data() const noexcept
Definition: ordered_map.h:666
void shrink_to_fit()
Definition: ordered_map.h:677
const values_container_type & values_container() const noexcept
Definition: ordered_map.h:672
size_type unordered_erase(const key_type &key)
Definition: ordered_map.h:744
size_type size() const noexcept
Definition: ordered_map.h:247
const_iterator end() const noexcept
Definition: ordered_map.h:231
iterator insert_or_assign(const_iterator hint, key_type &&k, M &&obj)
Definition: ordered_map.h:303
iterator erase(const_iterator pos)
Definition: ordered_map.h:365
ordered_map(std::initializer_list< value_type > init, size_type bucket_count=ht::DEFAULT_INIT_BUCKETS_SIZE, const Hash &hash=Hash(), const KeyEqual &equal=KeyEqual(), const Allocator &alloc=Allocator())
Definition: ordered_map.h:185
reverse_iterator rend() noexcept
Definition: ordered_map.h:238
std::pair< iterator, iterator > equal_range(const Key &key)
Definition: ordered_map.h:548
const_reference front() const
Definition: ordered_map.h:654
std::pair< iterator, bool > insert(value_type &&value)
Definition: ordered_map.h:262
iterator find(const Key &key)
Definition: ordered_map.h:496
iterator unordered_erase(const_iterator pos)
Definition: ordered_map.h:739
iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args)
Definition: ordered_map.h:346
const T & at(const K &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:457
std::pair< iterator, iterator > equal_range(const K &key)
Definition: ordered_map.h:572
std::pair< iterator, bool > emplace_at_position(const_iterator pos, Args &&... args)
Definition: ordered_map.h:705
std::pair< iterator, bool > try_emplace(key_type &&k, Args &&... args)
Definition: ordered_map.h:336
const_reference back() const
Definition: ordered_map.h:659
size_type erase(const K &key, std::size_t precalculated_hash)
Definition: ordered_map.h:403
const_iterator find(const K &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:542
friend bool operator>=(const ordered_map &lhs, const ordered_map &rhs)
Definition: ordered_map.h:823
ordered_map(size_type bucket_count, const Allocator &alloc)
Definition: ordered_map.h:146
void max_load_factor(float ml)
Definition: ordered_map.h:613
iterator mutable_iterator(const_iterator pos)
Definition: ordered_map.h:634
T & at(const K &key)
Definition: ordered_map.h:436
iterator find(const K &key, std::size_t precalculated_hash)
Definition: ordered_map.h:527
key_equal key_eq() const
Definition: ordered_map.h:623
size_type erase(const key_type &key)
Definition: ordered_map.h:375
ordered_map(size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: ordered_map.h:151
iterator emplace_hint(const_iterator hint, Args &&... args)
Definition: ordered_map.h:323
reverse_iterator rbegin() noexcept
Definition: ordered_map.h:234
const T & at(const Key &key) const
Definition: ordered_map.h:423
bool empty() const noexcept
Definition: ordered_map.h:246
size_type erase(const key_type &key, std::size_t precalculated_hash)
Definition: ordered_map.h:383
friend bool operator<=(const ordered_map &lhs, const ordered_map &rhs)
Definition: ordered_map.h:821
void pop_back()
Definition: ordered_map.h:727
const_reverse_iterator rcend() const noexcept
Definition: ordered_map.h:240
iterator insert_or_assign(const_iterator hint, const key_type &k, M &&obj)
Definition: ordered_map.h:298
iterator find(const K &key)
Definition: ordered_map.h:518
const_iterator find(const K &key) const
Definition: ordered_map.h:533
std::pair< iterator, bool > insert_at_position(const_iterator pos, value_type &&value)
Definition: ordered_map.h:694
std::pair< iterator, bool > insert(P &&value)
Definition: ordered_map.h:260
size_type count(const K &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:490
allocator_type get_allocator() const
Definition: ordered_map.h:219
void serialize(Serializer &serializer) const
Definition: ordered_map.h:786
ordered_map(InputIt first, InputIt last, size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: ordered_map.h:178
ordered_map(size_type bucket_count, const Hash &hash=Hash(), const KeyEqual &equal=KeyEqual(), const Allocator &alloc=Allocator())
Definition: ordered_map.h:138
std::pair< iterator, bool > insert_or_assign(key_type &&k, M &&obj)
Definition: ordered_map.h:292
size_type count(const K &key) const
Definition: ordered_map.h:481
void clear() noexcept
Definition: ordered_map.h:253
void insert(std::initializer_list< value_type > ilist)
Definition: ordered_map.h:281
std::pair< iterator, bool > try_emplace_at_position(const_iterator pos, key_type &&k, Args &&... args)
Definition: ordered_map.h:721
static ordered_map deserialize(Deserializer &deserializer, bool hash_compatible=false)
Definition: ordered_map.h:809
std::pair< const_iterator, const_iterator > equal_range(const K &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:595
std::pair< iterator, bool > insert_at_position(const_iterator pos, const value_type &value)
Definition: ordered_map.h:687
iterator try_emplace(const_iterator hint, const key_type &k, Args &&... args)
Definition: ordered_map.h:341
T & at(const Key &key)
Definition: ordered_map.h:414
T & operator[](Key &&key)
Definition: ordered_map.h:462
std::pair< const_iterator, const_iterator > equal_range(const K &key) const
Definition: ordered_map.h:589
std::pair< iterator, bool > insert(const value_type &value)
Definition: ordered_map.h:257
friend void swap(ordered_map &lhs, ordered_map &rhs)
Definition: ordered_map.h:825
const_iterator find(const Key &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:509
std::pair< iterator, bool > insert_or_assign(const key_type &k, M &&obj)
Definition: ordered_map.h:287
friend bool operator<(const ordered_map &lhs, const ordered_map &rhs)
Definition: ordered_map.h:820
Definition: ordered_map.h:77
std::pair< iterator, bool > emplace(Args &&... args)
Definition: ordered_map.h:314
friend bool operator!=(const ordered_map &lhs, const ordered_map &rhs)
Definition: ordered_map.h:819
void swap(ordered_map &other)
Definition: ordered_map.h:409
size_type bucket_count() const
Definition: ordered_map.h:604
std::pair< const_iterator, const_iterator > equal_range(const Key &key) const
Definition: ordered_map.h:558
std::pair< iterator, iterator > equal_range(const Key &key, std::size_t precalculated_hash)
Definition: ordered_map.h:554
ordered_map(const Allocator &alloc)
Definition: ordered_map.h:157
std::pair< iterator, bool > try_emplace_at_position(const_iterator pos, const key_type &k, Args &&... args)
Definition: ordered_map.h:713
const_iterator cbegin() const noexcept
Definition: ordered_map.h:228
iterator unordered_erase(iterator pos)
Definition: ordered_map.h:734
iterator nth(size_type index)
Definition: ordered_map.h:643
size_type erase(const K &key)
Definition: ordered_map.h:394
const_reverse_iterator rbegin() const noexcept
Definition: ordered_map.h:235
iterator insert(const_iterator hint, const value_type &value)
Definition: ordered_map.h:265
size_type max_bucket_count() const
Definition: ordered_map.h:605
T & at(const Key &key, std::size_t precalculated_hash)
Definition: ordered_map.h:420
const T & at(const Key &key, std::size_t precalculated_hash) const
Definition: ordered_map.h:428
ordered_map()
Definition: ordered_map.h:135
iterator erase(const_iterator first, const_iterator last)
Definition: ordered_map.h:370
ordered_map(std::initializer_list< value_type > init, size_type bucket_count, const Allocator &alloc)
Definition: ordered_map.h:194
size_type capacity() const noexcept
Definition: ordered_map.h:675
const_iterator begin() const noexcept
Definition: ordered_map.h:227
hasher hash_function() const
Definition: ordered_map.h:622
const_iterator cend() const noexcept
Definition: ordered_map.h:232
void insert(InputIt first, InputIt last)
Definition: ordered_map.h:280
ordered_map(InputIt first, InputIt last, size_type bucket_count=ht::DEFAULT_INIT_BUCKETS_SIZE, const Hash &hash=Hash(), const KeyEqual &equal=KeyEqual(), const Allocator &alloc=Allocator())
Definition: ordered_map.h:161
float max_load_factor() const
Definition: ordered_map.h:612
float load_factor() const
Definition: ordered_map.h:611
std::pair< iterator, bool > try_emplace(const key_type &k, Args &&... args)
Definition: ordered_map.h:331