ordered-map
ordered_set.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_SET_H
25 #define TSL_ORDERED_SET_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 set using open adressing with robin hood with backshift delete to resolve collisions.
45  *
46  * The particularity of this hash set 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 set 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 must be copy constructible and/or move constructible. To use `unordered_erase` it also must be swappable.
53  *
54  * The behaviour of the hash set is undefinded if the destructor of Key throws an exception.
55  *
56  * By default the maximum size of a set is limited to 2^32 - 1 values, if needed this can be changed through
57  * the IndexType template parameter. Using an `uint64_t` will raise this limit to 2^64 - 1 values but each
58  * bucket will use 16 bytes instead of 8 bytes in addition to the space needed to store the values.
59  *
60  * Iterators invalidation:
61  * - clear, operator=, reserve, rehash: always invalidate the iterators (also invalidate end()).
62  * - insert, emplace, emplace_hint, operator[]: when a std::vector is used as ValueTypeContainer
63  * and if size() < capacity(), only end().
64  * Otherwise all the iterators are invalidated if an insert occurs.
65  * - erase, unordered_erase: when a std::vector is used as ValueTypeContainer invalidate the iterator of
66  * the erased element and all the ones after the erased element (including end()).
67  * Otherwise all the iterators are invalidated if an erase occurs.
68  */
69 template<class Key,
70  class Hash = std::hash<Key>,
71  class KeyEqual = std::equal_to<Key>,
72  class Allocator = std::allocator<Key>,
73  class ValueTypeContainer = std::deque<Key, Allocator>,
74  class IndexType = std::uint_least32_t>
75 class ordered_set {
76 private:
77  template<typename U>
78  using has_is_transparent = tsl::detail_ordered_hash::has_is_transparent<U>;
79 
80  class KeySelect {
81  public:
82  using key_type = Key;
83 
84  const key_type& operator()(const Key& key) const noexcept {
85  return key;
86  }
87 
88  key_type& operator()(Key& key) noexcept {
89  return key;
90  }
91  };
92 
93  using ht = detail_ordered_hash::ordered_hash<Key, KeySelect, void,
94  Hash, KeyEqual, Allocator, ValueTypeContainer, IndexType>;
95 
96 public:
97  using key_type = typename ht::key_type;
98  using value_type = typename ht::value_type;
99  using size_type = typename ht::size_type;
100  using difference_type = typename ht::difference_type;
101  using hasher = typename ht::hasher;
102  using key_equal = typename ht::key_equal;
103  using allocator_type = typename ht::allocator_type;
104  using reference = typename ht::reference;
105  using const_reference = typename ht::const_reference;
106  using pointer = typename ht::pointer;
107  using const_pointer = typename ht::const_pointer;
108  using iterator = typename ht::iterator;
109  using const_iterator = typename ht::const_iterator;
110  using reverse_iterator = typename ht::reverse_iterator;
111  using const_reverse_iterator = typename ht::const_reverse_iterator;
112 
113  using values_container_type = typename ht::values_container_type;
114 
115 
116  /*
117  * Constructors
118  */
119  ordered_set(): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE) {
120  }
121 
122  explicit ordered_set(size_type bucket_count,
123  const Hash& hash = Hash(),
124  const KeyEqual& equal = KeyEqual(),
125  const Allocator& alloc = Allocator()):
126  m_ht(bucket_count, hash, equal, alloc, ht::DEFAULT_MAX_LOAD_FACTOR)
127  {
128  }
129 
130  ordered_set(size_type bucket_count,
131  const Allocator& alloc): ordered_set(bucket_count, Hash(), KeyEqual(), alloc)
132  {
133  }
134 
135  ordered_set(size_type bucket_count,
136  const Hash& hash,
137  const Allocator& alloc): ordered_set(bucket_count, hash, KeyEqual(), alloc)
138  {
139  }
140 
141  explicit ordered_set(const Allocator& alloc): ordered_set(ht::DEFAULT_INIT_BUCKETS_SIZE, alloc) {
142  }
143 
144  template<class InputIt>
145  ordered_set(InputIt first, InputIt last,
146  size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
147  const Hash& hash = Hash(),
148  const KeyEqual& equal = KeyEqual(),
149  const Allocator& alloc = Allocator()): ordered_set(bucket_count, hash, equal, alloc)
150  {
151  insert(first, last);
152  }
153 
154  template<class InputIt>
155  ordered_set(InputIt first, InputIt last,
156  size_type bucket_count,
157  const Allocator& alloc): ordered_set(first, last, bucket_count, Hash(), KeyEqual(), alloc)
158  {
159  }
160 
161  template<class InputIt>
162  ordered_set(InputIt first, InputIt last,
163  size_type bucket_count,
164  const Hash& hash,
165  const Allocator& alloc): ordered_set(first, last, bucket_count, hash, KeyEqual(), alloc)
166  {
167  }
168 
169  ordered_set(std::initializer_list<value_type> init,
170  size_type bucket_count = ht::DEFAULT_INIT_BUCKETS_SIZE,
171  const Hash& hash = Hash(),
172  const KeyEqual& equal = KeyEqual(),
173  const Allocator& alloc = Allocator()):
174  ordered_set(init.begin(), init.end(), bucket_count, hash, equal, alloc)
175  {
176  }
177 
178  ordered_set(std::initializer_list<value_type> init,
179  size_type bucket_count,
180  const Allocator& alloc):
181  ordered_set(init.begin(), init.end(), bucket_count, Hash(), KeyEqual(), alloc)
182  {
183  }
184 
185  ordered_set(std::initializer_list<value_type> init,
186  size_type bucket_count,
187  const Hash& hash,
188  const Allocator& alloc):
189  ordered_set(init.begin(), init.end(), bucket_count, hash, KeyEqual(), alloc)
190  {
191  }
192 
193 
194  ordered_set& operator=(std::initializer_list<value_type> ilist) {
195  m_ht.clear();
196 
197  m_ht.reserve(ilist.size());
198  m_ht.insert(ilist.begin(), ilist.end());
199 
200  return *this;
201  }
202 
203  allocator_type get_allocator() const { return m_ht.get_allocator(); }
204 
205 
206  /*
207  * Iterators
208  */
209  iterator begin() noexcept { return m_ht.begin(); }
210  const_iterator begin() const noexcept { return m_ht.begin(); }
211  const_iterator cbegin() const noexcept { return m_ht.cbegin(); }
212 
213  iterator end() noexcept { return m_ht.end(); }
214  const_iterator end() const noexcept { return m_ht.end(); }
215  const_iterator cend() const noexcept { return m_ht.cend(); }
216 
217  reverse_iterator rbegin() noexcept { return m_ht.rbegin(); }
218  const_reverse_iterator rbegin() const noexcept { return m_ht.rbegin(); }
219  const_reverse_iterator rcbegin() const noexcept { return m_ht.rcbegin(); }
220 
221  reverse_iterator rend() noexcept { return m_ht.rend(); }
222  const_reverse_iterator rend() const noexcept { return m_ht.rend(); }
223  const_reverse_iterator rcend() const noexcept { return m_ht.rcend(); }
224 
225 
226  /*
227  * Capacity
228  */
229  bool empty() const noexcept { return m_ht.empty(); }
230  size_type size() const noexcept { return m_ht.size(); }
231  size_type max_size() const noexcept { return m_ht.max_size(); }
232 
233  /*
234  * Modifiers
235  */
236  void clear() noexcept { m_ht.clear(); }
237 
238 
239 
240  std::pair<iterator, bool> insert(const value_type& value) { return m_ht.insert(value); }
241  std::pair<iterator, bool> insert(value_type&& value) { return m_ht.insert(std::move(value)); }
242 
243  iterator insert(const_iterator hint, const value_type& value) {
244  return m_ht.insert_hint(hint, value);
245  }
246 
247  iterator insert(const_iterator hint, value_type&& value) {
248  return m_ht.insert_hint(hint, std::move(value));
249  }
250 
251  template<class InputIt>
252  void insert(InputIt first, InputIt last) { m_ht.insert(first, last); }
253  void insert(std::initializer_list<value_type> ilist) { m_ht.insert(ilist.begin(), ilist.end()); }
254 
255 
256 
257  /**
258  * Due to the way elements are stored, emplace will need to move or copy the key-value once.
259  * The method is equivalent to insert(value_type(std::forward<Args>(args)...));
260  *
261  * Mainly here for compatibility with the std::unordered_map interface.
262  */
263  template<class... Args>
264  std::pair<iterator, bool> emplace(Args&&... args) { return m_ht.emplace(std::forward<Args>(args)...); }
265 
266  /**
267  * Due to the way elements are stored, emplace_hint will need to move or copy the key-value once.
268  * The method is equivalent to insert(hint, value_type(std::forward<Args>(args)...));
269  *
270  * Mainly here for compatibility with the std::unordered_map interface.
271  */
272  template<class... Args>
273  iterator emplace_hint(const_iterator hint, Args&&... args) {
274  return m_ht.emplace_hint(hint, std::forward<Args>(args)...);
275  }
276 
277  /**
278  * When erasing an element, the insert order will be preserved and no holes will be present in the container
279  * returned by 'values_container()'.
280  *
281  * The method is in O(n), if the order is not important 'unordered_erase(...)' method is faster with an O(1)
282  * average complexity.
283  */
284  iterator erase(iterator pos) { return m_ht.erase(pos); }
285 
286  /**
287  * @copydoc erase(iterator pos)
288  */
289  iterator erase(const_iterator pos) { return m_ht.erase(pos); }
290 
291  /**
292  * @copydoc erase(iterator pos)
293  */
294  iterator erase(const_iterator first, const_iterator last) { return m_ht.erase(first, last); }
295 
296  /**
297  * @copydoc erase(iterator pos)
298  */
299  size_type erase(const key_type& key) { return m_ht.erase(key); }
300 
301  /**
302  * @copydoc erase(iterator pos)
303  *
304  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
305  * as hash_function()(key). Usefull to speed-up the lookup to the value if you already have the hash.
306  */
307  size_type erase(const key_type& key, std::size_t precalculated_hash) {
308  return m_ht.erase(key, precalculated_hash);
309  }
310 
311  /**
312  * @copydoc erase(iterator pos)
313  *
314  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
315  * If so, K must be hashable and comparable to Key.
316  */
317  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
318  size_type erase(const K& key) { return m_ht.erase(key); }
319 
320  /**
321  * @copydoc erase(const key_type& key, std::size_t precalculated_hash)
322  *
323  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
324  * If so, K must be hashable and comparable to Key.
325  */
326  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
327  size_type erase(const K& key, std::size_t precalculated_hash) {
328  return m_ht.erase(key, precalculated_hash);
329  }
330 
331 
332 
333  void swap(ordered_set& other) { other.m_ht.swap(m_ht); }
334 
335  /*
336  * Lookup
337  */
338  size_type count(const Key& key) const { return m_ht.count(key); }
339 
340  /**
341  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
342  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
343  */
344  size_type count(const Key& key, std::size_t precalculated_hash) const {
345  return m_ht.count(key, precalculated_hash);
346  }
347 
348  /**
349  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
350  * If so, K must be hashable and comparable to Key.
351  */
352  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
353  size_type count(const K& key) const { return m_ht.count(key); }
354 
355  /**
356  * @copydoc count(const K& key) const
357  *
358  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
359  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
360  */
361  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
362  size_type count(const K& key, std::size_t precalculated_hash) const {
363  return m_ht.count(key, precalculated_hash);
364  }
365 
366 
367 
368 
369  iterator find(const Key& key) { return m_ht.find(key); }
370 
371  /**
372  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
373  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
374  */
375  iterator find(const Key& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
376 
377  const_iterator find(const Key& key) const { return m_ht.find(key); }
378 
379  /**
380  * @copydoc find(const Key& key, std::size_t precalculated_hash)
381  */
382  const_iterator find(const Key& key, std::size_t precalculated_hash) const {
383  return m_ht.find(key, precalculated_hash);
384  }
385 
386  /**
387  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
388  * If so, K must be hashable and comparable to Key.
389  */
390  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
391  iterator find(const K& key) { return m_ht.find(key); }
392 
393  /**
394  * @copydoc find(const K& key)
395  *
396  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
397  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
398  */
399  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
400  iterator find(const K& key, std::size_t precalculated_hash) { return m_ht.find(key, precalculated_hash); }
401 
402  /**
403  * @copydoc find(const K& key)
404  */
405  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
406  const_iterator find(const K& key) const { return m_ht.find(key); }
407 
408  /**
409  * @copydoc find(const K& key)
410  *
411  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
412  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
413  */
414  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
415  const_iterator find(const K& key, std::size_t precalculated_hash) const {
416  return m_ht.find(key, precalculated_hash);
417  }
418 
419 
420 
421  std::pair<iterator, iterator> equal_range(const Key& key) { return m_ht.equal_range(key); }
422 
423  /**
424  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
425  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
426  */
427  std::pair<iterator, iterator> equal_range(const Key& key, std::size_t precalculated_hash) {
428  return m_ht.equal_range(key, precalculated_hash);
429  }
430 
431  std::pair<const_iterator, const_iterator> equal_range(const Key& key) const { return m_ht.equal_range(key); }
432 
433  /**
434  * @copydoc equal_range(const Key& key, std::size_t precalculated_hash)
435  */
436  std::pair<const_iterator, const_iterator> equal_range(const Key& key, std::size_t precalculated_hash) const {
437  return m_ht.equal_range(key, precalculated_hash);
438  }
439 
440  /**
441  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
442  * If so, K must be hashable and comparable to Key.
443  */
444  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
445  std::pair<iterator, iterator> equal_range(const K& key) { return m_ht.equal_range(key); }
446 
447  /**
448  * @copydoc equal_range(const K& key)
449  *
450  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
451  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
452  */
453  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
454  std::pair<iterator, iterator> equal_range(const K& key, std::size_t precalculated_hash) {
455  return m_ht.equal_range(key, precalculated_hash);
456  }
457 
458  /**
459  * @copydoc equal_range(const K& key)
460  */
461  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
462  std::pair<const_iterator, const_iterator> equal_range(const K& key) const { return m_ht.equal_range(key); }
463 
464  /**
465  * @copydoc equal_range(const K& key, std::size_t precalculated_hash)
466  */
467  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
468  std::pair<const_iterator, const_iterator> equal_range(const K& key, std::size_t precalculated_hash) const {
469  return m_ht.equal_range(key, precalculated_hash);
470  }
471 
472 
473  /*
474  * Bucket interface
475  */
476  size_type bucket_count() const { return m_ht.bucket_count(); }
477  size_type max_bucket_count() const { return m_ht.max_bucket_count(); }
478 
479 
480  /*
481  * Hash policy
482  */
483  float load_factor() const { return m_ht.load_factor(); }
484  float max_load_factor() const { return m_ht.max_load_factor(); }
485  void max_load_factor(float ml) { m_ht.max_load_factor(ml); }
486 
487  void rehash(size_type count) { m_ht.rehash(count); }
488  void reserve(size_type count) { m_ht.reserve(count); }
489 
490 
491  /*
492  * Observers
493  */
494  hasher hash_function() const { return m_ht.hash_function(); }
495  key_equal key_eq() const { return m_ht.key_eq(); }
496 
497 
498  /*
499  * Other
500  */
501 
502  /**
503  * Convert a const_iterator to an iterator.
504  */
505  iterator mutable_iterator(const_iterator pos) {
506  return m_ht.mutable_iterator(pos);
507  }
508 
509  /**
510  * Requires index <= size().
511  *
512  * Return an iterator to the element at index. Return end() if index == size().
513  */
514  iterator nth(size_type index) { return m_ht.nth(index); }
515 
516  /**
517  * @copydoc nth(size_type index)
518  */
519  const_iterator nth(size_type index) const { return m_ht.nth(index); }
520 
521 
522  /**
523  * Return const_reference to the first element. Requires the container to not be empty.
524  */
525  const_reference front() const { return m_ht.front(); }
526 
527  /**
528  * Return const_reference to the last element. Requires the container to not be empty.
529  */
530  const_reference back() const { return m_ht.back(); }
531 
532 
533  /**
534  * Only available if ValueTypeContainer is a std::vector. Same as calling 'values_container().data()'.
535  */
536  template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>
537  const typename values_container_type::value_type* data() const noexcept { return m_ht.data(); }
538 
539  /**
540  * Return the container in which the values are stored. The values are in the same order as the insertion order
541  * and are contiguous in the structure, no holes (size() == values_container().size()).
542  */
543  const values_container_type& values_container() const noexcept { return m_ht.values_container(); }
544 
545  template<class U = values_container_type, typename std::enable_if<tsl::detail_ordered_hash::is_vector<U>::value>::type* = nullptr>
546  size_type capacity() const noexcept { return m_ht.capacity(); }
547 
548  void shrink_to_fit() { m_ht.shrink_to_fit(); }
549 
550 
551 
552  /**
553  * Insert the value before pos shifting all the elements on the right of pos (including pos) one position
554  * to the right.
555  *
556  * Amortized linear time-complexity in the distance between pos and end().
557  */
558  std::pair<iterator, bool> insert_at_position(const_iterator pos, const value_type& value) {
559  return m_ht.insert_at_position(pos, value);
560  }
561 
562  /**
563  * @copydoc insert_at_position(const_iterator pos, const value_type& value)
564  */
565  std::pair<iterator, bool> insert_at_position(const_iterator pos, value_type&& value) {
566  return m_ht.insert_at_position(pos, std::move(value));
567  }
568 
569  /**
570  * @copydoc insert_at_position(const_iterator pos, const value_type& value)
571  *
572  * Same as insert_at_position(pos, value_type(std::forward<Args>(args)...), mainly
573  * here for coherence.
574  */
575  template<class... Args>
576  std::pair<iterator, bool> emplace_at_position(const_iterator pos, Args&&... args) {
577  return m_ht.emplace_at_position(pos, std::forward<Args>(args)...);
578  }
579 
580 
581 
582  void pop_back() { m_ht.pop_back(); }
583 
584  /**
585  * Faster erase operation with an O(1) average complexity but it doesn't preserve the insertion order.
586  *
587  * If an erasure occurs, the last element of the map will take the place of the erased element.
588  */
589  iterator unordered_erase(iterator pos) { return m_ht.unordered_erase(pos); }
590 
591  /**
592  * @copydoc unordered_erase(iterator pos)
593  */
594  iterator unordered_erase(const_iterator pos) { return m_ht.unordered_erase(pos); }
595 
596  /**
597  * @copydoc unordered_erase(iterator pos)
598  */
599  size_type unordered_erase(const key_type& key) { return m_ht.unordered_erase(key); }
600 
601  /**
602  * @copydoc unordered_erase(iterator pos)
603  *
604  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
605  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
606  */
607  size_type unordered_erase(const key_type& key, std::size_t precalculated_hash) {
608  return m_ht.unordered_erase(key, precalculated_hash);
609  }
610 
611  /**
612  * @copydoc unordered_erase(iterator pos)
613  *
614  * This overload only participates in the overload resolution if the typedef KeyEqual::is_transparent exists.
615  * If so, K must be hashable and comparable to Key.
616  */
617  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
618  size_type unordered_erase(const K& key) { return m_ht.unordered_erase(key); }
619 
620  /**
621  * @copydoc unordered_erase(const K& key)
622  *
623  * Use the hash value 'precalculated_hash' instead of hashing the key. The hash value should be the same
624  * as hash_function()(key). Usefull to speed-up the lookup if you already have the hash.
625  */
626  template<class K, class KE = KeyEqual, typename std::enable_if<has_is_transparent<KE>::value>::type* = nullptr>
627  size_type unordered_erase(const K& key, std::size_t precalculated_hash) {
628  return m_ht.unordered_erase(key, precalculated_hash);
629  }
630 
631  /**
632  * Serialize the set through the `serializer` parameter.
633  *
634  * The `serializer` parameter must be a function object that supports the following call:
635  * - `void operator()(const U& value);` where the types `std::uint64_t`, `float` and `Key` must be supported for U.
636  *
637  * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, ...) of the types it serializes
638  * in the hands of the `Serializer` function object if compatibilty is required.
639  */
640  template<class Serializer>
641  void serialize(Serializer& serializer) const {
642  m_ht.serialize(serializer);
643  }
644 
645  /**
646  * Deserialize a previouly serialized set through the `deserializer` parameter.
647  *
648  * The `deserializer` parameter must be a function object that supports the following calls:
649  * - `template<typename U> U operator()();` where the types `std::uint64_t`, `float` and `Key` must be supported for U.
650  *
651  * If the deserialized hash set type is hash compatible with the serialized set, the deserialization process can be
652  * sped up by setting `hash_compatible` to true. To be hash compatible, the Hash and KeyEqual must behave the same way
653  * 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
654  * to serialize the map, the same apply for `IndexType`. If these criteria are not met, the behaviour is undefined with
655  * `hash_compatible` sets to true.
656  *
657  * The behaviour is undefined if the type `Key` of the `ordered_set` is not the same as the
658  * type used during serialization.
659  *
660  * The implementation leaves binary compatibilty (endianness, IEEE 754 for floats, size of int, ...) of the types it
661  * deserializes in the hands of the `Deserializer` function object if compatibilty is required.
662  */
663  template<class Deserializer>
664  static ordered_set deserialize(Deserializer& deserializer, bool hash_compatible = false) {
665  ordered_set set(0);
666  set.m_ht.deserialize(deserializer, hash_compatible);
667 
668  return set;
669  }
670 
671 
672 
673  friend bool operator==(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht == rhs.m_ht; }
674  friend bool operator!=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht != rhs.m_ht; }
675  friend bool operator<(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht < rhs.m_ht; }
676  friend bool operator<=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht <= rhs.m_ht; }
677  friend bool operator>(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht > rhs.m_ht; }
678  friend bool operator>=(const ordered_set& lhs, const ordered_set& rhs) { return lhs.m_ht >= rhs.m_ht; }
679 
680  friend void swap(ordered_set& lhs, ordered_set& rhs) { lhs.swap(rhs); }
681 
682 private:
683  ht m_ht;
684 };
685 
686 } // end namespace tsl
687 
688 #endif
void swap(ordered_set &other)
Definition: ordered_set.h:333
iterator mutable_iterator(const_iterator pos)
Definition: ordered_set.h:505
const values_container_type::value_type * data() const noexcept
Definition: ordered_set.h:537
friend void swap(ordered_set &lhs, ordered_set &rhs)
Definition: ordered_set.h:680
iterator insert(const_iterator hint, const value_type &value)
Definition: ordered_set.h:243
ordered_set(InputIt first, InputIt last, size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: ordered_set.h:162
void rehash(size_type count)
Definition: ordered_set.h:487
size_type count(const Key &key) const
Definition: ordered_set.h:338
Definition: ordered_hash.h:279
size_type erase(const K &key)
Definition: ordered_set.h:318
std::pair< const_iterator, const_iterator > equal_range(const Key &key, std::size_t precalculated_hash) const
Definition: ordered_set.h:436
std::pair< const_iterator, const_iterator > equal_range(const K &key) const
Definition: ordered_set.h:462
size_type unordered_erase(const key_type &key)
Definition: ordered_set.h:599
iterator nth(size_type index)
Definition: ordered_set.h:514
float max_load_factor() const
Definition: ordered_set.h:484
iterator emplace_hint(const_iterator hint, Args &&... args)
Definition: ordered_set.h:273
std::pair< iterator, bool > insert(const value_type &value)
Definition: ordered_set.h:240
const_reference front() const
Definition: ordered_set.h:525
Definition: ordered_hash.h:82
Definition: ordered_hash.h:80
Definition: ordered_set.h:75
size_type max_bucket_count() const
Definition: ordered_set.h:477
size_type unordered_erase(const K &key)
Definition: ordered_set.h:618
static ordered_set deserialize(Deserializer &deserializer, bool hash_compatible=false)
Definition: ordered_set.h:664
const_iterator begin() const noexcept
Definition: ordered_set.h:210
void insert(InputIt first, InputIt last)
Definition: ordered_set.h:252
size_type count(const K &key, std::size_t precalculated_hash) const
Definition: ordered_set.h:362
std::pair< iterator, bool > insert_at_position(const_iterator pos, const value_type &value)
Definition: ordered_set.h:558
ordered_set(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_set.h:145
void reserve(size_type count)
Definition: ordered_set.h:488
key_equal key_eq() const
Definition: ordered_set.h:495
std::pair< iterator, bool > insert_at_position(const_iterator pos, value_type &&value)
Definition: ordered_set.h:565
const_reverse_iterator rend() const noexcept
Definition: ordered_set.h:222
ordered_set & operator=(std::initializer_list< value_type > ilist)
Definition: ordered_set.h:194
iterator unordered_erase(const_iterator pos)
Definition: ordered_set.h:594
iterator begin() noexcept
Definition: ordered_set.h:209
ordered_set(size_type bucket_count, const Allocator &alloc)
Definition: ordered_set.h:130
void pop_back()
Definition: ordered_set.h:582
size_type erase(const key_type &key)
Definition: ordered_set.h:299
std::pair< iterator, iterator > equal_range(const Key &key, std::size_t precalculated_hash)
Definition: ordered_set.h:427
void insert(std::initializer_list< value_type > ilist)
Definition: ordered_set.h:253
const_iterator find(const K &key, std::size_t precalculated_hash) const
Definition: ordered_set.h:415
ordered_set(const Allocator &alloc)
Definition: ordered_set.h:141
size_type capacity() const noexcept
Definition: ordered_set.h:546
friend bool operator>=(const ordered_set &lhs, const ordered_set &rhs)
Definition: ordered_set.h:678
std::pair< iterator, bool > insert(value_type &&value)
Definition: ordered_set.h:241
ordered_set()
Definition: ordered_set.h:119
iterator find(const K &key)
Definition: ordered_set.h:391
size_type unordered_erase(const key_type &key, std::size_t precalculated_hash)
Definition: ordered_set.h:607
const_iterator cend() const noexcept
Definition: ordered_set.h:215
ordered_set(size_type bucket_count, const Hash &hash=Hash(), const KeyEqual &equal=KeyEqual(), const Allocator &alloc=Allocator())
Definition: ordered_set.h:122
hasher hash_function() const
Definition: ordered_set.h:494
allocator_type get_allocator() const
Definition: ordered_set.h:203
void clear() noexcept
Definition: ordered_set.h:236
const_iterator find(const K &key) const
Definition: ordered_set.h:406
std::pair< iterator, iterator > equal_range(const K &key, std::size_t precalculated_hash)
Definition: ordered_set.h:454
friend bool operator<=(const ordered_set &lhs, const ordered_set &rhs)
Definition: ordered_set.h:676
reverse_iterator rbegin() noexcept
Definition: ordered_set.h:217
iterator unordered_erase(iterator pos)
Definition: ordered_set.h:589
ordered_set(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_set.h:169
const_iterator nth(size_type index) const
Definition: ordered_set.h:519
ordered_set(std::initializer_list< value_type > init, size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: ordered_set.h:185
const_iterator end() const noexcept
Definition: ordered_set.h:214
void shrink_to_fit()
Definition: ordered_set.h:548
friend bool operator>(const ordered_set &lhs, const ordered_set &rhs)
Definition: ordered_set.h:677
iterator insert(const_iterator hint, value_type &&value)
Definition: ordered_set.h:247
size_type max_size() const noexcept
Definition: ordered_set.h:231
std::pair< const_iterator, const_iterator > equal_range(const K &key, std::size_t precalculated_hash) const
Definition: ordered_set.h:468
iterator find(const Key &key, std::size_t precalculated_hash)
Definition: ordered_set.h:375
const_reverse_iterator rcend() const noexcept
Definition: ordered_set.h:223
size_type unordered_erase(const K &key, std::size_t precalculated_hash)
Definition: ordered_set.h:627
iterator erase(iterator pos)
Definition: ordered_set.h:284
iterator find(const Key &key)
Definition: ordered_set.h:369
bool empty() const noexcept
Definition: ordered_set.h:229
std::pair< iterator, bool > emplace(Args &&... args)
Definition: ordered_set.h:264
std::pair< iterator, iterator > equal_range(const Key &key)
Definition: ordered_set.h:421
size_type count(const K &key) const
Definition: ordered_set.h:353
const_reverse_iterator rcbegin() const noexcept
Definition: ordered_set.h:219
void max_load_factor(float ml)
Definition: ordered_set.h:485
friend bool operator<(const ordered_set &lhs, const ordered_set &rhs)
Definition: ordered_set.h:675
std::pair< const_iterator, const_iterator > equal_range(const Key &key) const
Definition: ordered_set.h:431
const values_container_type & values_container() const noexcept
Definition: ordered_set.h:543
reverse_iterator rend() noexcept
Definition: ordered_set.h:221
iterator find(const K &key, std::size_t precalculated_hash)
Definition: ordered_set.h:400
friend bool operator!=(const ordered_set &lhs, const ordered_set &rhs)
Definition: ordered_set.h:674
const_reverse_iterator rbegin() const noexcept
Definition: ordered_set.h:218
iterator end() noexcept
Definition: ordered_set.h:213
size_type bucket_count() const
Definition: ordered_set.h:476
const_iterator cbegin() const noexcept
Definition: ordered_set.h:211
iterator erase(const_iterator pos)
Definition: ordered_set.h:289
float load_factor() const
Definition: ordered_set.h:483
size_type size() const noexcept
Definition: ordered_set.h:230
friend bool operator==(const ordered_set &lhs, const ordered_set &rhs)
Definition: ordered_set.h:673
void serialize(Serializer &serializer) const
Definition: ordered_set.h:641
std::pair< iterator, bool > emplace_at_position(const_iterator pos, Args &&... args)
Definition: ordered_set.h:576
size_type erase(const K &key, std::size_t precalculated_hash)
Definition: ordered_set.h:327
ordered_set(InputIt first, InputIt last, size_type bucket_count, const Allocator &alloc)
Definition: ordered_set.h:155
const_reference back() const
Definition: ordered_set.h:530
iterator erase(const_iterator first, const_iterator last)
Definition: ordered_set.h:294
ordered_set(std::initializer_list< value_type > init, size_type bucket_count, const Allocator &alloc)
Definition: ordered_set.h:178
ordered_set(size_type bucket_count, const Hash &hash, const Allocator &alloc)
Definition: ordered_set.h:135
std::pair< iterator, iterator > equal_range(const K &key)
Definition: ordered_set.h:445
const_iterator find(const Key &key, std::size_t precalculated_hash) const
Definition: ordered_set.h:382
const_iterator find(const Key &key) const
Definition: ordered_set.h:377
size_type count(const Key &key, std::size_t precalculated_hash) const
Definition: ordered_set.h:344
size_type erase(const key_type &key, std::size_t precalculated_hash)
Definition: ordered_set.h:307