hopscotch-map
hopscotch_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_HOPSCOTCH_MAP_H
25 #define TSL_HOPSCOTCH_MAP_H
26 
27 
28 #include <algorithm>
29 #include <cstddef>
30 #include <functional>
31 #include <initializer_list>
32 #include <list>
33 #include <memory>
34 #include <type_traits>
35 #include <utility>
36 #include "hopscotch_hash.h"
37 
38 
39 namespace tsl {
40 
41 /**
42  * Implementation of a hash map using the hopscotch hashing algorithm.
43  *
44  * The Key and the value T must be either nothrow move-constructible, copy-constuctible or both.
45  *
46  * The size of the neighborhood (NeighborhoodSize) must be > 0 and <= 62 if StoreHash is false.
47  * When StoreHash is true, 32-bits of the hash will be stored alongside the neighborhood limiting
48  * the NeighborhoodSize to <= 30. There is no memory usage difference between
49  * 'NeighborhoodSize 62; StoreHash false' and 'NeighborhoodSize 30; StoreHash true'.
50  *
51  * Storing the hash may improve performance on insert during the rehash process if the hash takes time
52  * to compute. It may also improve read performance if the KeyEqual function takes time (or incurs a cache-miss).
53  * If used with simple Hash and KeyEqual it may slow things down.
54  *
55  * StoreHash can only be set if the GrowthPolicy is set to tsl::power_of_two_growth_policy.
56  *
57  * GrowthPolicy defines how the map grows and consequently how a hash value is mapped to a bucket.
58  * By default the map uses tsl::power_of_two_growth_policy. This policy keeps the number of buckets
59  * to a power of two and uses a mask to map the hash to a bucket instead of the slow modulo.
60  * You may define your own growth policy, check tsl::power_of_two_growth_policy for the interface.
61  *
62  * If the destructors of Key or T throw an exception, behaviour of the class is undefined.
63  *
64  * Iterators invalidation:
65  * - clear, operator=, reserve, rehash: always invalidate the iterators.
66  * - insert, emplace, emplace_hint, operator[]: if there is an effective insert, invalidate the iterators
67  * if a displacement is needed to resolve a collision (which mean that most of the time,
68  * insert will invalidate the iterators). Or if there is a rehash.
69  * - erase: iterator on the erased element is the only one which become invalid.
70  */
71 template<class Key,
72  class T,
73  class Hash = std::hash<Key>,
74  class KeyEqual = std::equal_to<Key>,
75  class Allocator = std::allocator<std::pair<Key, T>>,
76  unsigned int NeighborhoodSize = 62,
77  bool StoreHash = false,
78  class GrowthPolicy = tsl::hh::power_of_two_growth_policy<2>>
80 private:
81  template<typename U>
82  using has_is_transparent = tsl::detail_hopscotch_hash::has_is_transparent<U>;
83 
84  class KeySelect {
85  public:
86  using key_type = Key;
87 
88  const key_type& operator()(const std::pair<Key, T>& key_value) const {
89  return key_value.first;
90  }
91 
92  key_type& operator()(std::pair<Key, T>& key_value) {
93  return key_value.first;
94  }
95  };
96 
97  class ValueSelect {
98  public:
99  using value_type = T;
100 
101  const value_type& operator()(const std::pair<Key, T>& key_value) const {
102  return key_value.second;
103  }
104 
105  value_type& operator()(std::pair<Key, T>& key_value) {
106  return key_value.second;
107  }
108  };
109 
110 
111  using overflow_container_type = std::list<std::pair<Key, T>, Allocator>;
112  using ht = detail_hopscotch_hash::hopscotch_hash<std::pair<Key, T>, KeySelect, ValueSelect,
113  Hash, KeyEqual,
114  Allocator, NeighborhoodSize,
115  StoreHash, GrowthPolicy,
116  overflow_container_type>;
117 
118 public:
119  using key_type = typename ht::key_type;
120  using mapped_type = T;
121  using value_type = typename ht::value_type;
122  using size_type = typename ht::size_type;
123  using difference_type = typename ht::difference_type;
124  using hasher = typename ht::hasher;
125  using key_equal = typename ht::key_equal;
126  using allocator_type = typename ht::allocator_type;
127  using reference = typename ht::reference;
128  using const_reference = typename ht::const_reference;
129  using pointer = typename ht::pointer;
130  using const_pointer = typename ht::const_pointer;
131  using iterator = typename ht::iterator;
132  using const_iterator = typename ht::const_iterator;
133 
134 
135 
136  /*
137  * Constructors
138  */
139  hopscotch_map() : hopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE) {
140  }
141 
142  explicit hopscotch_map(size_type bucket_count,
143  const Hash& hash = Hash(),
144  const KeyEqual& equal = KeyEqual(),
145  const Allocator& alloc = Allocator()) :
146  m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
147  {
148  }
149 
150  hopscotch_map(size_type bucket_count,
151  const Allocator& alloc) : hopscotch_map(bucket_count, Hash(), KeyEqual(), alloc)
152  {
153  }
154 
155  hopscotch_map(size_type bucket_count,
156  const Hash& hash,
157  const Allocator& alloc) : hopscotch_map(bucket_count, hash, KeyEqual(), alloc)
158  {
159  }
160 
161  explicit hopscotch_map(const Allocator& alloc) : hopscotch_map(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
162  }
163 
164  template<class InputIt>
165  hopscotch_map(InputIt first, InputIt last,
166  size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
167  const Hash& hash = Hash(),
168  const KeyEqual& equal = KeyEqual(),
169  const Allocator& alloc = Allocator()) : hopscotch_map(bucket_count, hash, equal, alloc)
170  {
171  insert(first, last);
172  }
173 
174  template<class InputIt>
175  hopscotch_map(InputIt first, InputIt last,
176  size_type bucket_count,
177  const Allocator& alloc) : hopscotch_map(first, last, bucket_count, Hash(), KeyEqual(), alloc)
178  {
179  }
180 
181  template<class InputIt>
182  hopscotch_map(InputIt first, InputIt last,
183  size_type bucket_count,
184  const Hash& hash,
185  const Allocator& alloc) : hopscotch_map(first, last, bucket_count, hash, KeyEqual(), alloc)
186  {
187  }
188 
189  hopscotch_map(std::initializer_list<value_type> init,
190  size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
191  const Hash& hash = Hash(),
192  const KeyEqual& equal = KeyEqual(),
193  const Allocator& alloc = Allocator()) :
194  hopscotch_map(init.begin(), init.end(), bucket_count, hash, equal, alloc)
195  {
196  }
197 
198  hopscotch_map(std::initializer_list<value_type> init,
199  size_type bucket_count,
200  const Allocator& alloc) :
201  hopscotch_map(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
202  {
203  }
204 
205  hopscotch_map(std::initializer_list<value_type> init,
206  size_type bucket_count,
207  const Hash& hash,
208  const Allocator& alloc) :
209  hopscotch_map(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
210  {
211  }
212 
213 
214  hopscotch_map& operator=(std::initializer_list<value_type> ilist) {
215  m_ht.clear();
216 
217  m_ht.reserve(ilist.size());
218  m_ht.insert(ilist.begin(), ilist.end());
219 
220  return *this;
221  }
222 
223  allocator_type get_allocator() const { return m_ht.get_allocator(); }
224 
225 
226  /*
227  * Iterators
228  */
229  iterator begin() noexcept { return m_ht.begin(); }
230  const_iterator begin() const noexcept { return m_ht.begin(); }
231  const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
232 
233  iterator end() noexcept { return m_ht.end(); }
234  const_iterator end() const noexcept { return m_ht.end(); }
235  const_iterator cend() const noexcept { return m_ht.cend(); }
236 
237 
238  /*
239  * Capacity
240  */
241  bool empty() const noexcept { return m_ht.empty(); }
242  size_type size() const noexcept { return m_ht.size(); }
243  size_type max_size() const noexcept { return m_ht.max_size(); }
244 
245  /*
246  * Modifiers
247  */
248  void clear() noexcept { m_ht.clear(); }
249 
250 
251 
252 
253  std::pair<iterator, bool> insert(const value_type& value) {
254  return m_ht.insert(value);
255  }
256 
257  template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
258  std::pair<iterator, bool> insert(P&& value) {
259  return m_ht.insert(std::forward<P>(value));
260  }
261 
262  std::pair<iterator, bool> insert(value_type&& value) {
263  return m_ht.insert(std::move(value));
264  }
265 
266 
267  iterator insert(const_iterator hint, const value_type& value) {
268  return m_ht.insert(hint, value);
269  }
270 
271  template<class P, typename std::enable_if<std::is_constructible<value_type, P&&>::value>::type* = nullptr>
272  iterator insert(const_iterator hint, P&& value) {
273  return m_ht.insert(hint, std::forward<P>(value));
274  }
275 
276  iterator insert(const_iterator hint, value_type&& value) {
277  return m_ht.insert(hint, std::move(value));
278  }
279 
280 
281  template<class InputIt>
282  void insert(InputIt first, InputIt last) {
283  m_ht.insert(first, last);
284  }
285 
286  void insert(std::initializer_list<value_type> ilist) {
287  m_ht.insert(ilist.begin(), ilist.end());
288  }
289 
290 
291 
292 
293  template<class M>
294  std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj) {
295  return m_ht.insert_or_assign(k, std::forward<M>(obj));
296  }
297 
298  template<class M>
299  std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj) {
300  return m_ht.insert_or_assign(std::move(k), std::forward<M>(obj));
301  }
302 
303  template<class M>
304  iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj) {
305  return m_ht.insert_or_assign(hint, k, std::forward<M>(obj));
306  }
307 
308  template<class M>
309  iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj) {
310  return m_ht.insert_or_assign(hint, std::move(k), std::forward<M>(obj));
311  }
312 
313 
314 
315 
316  /**
317  * Due to the way elements are stored, emplace will need to move or copy the key-value once.
318  * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
319  *
320  * Mainly here for compatibility with the std::unordered_map interface.
321  */
322  template<class... Args>
323  std::pair<iterator, bool> emplace(Args&&... args) {
324  return m_ht.emplace(std::forward<Args>(args)...);
325  }
326 
327 
328 
329 
330  /**
331  * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
332  * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
333  *
334  * Mainly here for compatibility with the std::unordered_map interface.
335  */
336  template<class... Args>
337  iterator emplace_hint(const_iterator hint, Args&&... args) {
338  return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
339  }
340 
341 
342 
343 
344  template<class... Args>
345  std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args) {
346  return m_ht.try_emplace(k, std::forward<Args>(args)...);
347  }
348 
349  template<class... Args>
350  std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args) {
351  return m_ht.try_emplace(std::move(k), std::forward<Args>(args)...);
352  }
353 
354  template<class... Args>
355  iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args) {
356  return m_ht.try_emplace(hint, k, std::forward<Args>(args)...);
357  }
358 
359  template<class... Args>
360  iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args) {
361  return m_ht.try_emplace(hint, std::move(k), std::forward<Args>(args)...);
362  }
363 
364 
365 
366 
367  iterator erase(iterator pos) { return m_ht.erase(pos); }
368  iterator erase(const_iterator pos) { return m_ht.erase(pos); }
369  iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
370  size_type erase(const key_type& key) { return m_ht.erase(key); }
371 
372  /**
373  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
374  * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
375  */
376  size_type erase(const key_type& key, std::size_t precalculated_hash) {
377  return m_ht.erase(key, precalculated_hash);
378  }
379 
380  /**
381  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
382  * If so, K must be hashable and comparable to Key.
383  */
384  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
385  size_type erase(const K& key) { return m_ht.erase(key); }
386 
387  /**
388  * @copydoc erase(const K& key)
389  *
390  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
391  * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
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, std::size_t precalculated_hash) {
395  return m_ht.erase(key, precalculated_hash);
396  }
397 
398 
399 
400 
401  void swap(hopscotch_map& other) { other.m_ht.swap(m_ht); }
402 
403  /*
404  * Lookup
405  */
406  T& at(const Key& key) { return m_ht.at(key); }
407 
408  /**
409  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
410  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
411  */
412  T& at(const Key& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
413 
414 
415  const T& at(const Key& key) const { return m_ht.at(key); }
416 
417  /**
418  * @copydoc at(const Key& key, std::size_t precalculated_hash)
419  */
420  const T& at(const Key& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
421 
422 
423  /**
424  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
425  * If so, K must be hashable and comparable to Key.
426  */
427  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
428  T& at(const K& key) { return m_ht.at(key); }
429 
430  /**
431  * @copydoc at(const K& key)
432  *
433  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
434  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
435  */
436  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
437  T& at(const K& key, std::size_t precalculated_hash) { return m_ht.at(key, precalculated_hash); }
438 
439 
440  /**
441  * @copydoc at(const K& key)
442  */
443  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
444  const T& at(const K& key) const { return m_ht.at(key); }
445 
446  /**
447  * @copydoc at(const K& key, std::size_t precalculated_hash)
448  */
449  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
450  const T& at(const K& key, std::size_t precalculated_hash) const { return m_ht.at(key, precalculated_hash); }
451 
452 
453 
454 
455  T& operator[](const Key& key) { return m_ht[key]; }
456  T& operator[](Key&& key) { return m_ht[std::move(key)]; }
457 
458 
459 
460 
461  size_type count(const Key& key) const { return m_ht.count(key); }
462 
463  /**
464  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
465  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
466  */
467  size_type count(const Key& key, std::size_t precalculated_hash) const {
468  return m_ht.count(key, precalculated_hash);
469  }
470 
471  /**
472  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
473  * If so, K must be hashable and comparable to Key.
474  */
475  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
476  size_type count(const K& key) const { return m_ht.count(key); }
477 
478  /**
479  * @copydoc count(const K& key) const
480  *
481  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
482  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
483  */
484  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
485  size_type count(const K& key, std::size_t precalculated_hash) const { return m_ht.count(key, precalculated_hash); }
486 
487 
488 
489 
490  iterator find(const Key& key) { return m_ht.find(key); }
491 
492  /**
493  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
494  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
495  */
496  iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
497 
498  const_iterator find(const Key& key) const { return m_ht.find(key); }
499 
500  /**
501  * @copydoc find(const Key& key, std::size_t precalculated_hash)
502  */
503  const_iterator find(const Key& key, std::size_t precalculated_hash) const {
504  return m_ht.find(key, precalculated_hash);
505  }
506 
507  /**
508  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
509  * If so, K must be hashable and comparable to Key.
510  */
511  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
512  iterator find(const K& key) { return m_ht.find(key); }
513 
514  /**
515  * @copydoc find(const K& key)
516  *
517  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
518  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
519  */
520  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
521  iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
522 
523  /**
524  * @copydoc find(const K& key)
525  */
526  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
527  const_iterator find(const K& key) const { return m_ht.find(key); }
528 
529  /**
530  * @copydoc find(const K& key)
531  *
532  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
533  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
534  */
535  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
536  const_iterator find(const K& key, std::size_t precalculated_hash) const {
537  return m_ht.find(key, precalculated_hash);
538  }
539 
540 
541 
542 
543  std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
544 
545  /**
546  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
547  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
548  */
549  std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) {
550  return m_ht.equal_range(key, precalculated_hash);
551  }
552 
553  std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
554 
555  /**
556  * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
557  */
558  std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const {
559  return m_ht.equal_range(key, precalculated_hash);
560  }
561 
562  /**
563  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
564  * If so, K must be hashable and comparable to Key.
565  */
566  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
567  std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
568 
569 
570  /**
571  * @copydoc equal_range(const K& key)
572  *
573  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
574  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
575  */
576  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
577  std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) {
578  return m_ht.equal_range(key, precalculated_hash);
579  }
580 
581  /**
582  * @copydoc equal_range(const K& key)
583  */
584  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
585  std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
586 
587  /**
588  * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
589  */
590  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
591  std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const {
592  return m_ht.equal_range(key, precalculated_hash);
593  }
594 
595 
596 
597 
598  /*
599  * Bucket interface
600  */
601  size_type bucket_count() const { return m_ht.bucket_count(); }
602  size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
603 
604 
605  /*
606  * Hash policy
607  */
608  float load_factor() const { return m_ht.load_factor(); }
609  float max_load_factor() const { return m_ht.max_load_factor(); }
610  void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
611 
612  void rehash(size_type count_) { m_ht.rehash(count_); }
613  void reserve(size_type count_) { m_ht.reserve(count_); }
614 
615 
616  /*
617  * Observers
618  */
619  hasher hash_function() const { return m_ht.hash_function(); }
620  key_equal key_eq() const { return m_ht.key_eq(); }
621 
622  /*
623  * Other
624  */
625 
626  /**
627  * Convert a const_iterator to an iterator.
628  */
629  iterator mutable_iterator(const_iterator pos) {
630  return m_ht.mutable_iterator(pos);
631  }
632 
633  size_type overflow_size() const noexcept { return m_ht.overflow_size(); }
634 
635  friend bool operator==(const hopscotch_map& lhs, const hopscotch_map& rhs) {
636  if(lhs.size() != rhs.size()) {
637  return false;
638  }
639 
640  for(const auto& element_lhs : lhs) {
641  const auto it_element_rhs = rhs.find(element_lhs.first);
642  if(it_element_rhs == rhs.cend() || element_lhs.second != it_element_rhs->second) {
643  return false;
644  }
645  }
646 
647  return true;
648  }
649 
650  friend bool operator!=(const hopscotch_map& lhs, const hopscotch_map& rhs) {
651  return !operator==(lhs, rhs);
652  }
653 
654  friend void swap(hopscotch_map& lhs, hopscotch_map& rhs) {
655  lhs.swap(rhs);
656  }
657 
658 
659 
660 private:
661  ht m_ht;
662 };
663 
664 
665 /**
666  * Same as `tsl::hopscotch_map<Key, T, Hash, KeyEqual, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>`.
667  */
668 template<class Key,
669  class T,
670  class Hash = std::hash<Key>,
671  class KeyEqual = std::equal_to<Key>,
672  class Allocator = std::allocator<std::pair<Key, T>>,
673  unsigned int NeighborhoodSize = 62,
674  bool StoreHash = false>
675 using hopscotch_pg_map = hopscotch_map<Key, T, Hash, KeyEqual, Allocator, NeighborhoodSize, StoreHash, tsl::hh::prime_growth_policy>;
676 
677 } // end namespace tsl
678 
679 #endif
void insert(InputIt first, InputIt last)
Definition: hopscotch_map.h:282
hopscotch_map(size_type bucket_count, const Allocator &alloc)
Definition: hopscotch_map.h:150
iterator mutable_iterator(const_iterator pos)
Definition: hopscotch_map.h:629
hopscotch_map()
Definition: hopscotch_map.h:139
const_iterator cend() const noexcept
Definition: hopscotch_map.h:235
size_type max_size() const noexcept
Definition: hopscotch_map.h:243
friend bool operator!=(const hopscotch_map &lhs, const hopscotch_map &rhs)
Definition: hopscotch_map.h:650
size_type overflow_size() const noexcept
Definition: hopscotch_map.h:633
const_iterator cbegin() const noexcept
Definition: hopscotch_map.h:231
T & operator[](Key &&key)
Definition: hopscotch_map.h:456
Definition: hopscotch_hash.h:69
hopscotch_map(const Allocator &alloc)
Definition: hopscotch_map.h:161
std::pair< iterator, bool > insert(const value_type &value)
Definition: hopscotch_map.h:253
const T & at(const Key &key) const
Definition: hopscotch_map.h:415
Definition: bhopscotch_map.h:39
hopscotch_map(size_type bucket_count, const Hash &hash=Hash(), const KeyEqual &equal=KeyEqual(), const Allocator &alloc=Allocator())
Definition: hopscotch_map.h:142
key_equal key_eq() const
Definition: hopscotch_map.h:620
float load_factor() const
Definition: hopscotch_map.h:608
hopscotch_map(InputIt first, InputIt last, size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: hopscotch_map.h:182
std::pair< const_iterator, const_iterator > equal_range(const Key &key) const
Definition: hopscotch_map.h:553
iterator insert(const_iterator hint, value_type &&value)
Definition: hopscotch_map.h:276
void clear() noexcept
Definition: hopscotch_map.h:248
iterator insert(const_iterator hint, P &&value)
Definition: hopscotch_map.h:272
const_iterator find(const K &key) const
Definition: hopscotch_map.h:527
std::pair< iterator, iterator > equal_range(const Key &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:549
iterator insert(const_iterator hint, const value_type &value)
Definition: hopscotch_map.h:267
size_type erase(const key_type &key)
Definition: hopscotch_map.h:370
iterator insert_or_assign(const_iterator hint, key_type &&k, M &&obj)
Definition: hopscotch_map.h:309
void max_load_factor(float ml)
Definition: hopscotch_map.h:610
allocator_type get_allocator() const
Definition: hopscotch_map.h:223
size_type bucket_count() const
Definition: hopscotch_map.h:601
iterator insert_or_assign(const_iterator hint, const key_type &k, M &&obj)
Definition: hopscotch_map.h:304
size_type size() const noexcept
Definition: hopscotch_map.h:242
hopscotch_map(std::initializer_list< value_type > init, size_type bucket_count, const Allocator &alloc)
Definition: hopscotch_map.h:198
iterator erase(const_iterator first, const_iterator last)
Definition: hopscotch_map.h:369
size_type count(const K &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:485
size_type max_bucket_count() const
Definition: hopscotch_map.h:602
hasher hash_function() const
Definition: hopscotch_map.h:619
friend bool operator==(const hopscotch_map &lhs, const hopscotch_map &rhs)
Definition: hopscotch_map.h:635
hopscotch_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: hopscotch_map.h:165
std::pair< const_iterator, const_iterator > equal_range(const K &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:591
std::pair< iterator, iterator > equal_range(const Key &key)
Definition: hopscotch_map.h:543
T & at(const Key &key)
Definition: hopscotch_map.h:406
size_type count(const Key &key) const
Definition: hopscotch_map.h:461
iterator find(const Key &key)
Definition: hopscotch_map.h:490
const_iterator find(const Key &key) const
Definition: hopscotch_map.h:498
std::pair< iterator, iterator > equal_range(const K &key)
Definition: hopscotch_map.h:567
iterator end() noexcept
Definition: hopscotch_map.h:233
const_iterator find(const K &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:536
std::pair< iterator, bool > insert(P &&value)
Definition: hopscotch_map.h:258
size_type erase(const K &key)
Definition: hopscotch_map.h:385
T & at(const K &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:437
iterator find(const Key &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:496
T & operator[](const Key &key)
Definition: hopscotch_map.h:455
size_type erase(const K &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:394
Definition: hopscotch_growth_policy.h:49
iterator emplace_hint(const_iterator hint, Args &&... args)
Definition: hopscotch_map.h:337
iterator find(const K &key)
Definition: hopscotch_map.h:512
std::pair< iterator, bool > emplace(Args &&... args)
Definition: hopscotch_map.h:323
size_type count(const K &key) const
Definition: hopscotch_map.h:476
std::pair< const_iterator, const_iterator > equal_range(const K &key) const
Definition: hopscotch_map.h:585
Definition: hopscotch_growth_policy.h:247
void swap(hopscotch_map &other)
Definition: hopscotch_map.h:401
const_iterator find(const Key &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:503
hopscotch_map(size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: hopscotch_map.h:155
Definition: hopscotch_map.h:79
std::pair< iterator, bool > try_emplace(key_type &&k, Args &&... args)
Definition: hopscotch_map.h:350
size_type erase(const key_type &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:376
const T & at(const K &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:450
const T & at(const Key &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:420
std::pair< iterator, iterator > equal_range(const K &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:577
const_iterator begin() const noexcept
Definition: hopscotch_map.h:230
iterator try_emplace(const_iterator hint, const key_type &k, Args &&... args)
Definition: hopscotch_map.h:355
iterator find(const K &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:521
float max_load_factor() const
Definition: hopscotch_map.h:609
hopscotch_map(std::initializer_list< value_type > init, size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: hopscotch_map.h:205
std::pair< iterator, bool > insert_or_assign(const key_type &k, M &&obj)
Definition: hopscotch_map.h:294
hopscotch_map(InputIt first, InputIt last, size_type bucket_count, const Allocator &alloc)
Definition: hopscotch_map.h:175
const T & at(const K &key) const
Definition: hopscotch_map.h:444
hopscotch_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: hopscotch_map.h:189
size_type count(const Key &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:467
void insert(std::initializer_list< value_type > ilist)
Definition: hopscotch_map.h:286
std::pair< iterator, bool > insert(value_type &&value)
Definition: hopscotch_map.h:262
iterator begin() noexcept
Definition: hopscotch_map.h:229
void rehash(size_type count_)
Definition: hopscotch_map.h:612
iterator try_emplace(const_iterator hint, key_type &&k, Args &&... args)
Definition: hopscotch_map.h:360
std::pair< const_iterator, const_iterator > equal_range(const Key &key, std::size_t precalculated_hash) const
Definition: hopscotch_map.h:558
const_iterator end() const noexcept
Definition: hopscotch_map.h:234
std::pair< iterator, bool > insert_or_assign(key_type &&k, M &&obj)
Definition: hopscotch_map.h:299
Definition: hopscotch_growth_policy.h:40
void reserve(size_type count_)
Definition: hopscotch_map.h:613
bool empty() const noexcept
Definition: hopscotch_map.h:241
T & at(const K &key)
Definition: hopscotch_map.h:428
friend void swap(hopscotch_map &lhs, hopscotch_map &rhs)
Definition: hopscotch_map.h:654
T & at(const Key &key, std::size_t precalculated_hash)
Definition: hopscotch_map.h:412
std::pair< iterator, bool > try_emplace(const key_type &k, Args &&... args)
Definition: hopscotch_map.h:345
iterator erase(const_iterator pos)
Definition: hopscotch_map.h:368
iterator erase(iterator pos)
Definition: hopscotch_map.h:367
hopscotch_map & operator=(std::initializer_list< value_type > ilist)
Definition: hopscotch_map.h:214