Flow 3.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
23#include <cstddef>
24
25namespace flow::util
26{
27
28/**
29 * An object of this class is a set that combines the lookup speed of an `unordered_flat_set<>` and ordering and
30 * iterator stability capabilities of a `list<>`.
31 *
32 * This is just like Linked_hash_map, except it only stores keys -- no mapped values. All comments, except for
33 * self-explanatory differences, from Linked_hash_map apply here. Thus I will only speak of differences below to
34 * avoid duplication of this header. Incidentally the most visible API difference (aside from having no `Mapped`s
35 * to speak of, only `Key`s) is that Linked_hash_set lacks `(*this)[]` operator; so one always uses insert() to
36 * insert.
37 *
38 * Move semantics for keys are supported (let `x` be a `*this`):
39 * - `x.insert(std::move(a_key))`;
40 * - `x.insert(Key{...})`.
41 *
42 * The iterators are, really, `list<Key>` `const`-iterators; and as such are not invalidated except
43 * due to direct erasure of a given pointee.
44 *
45 * @internal
46 * ### Impl notes ###
47 * It's very much like Linked_hash_map; just the `list` #m_value_list stores only `Key`s as opposed to
48 * `pair<const Key, Mapped>`s. See Linked_hash_map.
49 * @endinternal
50 *
51 * @tparam Key_t
52 * Key type. Same as for Linked_hash_map.
53 * @tparam Hash_t
54 * Hasher type. Same as for Linked_hash_map.
55 * @tparam Pred_t
56 * Equality functor type. Same as for Linked_hash_map.
57 */
58template<typename Key_t, typename Hash_t, typename Pred_t>
60{
61public:
62 // Types.
63
64 /// Convenience alias for template arg.
65 using Key = Key_t;
66
67 /// Convenience alias for template arg.
68 using Hash = Hash_t;
69
70 /// Convenience alias for template arg.
71 using Pred = Pred_t;
72
73 /// Short-hand for values, which in this case are simply the keys.
74 using Value = Key;
75
76private:
77 // Types. These are here in the middle of public block due to inability to forward-declare aliases.
78
79 /// Short-hand for doubly linked list of `Key`s.
80 using Value_list = std::list<Value>;
81
82public:
83
84 // Types (continued).
85
86 /// Expresses sizes/lengths of relevant things.
87 using size_type = std::size_t;
88 /// Type for difference of `size_type`s.
89 using difference_type = std::ptrdiff_t;
90
91 /// Type for iterator pointing into an immutable structure of this type.
92 using Const_iterator = typename Value_list::const_iterator;
93
94 /**
95 * Type for iterator pointing into a mutable structure of this type but actually that is not possible;
96 * so alias to #Const_iterator. Note these are standard semantics (see `std::set`, etc.).
97 */
99
100 /// Type for reverse iterator pointing into an immutable structure of this type.
101 using Const_reverse_iterator = typename Value_list::const_reverse_iterator;
102
103 /**
104 * Type for reverse iterator pointing into a mutable structure of this type but actually that is not possible;
105 * so alias to #Const_reverse_iterator. Note these are standard semantics (see `std::set`, etc.).
106 */
108
109 /// For container compliance (hence the irregular capitalization): #Key type.
110 using key_type = Key;
111 /// For container compliance (hence the irregular capitalization): #Value type.
113 /// For container compliance (hence the irregular capitalization): #Hash type.
114 using hasher = Hash;
115 /// For container compliance (hence the irregular capitalization): #Pred type.
117 /// For container compliance (hence the irregular capitalization): pointer to #Key type.
118 using pointer = Value*;
119 /// For container compliance (hence the irregular capitalization): pointer to `const Key` type.
120 using const_pointer = const Value*;
121 /// For container compliance (hence the irregular capitalization): reference to #Key type.
122 using reference = Value&;
123 /// For container compliance (hence the irregular capitalization): reference to `const Key` type.
124 using const_reference = const Value&;
125 /// For container compliance (hence the irregular capitalization): `Iterator` type.
127 /// For container compliance (hence the irregular capitalization): `Const_iterator` type.
129
130 // Constructors/destructor.
131
132 /**
133 * Constructs empty structure with some basic parameters.
134 *
135 * @param n_buckets
136 * Number of buckets for the unordered (hash) table. Special value -1 (default) will cause us to use
137 * whatever `unordered_*set<>` would use by default.
138 * @param hasher_obj
139 * Instance of the hash function type (`hasher_obj(k) -> size_t` should be hash of `Key k`).
140 * @param pred
141 * Instance of the equality function type (`pred(k1, k2)` should return `true` if and
142 * only if the `Key`s are equal by value).
143 */
145 const Hash& hasher_obj = {},
146 const Pred& pred = {});
147
148 /**
149 * Constructs structure with some basic parameters, and values initialized from initializer list.
150 * The values are inserted as if `insert(v)` was called for each element `v` in `values`
151 * **in reverse order**. Since the canonical ordering places the *newest* (last inserted/`touch()`ed)
152 * element at the *front* of the ordering, that means that forward iteration through the set (right after this
153 * constructor runs) will yield values in the *same* order as in initializer list `values`.
154 *
155 * @param values
156 * Values with which to fill the structure after initializing it.
157 * Typically you'd provide a series of keys like this:
158 * `{ key1, key2, ... }`. They will appear in iterated sequence in the same order as
159 * they appear in this list.
160 * @param n_buckets
161 * See other constructor.
162 * @param hasher_obj
163 * See other constructor.
164 * @param pred
165 * See other constructor.
166 */
167 explicit Linked_hash_set(std::initializer_list<Value> values,
168 size_type n_buckets = size_type(-1),
169 const Hash& hasher_obj = {},
170 const Pred& pred = {});
171
172 /**
173 * Constructs object that is a copy of the given source. Equivalent to default-ction followed by `operator=(src)`.
174 *
175 * @param src
176 * Source object.
177 */
179
180 /**
181 * Constructs object by making it equal to the given source, while the given source becomes as-if default-cted.
182 * Equivalent to default-ction followed by `operator=(std::move(src))`.
183 *
184 * This is a constant-time operation.
185 *
186 * @param src
187 * Source object which is emptied.
188 */
190
191 // Methods.
192
193 /**
194 * Overwrites this object with a copy of the given source. We become equal to `src` but independent of it to a
195 * common-sense extent. In addition, the hasher instance and equality predicate are copied from `src`. Finally, a
196 * reasonable attempt is made to also make the internal structure of the hash map to be similar to that of `src`.
197 *
198 * @param src
199 * Source object. No-op if `this == &src`.
200 * @return `*this`.
201 */
203
204 /**
205 * Overwrites this object making it identical to the given source, while the given source becomes as-if default-cted.
206 *
207 * This is a constant-time operation, plus whatever is the cost of `this->clear()` (linear in pre-op `.size()`).
208 *
209 * @param src
210 * Source object which is emptied; except no-op if `this == &src`.
211 * @return `*this`.
212 */
214
215 /**
216 * Swaps the contents of this structure and `other`. This is a constant-time operation, as internal
217 * representations are swapped instead of any copy-assignment.
218 *
219 * @see The `swap()` free function.
220 * It is generally best (equivalent but covers more generic cases) to use the ADL-enabled `swap(a, b)`
221 * pattern instead of this member function. That is: `using std::swap; ...; swap(a, b);`.
222 * (Details are outside our scope here; but in short ADL will cause the right thing to happen.)
223 *
224 * @param other
225 * The other structure.
226 */
227 void swap(Linked_hash_set& other);
228
229 /**
230 * Attempts to insert (copying it) the given keyinto the map; if key
231 * already in `*this` makes no change. See also the overload which can avoid a copy and destructively move
232 * the key instead.
233 *
234 * Return value indicates various info of interest about what occurred or did not occur.
235 * If inserted, the new element is considered "newest," as if by touch(). If not inserted, the existing element
236 * location is not affected (use touch() upon consulting the return value, if this is desirable).
237 *
238 * @param key
239 * The key to attempt to insert. A copy of this value is placed in `*this`.
240 * @return A pair whose second element is true if and only if the insertion occurred; and whose first element
241 * is an iterator pointing to either the newly inserted element or already present one with a key equal to
242 * `key`.
243 */
244 std::pair<Iterator, bool> insert(const Key& key);
245
246 /**
247 * Identical to the other overload, except that (if key not already present in `*this`) the key
248 * is moved, not copied, into `*this`.
249 *
250 * @param key
251 * The key to attempt to insert (it is moved-from, if insertion occurs).
252 * @return See other overload.
253 */
254 std::pair<Iterator, bool> insert(Key&& key);
255
256 /**
257 * Attempts to find value at the given key in the map. Key presence is determined identically to how it would be
258 * done in an `unordered_*set<Key_t, Hash_t, Pred_t>`, with the particular #Hash and #Pred instances given to ctor
259 * (typically their default-cted instances, typically occupying no memory).
260 *
261 * The returned iterator (if valid) *cannot* be used to mutate the key inside the map.
262 *
263 * @param key
264 * Key whose equal to find.
265 * @return If found, iterator to the key/mapped-value pair with the equivalent key; else `this->end()`.
266 */
267 Const_iterator find(const Key& key) const;
268
269 /**
270 * Returns the number of times a key equal to the given one is present (as-if via find()) in the map: either 1 or 0.
271 *
272 * @param key
273 * Key whose equal to find.
274 * @return 0 or 1.
275 */
276 size_type count(const Key& key) const;
277
278 /**
279 * Given a valid iterator into the structure, makes the pointed-to element "newest" by moving it from wherever it
280 * is to be first in the iteration order. Behavior undefined if iterator invalid.
281 *
282 * The iterator continues to be valid.
283 *
284 * @param it
285 * Iterator to an element of the structure.
286 */
287 void touch(const Const_iterator& it);
288
289 /**
290 * Given a key into the structure, makes the corresponding element "newest" by moving it from wherever it
291 * is to be first in the iteration order; or does nothing if no such key. `find(key)` equivalent is performed
292 * first. Return value indicates whether it was found.
293 *
294 * @param key
295 * Key whose equal to find.
296 * @return `true` if the key was found (even if it was already "newest"); `false` if not found.
297 */
298 bool touch(const Key& key);
299
300 /**
301 * Erases the element pointed to by the given valid iterator. Behavior undefined if it is not valid. `it` becomes
302 * invalid.
303 *
304 * @param it
305 * Iterator of element to erase.
306 * @return Iterator one position past (i.e., "older") than `it`, before `*it` was removed.
307 */
309
310 /**
311 * Erases all elements in the range [`it_newest`, `it_past_oldest`). Behavior undefined if a given iterator is
312 * invalid, or if the range is invalid. Corner case: an empty range is allowed; then this no-ops. Unless no-op,
313 * `it_newest` becomes invalid.
314 *
315 * @param it_newest
316 * Iterator of first ("newest") element to erase.
317 * @param it_past_oldest
318 * Iterator of one past last ("oldest") element to erase.
319 * @return `it_past_oldest` copy.
320 */
321 Const_iterator erase(const Const_iterator& it_newest, const Const_iterator& it_past_oldest);
322
323 /**
324 * Erases the element with the given key, if it exists. `find(key)` equivalent is performed
325 * first. Return value indicates whether it existed.
326 *
327 * @param key
328 * Key such that its equal's (if found) element will be erased.
329 * @return Number of elements erased (0 or 1).
330 */
331 size_type erase(const Key& key);
332
333 /// Makes it so that `size() == 0`.
334 void clear();
335
336 /**
337 * Synonym of newest().
338 * @return See newest().
339 */
341
342 /**
343 * Returns first, a/k/a "newest," element's iterator (to immutable element, due to nature of this type).
344 * @return Ditto.
345 */
347
348 /**
349 * Synonym of past_oldest(). Exists as standard container method.
350 * @return See past_oldest().
351 */
352 Iterator end() const;
353
354 /**
355 * Returns one past last, a/k/a "oldest," element's iterator (to immutable element, due to nature of this type).
356 * @return Ditto.
357 */
359
360 /**
361 * Synonym of const_newest(). Exists as standard container method (hence the odd formatting).
362 * @return See const_newest().
363 */
365
366 /**
367 * Returns first, a/k/a "newest," element's iterator (to immutable element).
368 * @return Ditto.
369 */
371
372 /**
373 * Synonym of const_past_oldest(). Exists as standard container method (hence the odd formatting).
374 * @return See const_past_oldest().
375 */
377
378 /**
379 * Returns one past last, a/k/a "oldest," element's iterator (to immutable element).
380 * @return Ditto.
381 */
383
384 /**
385 * Synonym of oldest().
386 * @return See oldest().
387 */
389
390 /**
391 * Returns first, a/k/a "oldest," element's reverse iterator (to immutable element, due to nature of this type).
392 * @return Ditto.
393 */
395
396 /**
397 * Synonym of past_newest(). Exists as standard container method.
398 * @return See past_newest().
399 */
401
402 /**
403 * Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element, due
404 * to nature of this type).
405 * @return Ditto.
406 */
408
409 /**
410 * Synonym of const_oldest().
411 * @return See const_oldest().
412 */
414
415 /**
416 * Returns first, a/k/a "oldest," element's reverse iterator (to immutable element).
417 * @return Ditto.
418 */
420
421 /**
422 * Synonym of const_past_newest(). Exists as standard container method.
423 * @return See const_past_newest().
424 */
426
427 /**
428 * Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element).
429 * @return Ditto.
430 */
432
433 /**
434 * Returns true if and only if container is empty. Same performance as of a certain `unordered_*set<>`.
435 * @return Ditto.
436 */
437 bool empty() const;
438
439 /**
440 * Returns number of elements stored. Same performance as of a certain `unordered_*set<>`.
441 * @return Ditto.
442 */
444
445 /**
446 * Returns max number of elements that can be stored. Same performance as of a certain `unordered_*set<>` +
447 * `list<>`.
448 * @return Ditto.
449 */
451
452private:
453
454 // Data.
455
456 /// Analogous to Linked_hash_map::m_value_list; but simpler in that it just stores `Key`s, not pairs of (stuff).
458
459 /**
460 * Analogous to Linked_hash_map::m_value_iter_set; just configured to generate a simpler `.iter()` off each element
461 * by supplying `false` instead of `true` for the last template arg.
462 */
464}; // class Linked_hash_set
465
466// Free functions: in *_fwd.hpp.
467
468// Template implementations.
469
470template<typename Key_t, typename Hash_t, typename Pred_t>
472 const Hash& hasher_obj,
473 const Pred& pred) :
474 // (`Linked_hash_set({}, ...)` delegation preferred, but if Key uncopyable it won't compile.)
475 m_value_iter_set((n_buckets == size_type(-1)) ? LINKED_HASH_KEY_SET_DEFAULT_N_BUCKETS : n_buckets,
476 hasher_obj, pred)
477{
478 // That's all.
479}
480
481template<typename Key_t, typename Hash_t, typename Pred_t>
483 size_type n_buckets,
484 const Hash& hasher_obj,
485 const Pred& pred) :
486 // Their initializer_list is meant for a set of keys, but it is perfect for our list of keys.
487 m_value_list(values),
488 m_value_iter_set((n_buckets == size_type(-1)) ? LINKED_HASH_KEY_SET_DEFAULT_N_BUCKETS : n_buckets,
489 hasher_obj, pred)
490{
491 // Now link each key in the quick-lookup table to its stored location in the ordering.
492 const auto value_list_end_it = m_value_list.cend();
493 for (auto value_list_it = m_value_list.cbegin(); value_list_it != value_list_end_it; ++value_list_it)
494 {
495 // Note that value_list_it contains both the iterator (lookup result) and the lookup key (iterator pointee).
496 m_value_iter_set.insert(value_list_it);
497 }
498}
499
500template<typename Key_t, typename Hash_t, typename Pred_t>
502 // An empty m_value_iter_set is constructed here but immediately replaced within the {body}.
503{
504 operator=(src);
505}
506
507template<typename Key_t, typename Hash_t, typename Pred_t>
509 // An empty m_value_iter_set is constructed here but immediately replaced within the {body}.
510{
511 operator=(std::move(src));
512}
513
514template<typename Key_t, typename Hash_t, typename Pred_t>
517{
518 /* See Linked_hash_map equivalent method, to which this is analogous. Keeping comments here light.
519 * Though we don't have to do the reinterpret_cast<> thing; can just assign the list to src's counterpart;
520 * in our case Value is just Key -- no const-ness involved. */
521
522 using Value_iter_set = decltype(m_value_iter_set);
523
524 if (&src == this)
525 {
526 return *this;
527 }
528 // else
529
530 m_value_list = src.m_value_list;
531
532 const auto& src_value_iter_set = src.m_value_iter_set;
533 m_value_iter_set = Value_iter_set{src_value_iter_set.bucket_count(),
534 src_value_iter_set.hash_function(),
535 src_value_iter_set.key_eq()};
536
537 const auto value_list_end_it = m_value_list.cend();
538 for (auto value_list_it = m_value_list.cbegin(); value_list_it != value_list_end_it; ++value_list_it)
539 {
540 m_value_iter_set.insert(value_list_it);
541 }
542
543 return *this;
544} // Linked_hash_set::operator=()
545
546template<typename Key_t, typename Hash_t, typename Pred_t>
549{
550 if (&src != this)
551 {
552 clear();
553 swap(src);
554 }
555 return *this;
556}
557
558template<typename Key_t, typename Hash_t, typename Pred_t>
560{
561 using std::swap;
562
563 swap(m_value_iter_set, other.m_value_iter_set); // unordered_*set<> exchange; constant-time for sure at least.
564 swap(m_value_list, other.m_value_list); // list<> exchange (probably ~= head+tail pointer pairs exchanged).
565 // Per cppreference.com `list<>::iterator`s (inside the `_maps`s) remain valid after list<>s swapped.
566}
567
568template<typename Key_t, typename Hash_t, typename Pred_t>
569std::pair<typename Linked_hash_set<Key_t, Hash_t, Pred_t>::Iterator, bool>
571{
572 using std::pair;
573
574 const auto set_it = m_value_iter_set.find(key);
575 if (set_it != m_value_iter_set.end())
576 {
577 return pair<Iterator, bool>{set_it->iter(), false}; // *set_it is Linked_hash_key.
578 }
579 // else
580
581 /* Insert it at the front: as advertised, new element is "touched," meaning it is made "newest," so goes at start.
582 * Note that "it" = a copy of key; this invokes Key copy ctor, as emplace_front() forwards to it. */
583 m_value_list.emplace_front(key);
584
585 /* Iterator to the new element is therefore iterator to start of list of `Key`s.
586 * And make sure we can look it up in the future quickly (such as what is done above).
587 * Linked_hash_key_set m_value_iter_set achieves these aims black-boxily. */
588 const auto list_it = m_value_list.cbegin();
589 m_value_iter_set.insert(list_it);
590 return pair<Iterator, bool>{list_it, true};
591}
592
593template<typename Key_t, typename Hash_t, typename Pred_t>
594std::pair<typename Linked_hash_set<Key_t, Hash_t, Pred_t>::Iterator, bool>
596{
597 using std::pair;
598
599 // Same as other insert() but construct value in-place inside the list<> as-if: Key k2{move(k)}.
600
601 const auto set_it = m_value_iter_set.find(key);
602 if (set_it != m_value_iter_set.end())
603 {
604 return pair<Iterator, bool>{set_it->iter(), false}; // *set_it is Linked_hash_key.
605 }
606 // else
607
608 m_value_list.emplace_front(std::move(key)); // <-- The difference.
609
610 const auto list_it = m_value_list.cbegin();
611 m_value_iter_set.insert(list_it);
612 return pair<Iterator, bool>{list_it, true};
613}
614
615template<typename Key_t, typename Hash_t, typename Pred_t>
618{
619 const auto set_it = m_value_iter_set.find(key);
620 return (set_it == m_value_iter_set.cend()) ? m_value_list.cend() : set_it->iter();
621}
622
623template<typename Key_t, typename Hash_t, typename Pred_t>
626{
627 return m_value_iter_set.count(key);
628}
629
630template<typename Key_t, typename Hash_t, typename Pred_t>
632{
633 m_value_list.splice(m_value_list.begin(), m_value_list, it);
634}
635
636template<typename Key_t, typename Hash_t, typename Pred_t>
638{
639 const auto it = find(key);
640 if (it == end())
641 {
642 return false;
643 }
644 // else
645
646 touch(it);
647 return true;
648}
649
650template<typename Key_t, typename Hash_t, typename Pred_t>
653{
654 m_value_iter_set.erase(*it);
655 return m_value_list.erase(it);
656}
657
658template<typename Key_t, typename Hash_t, typename Pred_t>
661{
662 for (auto it = it_newest; it != it_past_oldest; ++it)
663 {
664 m_value_iter_set.erase(*it);
665 }
666
667 return m_value_list.erase(it_newest, it_past_oldest);
668}
669
670template<typename Key_t, typename Hash_t, typename Pred_t>
673{
674 const auto set_it = m_value_iter_set.find(key);
675 if (set_it == m_value_iter_set.end())
676 {
677 return 0;
678 }
679 // else
680
681 const auto list_it = set_it->iter();
682 m_value_iter_set.erase(set_it);
683 m_value_list.erase(list_it);
684
685 return 1;
686}
687
688template<typename Key_t, typename Hash_t, typename Pred_t>
690{
691 m_value_iter_set.clear();
692 m_value_list.clear();
693}
694
695template<typename Key_t, typename Hash_t, typename Pred_t>
698{
699 return m_value_list.cbegin();
700}
701
702template<typename Key_t, typename Hash_t, typename Pred_t>
705{
706 return newest(); // For us Iterator = Const_iterator.
707}
708
709template<typename Key_t, typename Hash_t, typename Pred_t>
712{
713 return newest();
714}
715
716template<typename Key_t, typename Hash_t, typename Pred_t>
719{
720 return begin(); // For us Iterator = Const_iterator.
721}
722
723template<typename Key_t, typename Hash_t, typename Pred_t>
726{
727 return m_value_list.cend();
728}
729
730template<typename Key_t, typename Hash_t, typename Pred_t>
733{
734 return past_oldest(); // For us Iterator = Const_iterator.
735}
736
737template<typename Key_t, typename Hash_t, typename Pred_t>
740{
741 return past_oldest();
742}
743
744template<typename Key_t, typename Hash_t, typename Pred_t>
747{
748 return end(); // For us Iterator = Const_iterator.
749}
750
751template<typename Key_t, typename Hash_t, typename Pred_t>
754{
755 return m_value_list.crbegin();
756}
757
758template<typename Key_t, typename Hash_t, typename Pred_t>
761{
762 return oldest(); // For us Iterator = Const_iterator.
763}
764
765template<typename Key_t, typename Hash_t, typename Pred_t>
768{
769 return oldest();
770}
771
772template<typename Key_t, typename Hash_t, typename Pred_t>
775{
776 return rbegin(); // For us Reverse_iterator = Const_reverse_iterator.
777}
778
779template<typename Key_t, typename Hash_t, typename Pred_t>
782{
783 return m_value_list.crend(); // For us Reverse_iterator = Const_reverse_iterator.
784}
785
786template<typename Key_t, typename Hash_t, typename Pred_t>
789{
790 return past_newest(); // For us Reverse_iterator = Const_reverse_iterator.
791}
792
793template<typename Key_t, typename Hash_t, typename Pred_t>
796{
797 return past_newest();
798}
799
800template<typename Key_t, typename Hash_t, typename Pred_t>
803{
804 return m_value_list.rend(); // For us Reverse_iterator = Const_reverse_iterator.
805}
806
807template<typename Key_t, typename Hash_t, typename Pred_t>
810{
811 return m_value_iter_set.size(); // I'm skeptical/terrified of list::size()'s time complexity.
812}
813
814template<typename Key_t, typename Hash_t, typename Pred_t>
816{
817 return m_value_list.empty();
818}
819
820template<typename Key_t, typename Hash_t, typename Pred_t>
823{
824 return std::min(m_value_iter_set.max_size(), m_value_list.max_size());
825}
826
827template<typename Key_t, typename Hash_t, typename Pred_t>
829{
830 val1.swap(val2);
831}
832
833} // namespace flow::util
An object of this class is a set that combines the lookup speed of an unordered_flat_set<> and orderi...
Hash hasher
For container compliance (hence the irregular capitalization): Hash type.
Value * pointer
For container compliance (hence the irregular capitalization): pointer to Key type.
Linked_hash_set(const Linked_hash_set &src)
Constructs object that is a copy of the given source.
Const_iterator cbegin() const
Synonym of const_newest().
Const_reverse_iterator const_oldest() const
Returns first, a/k/a "oldest," element's reverse iterator (to immutable element).
Pred_t Pred
Convenience alias for template arg.
void swap(Linked_hash_set &other)
Swaps the contents of this structure and other.
Linked_hash_set & operator=(Linked_hash_set &&src)
Overwrites this object making it identical to the given source, while the given source becomes as-if ...
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.
bool empty() const
Returns true if and only if container is empty.
Value value_type
For container compliance (hence the irregular capitalization): Value type.
Reverse_iterator rend() const
Synonym of past_newest().
std::pair< Iterator, bool > insert(const Key &key)
Attempts to insert (copying it) the given keyinto the map; if key already in *this makes no change.
std::size_t size_type
Expresses sizes/lengths of relevant things.
Const_iterator erase(const Const_iterator &it)
Erases the element pointed to by the given valid iterator.
Linked_hash_set & operator=(const Linked_hash_set &src)
Overwrites this object with a copy of the given source.
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...
Const_reverse_iterator const_past_newest() const
Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element).
size_type size() const
Returns number of elements stored.
Linked_hash_set(size_type n_buckets=size_type(-1), const Hash &hasher_obj={}, const Pred &pred={})
Constructs empty structure with some basic parameters.
std::pair< Iterator, bool > insert(Key &&key)
Identical to the other overload, except that (if key not already present in *this) the key is moved,...
Reverse_iterator rbegin() const
Synonym of oldest().
Const_iterator const_past_oldest() const
Returns one past last, a/k/a "oldest," element's iterator (to immutable element).
Const_iterator cend() const
Synonym of const_past_oldest().
Pred key_equal
For container compliance (hence the irregular capitalization): Pred type.
Key Value
Short-hand for values, which in this case are simply the keys.
const Value * const_pointer
For container compliance (hence the irregular capitalization): pointer to const Key type.
void touch(const Const_iterator &it)
Given a valid iterator into the structure, makes the pointed-to element "newest" by moving it from wh...
typename Value_list::const_reverse_iterator Const_reverse_iterator
Type for reverse iterator pointing into an immutable structure of this type.
Const_iterator const_newest() const
Returns first, a/k/a "newest," element's iterator (to immutable element).
Const_iterator const_iterator
For container compliance (hence the irregular capitalization): Const_iterator type.
Iterator begin() const
Synonym of newest().
Reverse_iterator oldest() const
Returns first, a/k/a "oldest," element's reverse iterator (to immutable element, due to nature of thi...
size_type erase(const Key &key)
Erases the element with the given key, if it exists.
Const_iterator erase(const Const_iterator &it_newest, const Const_iterator &it_past_oldest)
Erases all elements in the range [it_newest, it_past_oldest).
Key key_type
For container compliance (hence the irregular capitalization): Key type.
Iterator past_oldest() const
Returns one past last, a/k/a "oldest," element's iterator (to immutable element, due to nature of thi...
Const_iterator Iterator
Type for iterator pointing into a mutable structure of this type but actually that is not possible; s...
size_type count(const Key &key) const
Returns the number of times a key equal to the given one is present (as-if via find()) in the map: ei...
Key_t Key
Convenience alias for template arg.
size_type max_size() const
Returns max number of elements that can be stored.
const Value & const_reference
For container compliance (hence the irregular capitalization): reference to const Key type.
typename Value_list::const_iterator Const_iterator
Type for iterator pointing into an immutable structure of this type.
Hash_t Hash
Convenience alias for template arg.
Linked_hash_set(std::initializer_list< Value > values, size_type n_buckets=size_type(-1), const Hash &hasher_obj={}, const Pred &pred={})
Constructs structure with some basic parameters, and values initialized from initializer list.
Iterator iterator
For container compliance (hence the irregular capitalization): Iterator type.
Const_iterator find(const Key &key) const
Attempts to find value at the given key in the map.
Iterator newest() const
Returns first, a/k/a "newest," element's iterator (to immutable element, due to nature of this type).
std::list< Value > Value_list
Short-hand for doubly linked list of Keys.
Value_list m_value_list
Analogous to Linked_hash_map::m_value_list; but simpler in that it just stores Keys,...
std::ptrdiff_t difference_type
Type for difference of size_types.
Const_reverse_iterator crend() const
Synonym of const_past_newest().
Iterator end() const
Synonym of past_oldest().
bool touch(const Key &key)
Given a key into the structure, makes the corresponding element "newest" by moving it from wherever i...
Reverse_iterator past_newest() const
Returns one past last, a/k/a "newest," element's reverse iterator (to immutable element,...
Linked_hash_key_set< Key, Iterator, Hash, Pred, false > m_value_iter_set
Analogous to Linked_hash_map::m_value_iter_set; just configured to generate a simpler ....
Value & reference
For container compliance (hence the irregular capitalization): reference to Key type.
Const_reverse_iterator crbegin() const
Synonym of const_oldest().
Flow module containing miscellaneous general-use facilities that don't fit into any other Flow module...
constexpr size_t LINKED_HASH_KEY_SET_DEFAULT_N_BUCKETS
Value used by alias-target type of Linked_hash_key_set as the default hash bucket count,...
Definition: util_fwd.hpp:106
void swap(Basic_blob< Allocator_t, SHARING > &blob1, Basic_blob< Allocator_t, SHARING > &blob2, log::Logger *logger_ptr) noexcept
Equivalent to blob1.swap(blob2).
void swap(Linked_hash_set< Key_t, Hash_t, Pred_t > &val1, Linked_hash_set< Key_t, Hash_t, Pred_t > &val2)
Equivalent to val1.swap(val2).