Flow 1.0.0
Flow project: Full implementation reference.
linked_hash_set.hpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
22#include <cstddef>
23#include <boost/unordered_set.hpp>
24#include <boost/move/unique_ptr.hpp>
25
26namespace flow::util
27{
28
29/**
30 * An object of this class is a set that combines the lookup speed of an `unordered_set<>` and ordering and iterator
31 * stability capabilities of an `std::list<>`.
32 *
33 * This is just like Linked_hash_map, except it only stores keys -- no mapped values. All comments, except for
34 * self-explanatory differences, from Linked_hash_map apply here. Thus I will only speak of differences below to
35 * avoid duplication of this header.
36 *
37 * @see class Linked_hash_map.
38 *
39 * @tparam Key
40 * Key type. Same as for Linked_hash_map.
41 * @tparam Hash
42 * Hasher type. Same as for Linked_hash_map.
43 * @tparam Pred
44 * Equality functor type. Same as for Linked_hash_map.
45 */
46template<typename Key, typename Hash, typename Pred>
48{
49public:
50 // Types.
51
52 /// Short-hand for values, which in this case are simply the keys.
53 using Value = Key;
54
55private:
56 // Types. These are here in the middle of public block due to inability to forward-declare aliases.
57
58 /// Short-hand for doubly linked list of `Key`s.
59 using Value_list = std::list<Value>;
60
61public:
62
63 // Types (continued).
64
65 /// Type for index into array of items, where items are all applicable objects including `Value`s and `Key`s.
66 using size_type = std::size_t;
67 /// Type for difference of `size_type`s.
68 using difference_type = std::ptrdiff_t;
69
70 /// Type for iterator pointing into an immutable structure of this type.
71 using Const_iterator = typename Value_list::const_iterator;
72
73 /**
74 * Type for iterator pointing into a mutable structure of this type but actually that is not possible;
75 * so alias to #Const_iterator. Note these are standard semantics (see `std::set`, etc.).
76 */
78
79 /// Type for reverse iterator pointing into an immutable structure of this type.
80 using Const_reverse_iterator = typename Value_list::const_reverse_iterator;
81
82 /**
83 * Type for reverse iterator pointing into a mutable structure of this type but actually that is not possible;
84 * so alias to #Const_reverse_iterator. Note these are standard semantics (see `std::set`, etc.).
85 */
87
88 /// For container compliance (hence the irregular capitalization): `Key` type.
89 using key_type = Key;
90 /// For container compliance (hence the irregular capitalization): `Value` type.
92 /// For container compliance (hence the irregular capitalization): `Hash` type.
93 using hasher = Hash;
94 /// For container compliance (hence the irregular capitalization): `Pred` type.
95 using key_equal = Pred;
96 /// For container compliance (hence the irregular capitalization): pointer to `Key` type.
97 using pointer = Value*;
98 /// For container compliance (hence the irregular capitalization): pointer to `const Key` type.
99 using const_pointer = Value const *;
100 /// For container compliance (hence the irregular capitalization): reference to `Key` type.
101 using reference = Value&;
102 /// For container compliance (hence the irregular capitalization): reference to `const Key` type.
103 using const_reference = Value const &;
104 /// For container compliance (hence the irregular capitalization): `Iterator` type.
106 /// For container compliance (hence the irregular capitalization): `Const_iterator` type.
108
109 // Constructors/destructor.
110
111 /**
112 * Constructs empty structure with some basic parameters.
113 *
114 * @param n_buckets
115 * Number of buckets for the unordered (hash) table. Special value -1 (default) will cause us to use
116 * whatever `unordered_set<>` would use by default.
117 * @param hasher_instance
118 * Instance of the hash function type (`hasher_instance(Key k)` should be `size_type`d hash of key `k`).
119 * @param key_equal_instance
120 * Instance of the equality function type (`key_equal_instance(Key k1, Key k2)` should return `true` if and
121 * only if `k1` equals `k2`).
122 */
123 explicit Linked_hash_set(size_type n_buckets = size_type(-1),
124 Hash const & hasher_instance = Hash(),
125 Pred const & key_equal_instance = Pred());
126
127 /**
128 * Constructs structure with some basic parameters, and values initialized from initializer list.
129 * The values are inserted as if `insert(v)` was called for each pair `v` in `values`
130 * <em>in reverse order</em>. Since the canonical ordering places the *newest* (last inserted/touch()ed)
131 * element at the *front* of the ordering, that means that forward iteration through the set (right after this
132 * constructor runs) will yield values in the *same* order as in initializer list `values`.
133 *
134 * @param values
135 * Values with which to fill the structure after initializing it.
136 * Typically you'd provide a series of keys like this:
137 * `{ key1, key2, ... }`. They will appear in iterated sequence in the same order as they appear
138 * in this list.
139 * @param n_buckets
140 * See other constructor.
141 * @param hasher_instance
142 * See other constructor.
143 * @param key_equal_instance
144 * See other constructor.
145 */
146 explicit Linked_hash_set(std::initializer_list<Value> values,
147 size_type n_buckets = size_type(-1),
148 Hash const & hasher_instance = Hash(),
149 Pred const & key_equal_instance = Pred());
150
151 /**
152 * Constructs object that is a copy of the given source. Equivalent to `operator=(src)`.
153 *
154 * @param src
155 * Source object.
156 */
158
159 /**
160 * Constructs object by making it equal to the given source, while the given source becomes as-if default-cted.
161 *
162 * @param src
163 * Source object which is emptied.
164 */
166
167 // Methods.
168
169 /**
170 * Overwrites this object with a copy of the given source. We become equal to `src` but independent of it to the max
171 * extent possible (if you've got pointers stored in there, for example, the pointers are copied, not the values
172 * at those pointers). In addition, the hasher instance and equality predicate are copied from `src`. Finally, a
173 * reasonable attempt is made to also make the internal structure of the hash set to be similar to that of `src`.
174 *
175 * @param src
176 * Source object.
177 * @return `*this`.
178 */
180
181 /**
182 * Overwrites this object making it equal to the given source, while the given source becomes as-if default-cted.
183 *
184 * @param src
185 * Source object which is emptied (unless it *is* `*this`; then no-op).
186 * @return `*this`.
187 */
189
190 /**
191 * Attempts to insert the given key into the set. If the key is already present in the set,
192 * does nothing. Return value indicates various info of interest about what occurred or did not occur.
193 * Key presence is determined according to the `Pred` template parameter which determines equality of 2 given keys;
194 * and via the `Hash` template parameter that enables efficient hash-based lookup.
195 * If inserted, the new element is considered "newest," as if by touch(). If not inserted, the existing element
196 * location is not affected.
197 *
198 * @param key
199 * The key to attempt to insert. This value is copied, and the copy is inserted.
200 * @return A pair whose second element is `true` if and only if the insertion occurred; and whose first element
201 * is an iterator pointing to either the newly inserted element or already present one equal to
202 * `key`.
203 */
204 std::pair<Iterator, bool> insert(Value const & key);
205
206 /**
207 * Attempts to find the given key in the set. Key presence is determined according to the `Pred` template
208 * parameter which determines equality of 2 given keys; and via the `Hash` template parameter that enables efficient
209 * hash-based lookup. The returned iterator (if valid) cannot be used to mutate the elements stored in the map.
210 *
211 * As long as the key is not removed from the map, the iterator will continue to be valid.
212 *
213 * @note Let `r` be the returned value. Since no `key`-associated value beyond `key` itself is stored in the
214 * structure, the fact that `*r == key` is not valuable: you already had `key` after all! It is only useful
215 * in pin-pointing the relative location in the chronological ordering; in being used as an argument to
216 * various erasing methods; and in checking for presence of the key in the set. For the latter, I recommend
217 * the following utility:
218 * @see util::key_exists(), which uses this method to more concisely check for the presence of a key.
219 * @param key
220 * Key whose equal to find.
221 * @return If found, iterator to the equivalent key; else `this->const_past_oldest()`.
222 */
223 Const_iterator find(Key const & key) const;
224
225 /**
226 * Returns the number of times a key is equivalent to the given one is present in the hash: either 1 or 0.
227 *
228 * @param key
229 * Key whose equal to find.
230 * @return 0 or 1.
231 */
232 size_type count(Key const & key) const;
233
234 /**
235 * Returns reference to immutable front ("newest") element in the structure; formally equivalent to
236 * `*(this->const_newest())`.
237 *
238 * OK to call when empty(); but behavior undefined if you attempt to access the result in any way if either empty()
239 * when this was called; or if `!empty()` at that time, but the underlying element is erased at time of access.
240 * If not `empty()` when this was called, then resulting reference continues to be valid as long as the underlying
241 * element is not erased; however, in the future the reference (while referring to the same element) might not refer
242 * to front ("newest") element any longer. (Informally, most uses would only call const_front() when `!empty()`, and
243 * would access it immediately and but once. However, I'm listing the corner cases above.)
244 *
245 * @return Reference to immutable `Key` (a/k/a `Value`) directly inside data structure; or to undefined location if
246 * currently empty().
247 */
248 Value const & const_front() const;
249
250 /**
251 * Returns reference to immutable back ("oldest") element in the structure; formally equivalent to
252 * `*(--this->const_past_oldest())`.
253 *
254 * All other comments for const_front() apply analogously.
255 *
256 * @return Reference to immutable `Key` (a/k/a `Value`) directly inside data structure; or to undefined location if
257 * currently empty().
258 */
259 Value const & const_back() const;
260
261 /**
262 * Given a valid iterator into the structure, makes the pointed to element "newest" by moving it from wherever it
263 * is to be first in the iteration order. Behavior undefined if iterator invalid.
264 *
265 * The iterator continues to be valid.
266 *
267 * @param it
268 * Iterator to an element of the structure.
269 */
270 void touch(Const_iterator const & it);
271
272 /**
273 * Given a key into the structure, makes the corresponding element "newest" by moving it from wherever it
274 * is to be first in the iteration order; or does nothing if no such key. Return value indicates various info of
275 * interest about what occurred or did not occur.
276 *
277 * @param key
278 * Key whose equal to find.
279 * @return `true` if the key was found (even if it was already "newest"); false if not found.
280 */
281 bool touch(Key const & key);
282
283 /**
284 * Erases the element pointed to by the given valid iterator. Behavior undefined if it is not valid. `it` becomes
285 * invalid.
286 *
287 * @param it
288 * Iterator of element to erase.
289 * @return Iterator one position past (i.e., "older") than `it`, before `*it` was removed.
290 */
292
293 /**
294 * Erases all elements in the range [`it_newest`, `it_past_oldest`). Behavior undefined if given iterator is invalid.
295 * `it_newest` becomes invalid.
296 *
297 * @param it_newest
298 * Iterator of first ("newest") element to erase.
299 * @param it_past_oldest
300 * Iterator of one past last ("oldest") element to erase.
301 * @return `it_past_oldest` copy.
302 */
303 Iterator erase(Const_iterator const & it_newest, Const_iterator const & it_past_oldest);
304
305 /**
306 * Erases the element with the given key, if it exists. Return value indicates various info of interest about what
307 * occurred or did not occur.
308 *
309 * @param key
310 * Key such that its equal's (if found) element will be erased.
311 * @return Number of elements erased (0 or 1).
312 */
313 size_type erase(Key const & key);
314
315 /// Queue-style pop (erase) of the front -- a/k/a newest -- element. Behavior undefined if empty().
316 void pop_front();
317
318 /// Queue-style pop (erase) of the back -- a/k/a oldest -- element. Behavior undefined if empty().
319 void pop_back();
320
321 /// Makes it so that `size() == 0`.
322 void clear();
323
324 /**
325 * Swaps the contents of this structure and `other`. This is a constant-time operation.
326 *
327 * @param other
328 * The other structure.
329 */
330 void swap(Linked_hash_set& other);
331
332 /**
333 * Synonym of newest().
334 * @return See newest().
335 */
337
338 /**
339 * Returns first, a/k/a "newest," element's iterator (to immutable element, due to nature of this type).
340 * @return Ditto.
341 */
343
344 /**
345 * Synonym of past_oldest(). Exists as standard container method.
346 * @return See past_oldest().
347 */
348 Iterator end() const;
349
350 /**
351 * Returns one past last, a/k/a "oldest," element's iterator (to immutable element, due to nature of this type).
352 * @return Ditto.
353 */
355
356 /**
357 * Synonym of const_newest(). Exists as standard container method (hence the odd formatting).
358 * @return See const_newest().
359 */
361
362 /**
363 * Returns first, a/k/a "newest," element's iterator (to immutable element).
364 * @return Ditto.
365 */
367
368 /**
369 * Synonym of const_past_oldest(). Exists as standard container method (hence the odd formatting).
370 * @return See const_past_oldest().
371 */
373
374 /**
375 * Returns one past last, a/k/a "oldest," element's iterator (to immutable element).
376 * @return Ditto.
377 */
379
380 /**
381 * Synonym of oldest().
382 * @return See oldest().
383 */
385
386 /**
387 * Returns first, a/k/a "oldest," element's reverse iterator (to immutable element, due to nature of this type).
388 * @return Ditto.
389 */
391
392 /**
393 * Synonym of past_newest(). Exists as standard container method.
394 * @return See past_newest().
395 */
397
398 /**
399 * Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element, due
400 * to nature of this type).
401 * @return Ditto.
402 */
404
405 /**
406 * Synonym of const_oldest().
407 * @return See const_oldest().
408 */
410
411 /**
412 * Returns first, a/k/a "oldest," element's reverse iterator (to immutable element).
413 * @return Ditto.
414 */
416
417 /**
418 * Synonym of const_past_newest(). Exists as standard container method.
419 * @return See const_past_newest().
420 */
422
423 /**
424 * Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element).
425 * @return Ditto.
426 */
428
429 /**
430 * Returns `true` if and only if container is empty. Same performance as of `unordered_map<>`.
431 * @return Ditto.
432 */
433 bool empty() const;
434
435 /**
436 * Returns number of elements stored. Same performance as of `unordered_map<>`.
437 * @return Ditto.
438 */
440
441 /**
442 * Returns max number of elements that can be stored. Same performance as of `unordered_map<>` + `list<>`.
443 * @return Ditto.
444 */
446
447private:
448
449 // Methods.
450
451 /**
452 * Helper that modifies #m_value_list and #m_keys_into_list_map so that `key`'s copy is inserted into
453 * the structure. Pre-condition is that `key` is not in the structure (else behavior undefined).
454 *
455 * @param key
456 * Same as in insert().
457 * @return Same as in `insert().first`.
458 */
460
461 // Types.
462
463 /// Short-hand for iterator into doubly linked list of `Key` elements.
465
466 /// Short-hand for const iterator into doubly linked list of `Key` elements.
468
469 /// Short-hand for a hash map that maps `Key` to iterator into doubly linked list of `Key` elements.
470 using Key_to_value_iter_map = boost::unordered_map<Key, Value_list_iter, Hash, Pred>;
471
472 // Data.
473
474 /// See Linked_hash_map::m_value_list. Essentially all of that applies here.
476
477 /// See Linked_hash_map::m_keys_into_list_map. Essentially all of that applies here.
478 boost::movelib::unique_ptr<Key_to_value_iter_map> m_keys_into_list_map;
479}; // class Linked_hash_set
480
481// Free functions: in *_fwd.hpp.
482
483// Template implementations.
484
485template<typename Key, typename Hash, typename Pred>
487 hasher const & hasher_instance,
488 key_equal const & key_equal_instance) :
489 Linked_hash_set({}, n_buckets, hasher_instance, key_equal_instance)
490{
491 // Nothing.
492}
493
494template<typename Key, typename Hash, typename Pred>
495Linked_hash_set<Key, Hash, Pred>::Linked_hash_set(std::initializer_list<Value> values,
496 size_type n_buckets,
497 hasher const & hasher_instance,
498 key_equal const & key_equal_instance) :
499 // Their initializer_list is meant for a set, but it is perfect for our list of keys.
500 m_value_list(values)
501{
502 using boost::unordered_set;
503
504 /* Guess the default size, if they specified the default, from a dummy unrelated-type set. Probably
505 * that'll be correct. Even use our template argument values, just in case that matters. */
506 if (n_buckets == size_type(-1))
507 {
508 unordered_set<Key, Hash, Pred> dummy;
509 n_buckets = dummy.bucket_count();
510 }
511
512 // We use a unique_ptr<> because of the above: we couldn't immediately initialize this map.
513 m_keys_into_list_map.reset(new Key_to_value_iter_map(n_buckets, hasher_instance, key_equal_instance));
514
515 // Now link each key in the quick-lookup table to its stored location in the ordering.
516 for (Value_list_iter value_list_it = m_value_list.begin(); value_list_it != m_value_list.end();
517 ++value_list_it)
518 {
519 // Note this sets (at key K) the value: iterator to K.
520 (*m_keys_into_list_map)[*value_list_it] = value_list_it;
521 }
522}
523
524template<typename Key, typename Hash, typename Pred>
526 m_keys_into_list_map(new Key_to_value_iter_map()) // Dummy: all this is quickly replaced.
527{
528 operator=(src);
529}
530
531template<typename Key, typename Hash, typename Pred>
533 m_keys_into_list_map(new Key_to_value_iter_map()) // Dummy: all this is quickly replaced.
534{
535 operator=(std::move(src));
536}
537
538template<typename Key, typename Hash, typename Pred>
541{
542 // See Linked_hash_map equivalent method, to which this is analogous. Keeping comments here light.
543
544 if (&src == this)
545 {
546 return *this;
547 }
548 // else
549
550 {
551 using std::pair;
552 using std::list;
553
554 using Mutable_key_list = list<Key>;
555
556 Mutable_key_list* const dst_list_ptr
557 = reinterpret_cast<Mutable_key_list*>(&m_value_list);
558 const Mutable_key_list* const src_list_ptr
559 = reinterpret_cast<const Mutable_key_list*>(&src.m_value_list);
560
561 *dst_list_ptr = *src_list_ptr;
562 }
563
564 *m_keys_into_list_map = *src.m_keys_into_list_map;
565
566 // So now replace the keys in the ready map.
567 for (Value_list_iter value_list_it = m_value_list.begin(); value_list_it != m_value_list.end();
568 ++value_list_it)
569 {
570 // Note this sets (at key K) the value: iterator to K.
571 (*m_keys_into_list_map)[*value_list_it] = value_list_it;
572 }
573
574 return *this;
575} // Linked_hash_set::operator=()
576
577template<typename Key, typename Hash, typename Pred>
580{
581 if (&src != this)
582 {
583 clear();
584 swap(src);
585 }
586 return *this;
587}
588
589template<typename Key, typename Hash, typename Pred>
590std::pair<typename Linked_hash_set<Key, Hash, Pred>::Iterator, bool>
592{
593 // See Linked_hash_map equivalent method, to which this is analogous. Keeping comments here light.
594
595 using std::pair;
596
597 typename Key_to_value_iter_map::iterator const map_it = m_keys_into_list_map->find(key);
598 if (map_it != m_keys_into_list_map->end())
599 {
600 return pair<Iterator, bool>(map_it->second, false);
601 }
602 return pair<Iterator, bool>(insert_impl(key), true);
603}
604
605template<typename Key, typename Hash, typename Pred>
608{
609 // See Linked_hash_map equivalent method, to which this is analogous. Keeping comments here light.
610
611 m_value_list.push_front(key);
612 Iterator const new_elem_it = m_value_list.begin();
613 (*m_keys_into_list_map)[key] = new_elem_it;
614
615 return new_elem_it;
616}
617
618template<typename Key, typename Hash, typename Pred>
621{
622 typename Key_to_value_iter_map::const_iterator const map_it = m_keys_into_list_map->find(key);
623 return (map_it == m_keys_into_list_map->cend()) ? m_value_list.cend() : map_it->second;
624}
625
626template<typename Key, typename Hash, typename Pred>
629{
630 return m_keys_into_list_map->count(key);
631}
632
633template<typename Key, typename Hash, typename Pred>
636{
637 // No assert(): we promised not to crash even if empty(). They just can't access it subsequently if so.
638 return *(const_newest());
639}
640
641template<typename Key, typename Hash, typename Pred>
644{
645 // No assert(): we promised not to crash even if empty(). They just can't access it subsequently if so.
646 return *(--const_past_oldest());
647}
648
649template<typename Key, typename Hash, typename Pred>
651{
652 m_value_list.splice(m_value_list.begin(), m_value_list, it);
653}
654
655template<typename Key, typename Hash, typename Pred>
657{
658 const Iterator it = find(key);
659 if (it == end())
660 {
661 return false;
662 }
663 // else
664
665 touch(it);
666 return true;
667}
668
669template<typename Key, typename Hash, typename Pred>
672{
673 m_keys_into_list_map->erase(m_keys_into_list_map->find(*it));
674 return m_value_list.erase(it);
675}
676
677template<typename Key, typename Hash, typename Pred>
680 Const_iterator const & it_past_oldest)
681{
682 for (Value_list_const_iter it = it_newest; it != it_past_oldest; ++it)
683 {
684 m_keys_into_list_map->erase(it->first);
685 }
686
687 return m_value_list.erase(it_newest, it_past_oldest);
688}
689
690template<typename Key, typename Hash, typename Pred>
693{
694 typename Key_to_value_iter_map::iterator const map_it = m_keys_into_list_map->find(key);
695 if (map_it == m_keys_into_list_map->end())
696 {
697 return 0;
698 }
699 // else
700
701 m_value_list.erase(map_it->second);
702 m_keys_into_list_map->erase(map_it);
703
704 return 1;
705}
706
707template<typename Key, typename Hash, typename Pred>
709{
710 assert(!empty());
711 erase(const_newest());
712}
713
714template<typename Key, typename Hash, typename Pred>
716{
717 assert(!empty());
718 erase(--const_past_oldest());
719}
720
721template<typename Key, typename Hash, typename Pred>
723{
724 m_keys_into_list_map->clear();
725 m_value_list.clear();
726}
727
728template<typename Key, typename Hash, typename Pred>
730{
731 using std::swap;
732
733 swap(m_keys_into_list_map, other.m_keys_into_list_map); // unique_ptr<>s exchanged (= raw pointers exchanged).
734 swap(m_value_list, other.m_value_list); // list<> exchange (probably = head+tail pointer pairs exchanged).
735 // Per cppreference.com `list<>::iterator`s (inside the `_maps`s) remain valid after list<>s swapped.
736}
737
738template<typename Key, typename Hash, typename Pred>
741{
742 return m_value_list.cbegin();
743}
744
745template<typename Key, typename Hash, typename Pred>
748{
749 return newest(); // For us Iterator = Const_iterator.
750}
751
752template<typename Key, typename Hash, typename Pred>
755{
756 return newest();
757}
758
759template<typename Key, typename Hash, typename Pred>
762{
763 return begin(); // For us Iterator = Const_iterator.
764}
765
766template<typename Key, typename Hash, typename Pred>
769{
770 return m_value_list.cend();
771}
772
773template<typename Key, typename Hash, typename Pred>
776{
777 return past_oldest(); // For us Iterator = Const_iterator.
778}
779
780template<typename Key, typename Hash, typename Pred>
783{
784 return past_oldest();
785}
786
787template<typename Key, typename Hash, typename Pred>
790{
791 return end(); // For us Iterator = Const_iterator.
792}
793
794template<typename Key, typename Hash, typename Pred>
797{
798 return m_value_list.crbegin();
799}
800
801template<typename Key, typename Hash, typename Pred>
804{
805 return oldest(); // For us Iterator = Const_iterator.
806}
807
808template<typename Key, typename Hash, typename Pred>
811{
812 return oldest();
813}
814
815template<typename Key, typename Hash, typename Pred>
818{
819 return rbegin(); // For us Reverse_iterator = Const_reverse_iterator.
820}
821
822template<typename Key, typename Hash, typename Pred>
825{
826 return m_value_list.crend(); // For us Reverse_iterator = Const_reverse_iterator.
827}
828
829template<typename Key, typename Hash, typename Pred>
832{
833 return past_newest(); // For us Reverse_iterator = Const_reverse_iterator.
834}
835
836template<typename Key, typename Hash, typename Pred>
839{
840 return past_newest();
841}
842
843template<typename Key, typename Hash, typename Pred>
846{
847 return m_value_list.rend(); // For us Reverse_iterator = Const_reverse_iterator.
848}
849
850template<typename Key, typename Hash, typename Pred>
853{
854 return m_keys_into_list_map->size(); // I'm skeptical/terrified of list::size()'s time complexity.
855}
856
857template<typename Key, typename Hash, typename Pred>
859{
860 return m_keys_into_list_map->empty();
861}
862
863template<typename Key, typename Hash, typename Pred>
866{
867 return std::min(m_keys_into_list_map->max_size(), m_value_list.max_size());
868}
869
870template<typename Key, typename Hash, typename Pred>
872{
873 val1.swap(val2);
874}
875
876} // namespace flow::util
877
An object of this class is a set that combines the lookup speed of an unordered_set<> and ordering an...
bool empty() const
Returns true if and only if container is empty.
Const_iterator const_past_oldest() const
Returns one past last, a/k/a "oldest," element's iterator (to immutable element).
Const_iterator const_iterator
For container compliance (hence the irregular capitalization): Const_iterator type.
Iterator insert_impl(Value const &key)
Helper that modifies m_value_list and m_keys_into_list_map so that key's copy is inserted into the st...
Key key_type
For container compliance (hence the irregular capitalization): Key type.
Iterator begin() const
Synonym of newest().
Const_reverse_iterator const_past_newest() const
Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element).
std::ptrdiff_t difference_type
Type for difference of size_types.
Const_iterator cend() const
Synonym of const_past_oldest().
Linked_hash_set(Linked_hash_set const &src)
Constructs object that is a copy of the given source.
Iterator erase(Const_iterator const &it_newest, Const_iterator const &it_past_oldest)
Erases all elements in the range [it_newest, it_past_oldest).
Const_iterator Iterator
Type for iterator pointing into a mutable structure of this type but actually that is not possible; s...
Iterator Value_list_iter
Short-hand for iterator into doubly linked list of Key elements.
Value const & const_reference
For container compliance (hence the irregular capitalization): reference to const Key type.
Const_iterator Value_list_const_iter
Short-hand for const iterator into doubly linked list of Key elements.
Pred key_equal
For container compliance (hence the irregular capitalization): Pred type.
void swap(Linked_hash_set &other)
Swaps the contents of this structure and other.
Value value_type
For container compliance (hence the irregular capitalization): Value type.
Iterator erase(Const_iterator const &it)
Erases the element pointed to by the given valid iterator.
Value_list m_value_list
See Linked_hash_map::m_value_list. Essentially all of that applies here.
std::pair< Iterator, bool > insert(Value const &key)
Attempts to insert the given key into the set.
Hash hasher
For container compliance (hence the irregular capitalization): Hash type.
typename Value_list::const_iterator Const_iterator
Type for iterator pointing into an immutable structure of this type.
Key Value
Short-hand for values, which in this case are simply the keys.
std::size_t size_type
Type for index into array of items, where items are all applicable objects including Values and Keys.
Reverse_iterator oldest() const
Returns first, a/k/a "oldest," element's reverse iterator (to immutable element, due to nature of thi...
void touch(Const_iterator const &it)
Given a valid iterator into the structure, makes the pointed to element "newest" by moving it from wh...
Value & reference
For container compliance (hence the irregular capitalization): reference to Key type.
Value * pointer
For container compliance (hence the irregular capitalization): pointer to Key type.
Iterator end() const
Synonym of past_oldest().
Value const & const_back() const
Returns reference to immutable back ("oldest") element in the structure; formally equivalent to *(--t...
Reverse_iterator past_newest() const
Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element,...
Linked_hash_set(std::initializer_list< Value > values, size_type n_buckets=size_type(-1), Hash const &hasher_instance=Hash(), Pred const &key_equal_instance=Pred())
Constructs structure with some basic parameters, and values initialized from initializer list.
Const_reverse_iterator Reverse_iterator
Type for reverse iterator pointing into a mutable structure of this type but actually that is not pos...
void clear()
Makes it so that size() == 0.
void pop_front()
Queue-style pop (erase) of the front – a/k/a newest – element. Behavior undefined if empty().
Linked_hash_set & operator=(Linked_hash_set const &src)
Overwrites this object with a copy of the given source.
Const_iterator const_newest() const
Returns first, a/k/a "newest," element's iterator (to immutable element).
Reverse_iterator rend() const
Synonym of past_newest().
Value const & const_front() const
Returns reference to immutable front ("newest") element in the structure; formally equivalent to *(th...
Const_iterator find(Key const &key) const
Attempts to find the given key in the set.
size_type count(Key const &key) const
Returns the number of times a key is equivalent to the given one is present in the hash: either 1 or ...
Value const * const_pointer
For container compliance (hence the irregular capitalization): pointer to const Key type.
Const_reverse_iterator crbegin() const
Synonym of const_oldest().
typename Value_list::const_reverse_iterator Const_reverse_iterator
Type for reverse iterator pointing into an immutable structure of this type.
boost::movelib::unique_ptr< Key_to_value_iter_map > m_keys_into_list_map
See Linked_hash_map::m_keys_into_list_map. Essentially all of that applies here.
Const_iterator cbegin() const
Synonym of const_newest().
size_type erase(Key const &key)
Erases the element with the given key, if it exists.
Reverse_iterator rbegin() const
Synonym of oldest().
boost::unordered_map< Key, Value_list_iter, Hash, Pred > Key_to_value_iter_map
Short-hand for a hash map that maps Key to iterator into doubly linked list of Key elements.
void pop_back()
Queue-style pop (erase) of the back – a/k/a oldest – element. Behavior undefined if empty().
Iterator past_oldest() const
Returns one past last, a/k/a "oldest," element's iterator (to immutable element, due to nature of thi...
size_type max_size() const
Returns max number of elements that can be stored.
Iterator newest() const
Returns first, a/k/a "newest," element's iterator (to immutable element, due to nature of this type).
size_type size() const
Returns number of elements stored.
std::list< Value > Value_list
Short-hand for doubly linked list of Keys.
Iterator iterator
For container compliance (hence the irregular capitalization): Iterator type.
Const_reverse_iterator crend() const
Synonym of const_past_newest().
Linked_hash_set & operator=(Linked_hash_set &&src)
Overwrites this object making it equal to the given source, while the given source becomes as-if defa...
bool touch(Key const &key)
Given a key into the structure, makes the corresponding element "newest" by moving it from wherever i...
Const_reverse_iterator const_oldest() const
Returns first, a/k/a "oldest," element's reverse iterator (to immutable element).
Linked_hash_set(Linked_hash_set &&src)
Constructs object by making it equal to the given source, while the given source becomes as-if defaul...
Linked_hash_set(size_type n_buckets=size_type(-1), Hash const &hasher_instance=Hash(), Pred const &key_equal_instance=Pred())
Constructs empty structure with some basic parameters.
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
Definition: basic_blob.hpp:29
void swap(Basic_blob< Allocator, S_SHARING_ALLOWED > &blob1, Basic_blob< Allocator, S_SHARING_ALLOWED > &blob2, log::Logger *logger_ptr)
Equivalent to blob1.swap(blob2).
void swap(Linked_hash_set< Key, Hash, Pred > &val1, Linked_hash_set< Key, Hash, Pred > &val2)
Equivalent to val1.swap(val2).