xrpld
Loading...
Searching...
No Matches
aged_unordered_container.h
1#pragma once
2
3#include <xrpl/beast/clock/abstract_clock.h>
4#include <xrpl/beast/container/aged_container.h>
5#include <xrpl/beast/container/detail/aged_associative_container.h>
6#include <xrpl/beast/container/detail/aged_container_iterator.h>
7#include <xrpl/beast/container/detail/empty_base_optimization.h>
8#include <xrpl/beast/utility/instrumentation.h>
9
10#include <boost/intrusive/list.hpp>
11#include <boost/intrusive/unordered_set.hpp>
12
13#include <algorithm>
14#include <chrono>
15#include <cmath>
16#include <cstddef>
17#include <cstdint>
18#include <functional>
19#include <initializer_list>
20#include <iterator>
21#include <memory>
22#include <stdexcept>
23#include <tuple>
24#include <type_traits>
25#include <utility>
26#include <vector>
27
28/*
29
30TODO
31
32- Add constructor variations that take a bucket count
33
34- Review for noexcept and exception guarantees
35
36- Call the safe version of is_permutation that takes 4 iterators
37
38*/
39
40#ifndef BEAST_NO_CXX14_IS_PERMUTATION
41#define BEAST_NO_CXX14_IS_PERMUTATION 1
42#endif
43
44namespace beast {
45namespace detail {
46
65template <
66 bool IsMulti,
67 bool IsMap,
68 class Key,
69 class T,
70 class Clock = std::chrono::steady_clock,
71 class Hash = std::hash<Key>,
72 class KeyEqual = std::equal_to<Key>,
73 class Allocator = std::allocator<std::conditional_t<IsMap, std::pair<Key const, T>, Key>>>
75{
76public:
80 using key_type = Key;
81 using mapped_type = T;
85
86 // Introspection (for unit tests)
90
91private:
92 static Key const&
93 extract(value_type const& value)
94 {
96 }
97
98 // VFALCO TODO hoist to remove template argument dependencies
99 struct Element : boost::intrusive::unordered_set_base_hook<
100 boost::intrusive::link_mode<boost::intrusive::normal_link>>,
101 boost::intrusive::list_base_hook<
102 boost::intrusive::link_mode<boost::intrusive::normal_link>>
103 {
104 // Stash types here so the iterator doesn't
105 // need to see the container declaration.
113
115 {
116 }
117
119 {
120 }
121
122 template <class... Args>
123 Element(time_point const& when, Args&&... args)
124 requires(std::is_constructible_v<value_type, Args...>)
125 : value(std::forward<Args>(args)...), when(when)
126 {
127 }
128
131 };
132
133 // VFALCO TODO hoist to remove template argument dependencies
134 class ValueHash : public Hash
135 {
136 public:
138 using result_type = size_t;
139
140 ValueHash() = default;
141
142 ValueHash(Hash const& h) : Hash(h)
143 {
144 }
145
147 operator()(Element const& e) const
148 {
149 return Hash::operator()(extract(e.value));
150 }
151
152 Hash&
154 {
155 return *this;
156 }
157
158 [[nodiscard]] Hash const&
160 {
161 return *this;
162 }
163 };
164
165 // Compares value_type against element, used in find/insert_check
166 // VFALCO TODO hoist to remove template argument dependencies
167 class KeyValueEqual : public KeyEqual
168 {
169 public:
172 using result_type = bool;
173
174 KeyValueEqual() = default;
175
176 KeyValueEqual(KeyEqual const& keyEqual) : KeyEqual(keyEqual)
177 {
178 }
179
180 bool
181 operator()(Key const& k, Element const& e) const
182 {
183 return KeyEqual::operator()(k, extract(e.value));
184 }
185
186 bool
187 operator()(Element const& e, Key const& k) const
188 {
189 return KeyEqual::operator()(extract(e.value), k);
190 }
191
192 bool
193 operator()(Element const& lhs, Element const& rhs) const
194 {
195 return KeyEqual::operator()(extract(lhs.value), extract(rhs.value));
196 }
197
198 KeyEqual&
200 {
201 return *this;
202 }
203
204 [[nodiscard]] KeyEqual const&
205 keyEq() const
206 {
207 return *this;
208 }
209 };
210
211 using list_type =
212 boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
213
215 IsMulti,
216 typename boost::intrusive::make_unordered_multiset<
217 Element,
218 boost::intrusive::constant_time_size<true>,
219 boost::intrusive::hash<ValueHash>,
220 boost::intrusive::equal<KeyValueEqual>,
221 boost::intrusive::cache_begin<true>>::type,
222 typename boost::intrusive::make_unordered_set<
223 Element,
224 boost::intrusive::constant_time_size<true>,
225 boost::intrusive::hash<ValueHash>,
226 boost::intrusive::equal<KeyValueEqual>,
227 boost::intrusive::cache_begin<true>>::type>;
228
229 using bucket_type = cont_type::bucket_type;
230 using bucket_traits = cont_type::bucket_traits;
231
233
235
237
239
240 class ConfigT : private ValueHash,
241 private KeyValueEqual,
242 private beast::detail::EmptyBaseOptimization<ElementAllocator>
243 {
244 public:
246 {
247 }
248
249 ConfigT(clock_type& clock, Hash const& hash) : ValueHash(hash), clock(clock)
250 {
251 }
252
253 ConfigT(clock_type& clock, KeyEqual const& keyEqual) : KeyValueEqual(keyEqual), clock(clock)
254 {
255 }
256
261
262 ConfigT(clock_type& clock, Hash const& hash, KeyEqual const& keyEqual)
263 : ValueHash(hash), KeyValueEqual(keyEqual), clock(clock)
264 {
265 }
266
267 ConfigT(clock_type& clock, Hash const& hash, Allocator const& alloc)
268 : ValueHash(hash)
270 , clock(clock)
271 {
272 }
273
274 ConfigT(clock_type& clock, KeyEqual const& keyEqual, Allocator const& alloc)
275 : KeyValueEqual(keyEqual)
277 , clock(clock)
278 {
279 }
280
283 Hash const& hash,
284 KeyEqual const& keyEqual,
285 Allocator const& alloc)
286 : ValueHash(hash)
287 , KeyValueEqual(keyEqual)
289 , clock(clock)
290 {
291 }
292
293 ConfigT(ConfigT const& other)
294 : ValueHash(other.hashFunction())
295 , KeyValueEqual(other.keyEq())
297 ElementAllocatorTraits::select_on_container_copy_construction(other.alloc()))
298 , clock(other.clock)
299 {
300 }
301
302 ConfigT(ConfigT const& other, Allocator const& alloc)
303 : ValueHash(other.hashFunction())
304 , KeyValueEqual(other.keyEq())
306 , clock(other.clock)
307 {
308 }
309
311 : ValueHash(std::move(other.hashFunction()))
312 , KeyValueEqual(std::move(other.keyEq()))
314 , clock(other.clock)
315 {
316 }
317
319 ConfigT&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
320 Allocator const& alloc)
321 : ValueHash(std::move(other.hashFunction()))
322 , KeyValueEqual(std::move(other.keyEq()))
324 , clock(other.clock)
325 {
326 }
327
328 ConfigT&
329 operator=(ConfigT const& other)
330 {
331 hashFunction() = other.hashFunction();
332 keyEq() = other.keyEq();
333 alloc() = other.alloc();
334 clock = other.clock;
335 return *this;
336 }
337
338 ConfigT&
340 {
341 hashFunction() = std::move(other.hashFunction());
342 keyEq() = std::move(other.keyEq());
343 alloc() = std::move(other.alloc());
344 clock = other.clock;
345 return *this;
346 }
347
348 ValueHash&
350 {
351 return *this;
352 }
353
354 [[nodiscard]] ValueHash const&
355 valueHash() const
356 {
357 return *this;
358 }
359
360 Hash&
362 {
364 }
365
366 [[nodiscard]] Hash const&
368 {
370 }
371
374 {
375 return *this;
376 }
377
378 [[nodiscard]] KeyValueEqual const&
380 {
381 return *this;
382 }
383
384 KeyEqual&
386 {
387 return keyValueEqual().keyEq();
388 }
389
390 [[nodiscard]] KeyEqual const&
391 keyEq() const
392 {
393 return keyValueEqual().keyEq();
394 }
395
401
402 [[nodiscard]] ElementAllocator const&
407
409 };
410
412 {
413 public:
416 typename std::allocator_traits<Allocator>::template rebind_alloc<bucket_type>>;
417
419 {
420 vec_.resize(cont_type::suggested_upper_bucket_count(0));
421 }
422
423 Buckets(Allocator const& alloc) : maxLoadFactor_(1.f), vec_(alloc)
424 {
425 vec_.resize(cont_type::suggested_upper_bucket_count(0));
426 }
427
428 operator bucket_traits()
429 {
430 return bucket_traits(&vec_[0], vec_.size());
431 }
432
433 void
435 {
436 vec_.clear();
437 }
438
439 [[nodiscard]] size_type
441 {
442 return vec_.max_size();
443 }
444
445 float&
447 {
448 return maxLoadFactor_;
449 }
450
451 [[nodiscard]] float const&
453 {
454 return maxLoadFactor_;
455 }
456
457 // count is the number of buckets
458 template <class Container>
459 void
460 rehash(size_type count, Container& c)
461 {
462 size_type const size(vec_.size());
463 if (count == size)
464 return;
465 if (count > vec_.capacity())
466 {
467 // Need two vectors otherwise we
468 // will destroy non-empty buckets.
469 vec_type vec(vec_.get_allocator());
470 std::swap(vec_, vec);
471 vec_.resize(count);
472 c.rehash(bucket_traits(&vec_[0], vec_.size()));
473 return;
474 }
475 // Rehash in place.
476 if (count > size)
477 {
478 // This should not reallocate since
479 // we checked capacity earlier.
480 vec_.resize(count);
481 c.rehash(bucket_traits(&vec_[0], count));
482 return;
483 }
484 // Resize must happen after rehash otherwise
485 // we might destroy non-empty buckets.
486 c.rehash(bucket_traits(&vec_[0], count));
487 vec_.resize(count);
488 }
489
490 // Resize the buckets to accommodate at least n items.
491 template <class Container>
492 void
493 resize(size_type n, Container& c)
494 {
495 size_type const suggested(cont_type::suggested_upper_bucket_count(n));
496 rehash(suggested, c);
497 }
498
499 private:
502 };
503
504 template <class... Args>
505 Element*
506 newElement(Args&&... args)
507 {
508 struct Deleter
509 {
511 Deleter(ElementAllocator& a) : a(a)
512 {
513 }
514
515 void
516 operator()(Element* p)
517 {
519 }
520 };
521
523 ElementAllocatorTraits::allocate(config_.alloc(), 1), Deleter(config_.alloc()));
525 config_.alloc(), p.get(), clock().now(), std::forward<Args>(args)...);
526 return p.release();
527 }
528
529 void
530 deleteElement(Element const* p)
531 {
533 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
534 ElementAllocatorTraits::deallocate(config_.alloc(), const_cast<Element*>(p), 1);
535 }
536
537 void
538 unlinkAndDeleteElement(Element const* p)
539 {
540 chronological.list_.erase(chronological.list_.iterator_to(*p));
541 cont_.erase(cont_.iterator_to(*p));
542 deleteElement(p);
543 }
544
545public:
546 using hasher = Hash;
547 using key_equal = KeyEqual;
548 using allocator_type = Allocator;
553
554 // A set iterator (IsMap==false) is always const
555 // because the elements of a set are immutable.
558
563
564 //--------------------------------------------------------------------------
565 //
566 // Chronological ordered iterators
567 //
568 // "Memberspace"
569 // http://accu.org/index.php/journals/1527
570 //
571 //--------------------------------------------------------------------------
572
574 {
575 public:
576 // A set iterator (IsMap==false) is always const
577 // because the elements of a set are immutable.
585
588 {
589 return iterator(list_.begin());
590 }
591
593 begin() const
594 {
595 return const_iterator(list_.begin());
596 }
597
599 cbegin() const
600 {
601 return const_iterator(list_.begin());
602 }
603
606 {
607 return iterator(list_.end());
608 }
609
611 end() const
612 {
613 return const_iterator(list_.end());
614 }
615
617 cend() const
618 {
619 return const_iterator(list_.end());
620 }
621
624 {
625 return reverse_iterator(list_.rbegin());
626 }
627
629 rbegin() const
630 {
631 return const_reverse_iterator(list_.rbegin());
632 }
633
635 crbegin() const
636 {
637 return const_reverse_iterator(list_.rbegin());
638 }
639
642 {
643 return reverse_iterator(list_.rend());
644 }
645
647 rend() const
648 {
649 return const_reverse_iterator(list_.rend());
650 }
651
653 crend() const
654 {
655 return const_reverse_iterator(list_.rend());
656 }
657
660 {
661 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
662 return list_.iterator_to(*reinterpret_cast<Element*>(
663 reinterpret_cast<uint8_t*>(&value) -
664 ((std::size_t)std::addressof(((Element*)0)->member))));
665 }
666
668 iteratorTo(value_type const& value) const
669 {
670 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
671 return list_.iterator_to(*reinterpret_cast<Element const*>(
672 reinterpret_cast<uint8_t const*>(&value) -
673 ((std::size_t)std::addressof(((Element*)0)->member))));
674 }
675
678 ChronologicalT() = default;
679
680 private:
684
685 //--------------------------------------------------------------------------
686 //
687 // Construction
688 //
689 //--------------------------------------------------------------------------
690
692
694
696
698
699 AgedUnorderedContainer(clock_type& clock, Allocator const& alloc);
700
701 AgedUnorderedContainer(clock_type& clock, Hash const& hash, KeyEqual const& keyEq);
702
703 AgedUnorderedContainer(clock_type& clock, Hash const& hash, Allocator const& alloc);
704
705 AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq, Allocator const& alloc);
706
709 Hash const& hash,
710 KeyEqual const& keyEq,
711 Allocator const& alloc);
712
713 template <class InputIt>
714 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock);
715
716 template <class InputIt>
717 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Hash const& hash);
718
719 template <class InputIt>
720 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, KeyEqual const& keyEq);
721
722 template <class InputIt>
723 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc);
724
725 template <class InputIt>
727 InputIt first,
728 InputIt last,
730 Hash const& hash,
731 KeyEqual const& keyEq);
732
733 template <class InputIt>
735 InputIt first,
736 InputIt last,
738 Hash const& hash,
739 Allocator const& alloc);
740
741 template <class InputIt>
743 InputIt first,
744 InputIt last,
746 KeyEqual const& keyEq,
747 Allocator const& alloc);
748
749 template <class InputIt>
751 InputIt first,
752 InputIt last,
754 Hash const& hash,
755 KeyEqual const& keyEq,
756 Allocator const& alloc);
757
759
760 AgedUnorderedContainer(AgedUnorderedContainer const& other, Allocator const& alloc);
761
763
765 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
767 Allocator const& alloc);
768
770
774 Hash const& hash);
775
779 KeyEqual const& keyEq);
780
784 Allocator const& alloc);
785
789 Hash const& hash,
790 KeyEqual const& keyEq);
791
795 Hash const& hash,
796 Allocator const& alloc);
797
801 KeyEqual const& keyEq,
802 Allocator const& alloc);
803
807 Hash const& hash,
808 KeyEqual const& keyEq,
809 Allocator const& alloc);
810
812
815
818
821
824 {
825 return config_.alloc();
826 }
827
830 {
831 return config_.clock;
832 }
833
834 clock_type const&
835 clock() const
836 {
837 return config_.clock;
838 }
839
840 //--------------------------------------------------------------------------
841 //
842 // Element access (maps)
843 //
844 //--------------------------------------------------------------------------
845
846 template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
848 at(K const& k)
849 requires(MaybeMap && !MaybeMulti);
850
851 template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
853 at(K const& k) const
854 requires(MaybeMap && !MaybeMulti);
855
856 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
858 operator[](Key const& key)
859 requires(MaybeMap && !MaybeMulti);
860
861 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
863 operator[](Key&& key)
864 requires(MaybeMap && !MaybeMulti);
865
866 //--------------------------------------------------------------------------
867 //
868 // Iterators
869 //
870 //--------------------------------------------------------------------------
871
874 {
875 return iterator(cont_.begin());
876 }
877
879 begin() const
880 {
881 return const_iterator(cont_.begin());
882 }
883
885 cbegin() const
886 {
887 return const_iterator(cont_.begin());
888 }
889
892 {
893 return iterator(cont_.end());
894 }
895
897 end() const
898 {
899 return const_iterator(cont_.end());
900 }
901
903 cend() const
904 {
905 return const_iterator(cont_.end());
906 }
907
910 {
911 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
912 return cont_.iterator_to(*reinterpret_cast<Element*>(
913 reinterpret_cast<uint8_t*>(&value) -
914 ((std::size_t)std::addressof(((Element*)0)->member))));
915 }
916
918 iteratorTo(value_type const& value) const
919 {
920 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
921 return cont_.iterator_to(*reinterpret_cast<Element const*>(
922 reinterpret_cast<uint8_t const*>(&value) -
923 ((std::size_t)std::addressof(((Element*)0)->member))));
924 }
925
926 //--------------------------------------------------------------------------
927 //
928 // Capacity
929 //
930 //--------------------------------------------------------------------------
931
932 bool
933 empty() const noexcept
934 {
935 return cont_.empty();
936 }
937
939 size() const noexcept
940 {
941 return cont_.size();
942 }
943
945 maxSize() const noexcept
946 {
947 return config_.max_size();
948 }
949
950 //--------------------------------------------------------------------------
951 //
952 // Modifiers
953 //
954 //--------------------------------------------------------------------------
955
956 void
958
959 // map, set
960 template <bool MaybeMulti = IsMulti>
961 auto
963 requires(!MaybeMulti);
964
965 // multimap, multiset
966 template <bool MaybeMulti = IsMulti>
967 auto
968 insert(value_type const& value) -> iterator
969 requires MaybeMulti;
970
971 // map, set
972 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
973 auto
975 requires(!MaybeMulti && !MaybeMap);
976
977 // multimap, multiset
978 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
979 auto
981 requires(MaybeMulti && !MaybeMap);
982
983 // map, set
984 template <bool MaybeMulti = IsMulti>
986 insert(const_iterator /*hint*/, value_type const& value)
987 requires(!MaybeMulti)
988 {
989 // Hint is ignored but we provide the interface so
990 // callers may use ordered and unordered interchangeably.
991 return insert(value).first;
992 }
993
994 // multimap, multiset
995 template <bool MaybeMulti = IsMulti>
997 insert(const_iterator /*hint*/, value_type const& value)
998 requires MaybeMulti
999 {
1000 // VFALCO TODO The hint could be used to let
1001 // the client order equal ranges
1002 return insert(value);
1003 }
1004
1005 // map, set
1006 template <bool MaybeMulti = IsMulti>
1007 iterator
1009 requires(!MaybeMulti)
1010 {
1011 // Hint is ignored but we provide the interface so
1012 // callers may use ordered and unordered interchangeably.
1013 return insert(std::move(value)).first;
1014 }
1015
1016 // multimap, multiset
1017 template <bool MaybeMulti = IsMulti>
1018 iterator
1020 requires MaybeMulti
1021 {
1022 // VFALCO TODO The hint could be used to let
1023 // the client order equal ranges
1024 return insert(std::move(value));
1025 }
1026
1027 // map, multimap
1028 template <class P, bool MaybeMap = IsMap>
1030 insert(P&& value)
1031 requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
1032 {
1033 return emplace(std::forward<P>(value));
1034 }
1035
1036 // map, multimap
1037 template <class P, bool MaybeMap = IsMap>
1039 insert(const_iterator hint, P&& value)
1040 requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
1041 {
1042 return emplaceHint(hint, std::forward<P>(value));
1043 }
1044
1045 template <class InputIt>
1046 void
1047 insert(InputIt first, InputIt last)
1048 {
1050 }
1051
1052 void
1054 {
1055 insert(init.begin(), init.end());
1056 }
1057
1058 // set, map
1059 template <bool MaybeMulti = IsMulti, class... Args>
1060 auto
1062 requires(!MaybeMulti);
1063
1064 // multiset, multimap
1065 template <bool MaybeMulti = IsMulti, class... Args>
1066 auto
1067 emplace(Args&&... args) -> iterator
1068 requires MaybeMulti;
1069
1070 // set, map
1071 template <bool MaybeMulti = IsMulti, class... Args>
1072 auto
1074 requires(!MaybeMulti);
1075
1076 // multiset, multimap
1077 template <bool MaybeMulti = IsMulti, class... Args>
1078 iterator
1079 emplaceHint(const_iterator /*hint*/, Args&&... args)
1080 requires MaybeMulti
1081 {
1082 // VFALCO TODO The hint could be used for multi, to let
1083 // the client order equal ranges
1084 return emplace<MaybeMulti>(std::forward<Args>(args)...);
1085 }
1086
1087 template <bool IsConst, class Iterator>
1090
1091 template <bool IsConst, class Iterator>
1096
1097 template <class K>
1098 auto
1099 erase(K const& k) -> size_type;
1100
1101 void
1103
1104 template <bool IsConst, class Iterator>
1105 void
1110
1111 template <class K>
1112 auto
1113 touch(K const& k) -> size_type;
1114
1115 //--------------------------------------------------------------------------
1116 //
1117 // Lookup
1118 //
1119 //--------------------------------------------------------------------------
1120
1121 // VFALCO TODO Respect is_transparent (c++14)
1122 template <class K>
1123 size_type
1124 count(K const& k) const
1125 {
1126 return cont_.count(
1127 k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()));
1128 }
1129
1130 // VFALCO TODO Respect is_transparent (c++14)
1131 template <class K>
1132 iterator
1133 find(K const& k)
1134 {
1135 return iterator(
1136 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1137 }
1138
1139 // VFALCO TODO Respect is_transparent (c++14)
1140 template <class K>
1142 find(K const& k) const
1143 {
1144 return const_iterator(
1145 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1146 }
1147
1148 // VFALCO TODO Respect is_transparent (c++14)
1149 template <class K>
1151 equalRange(K const& k)
1152 {
1153 auto const r(cont_.equal_range(
1154 k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1155 return std::make_pair(iterator(r.first), iterator(r.second));
1156 }
1157
1158 // VFALCO TODO Respect is_transparent (c++14)
1159 template <class K>
1161 equalRange(K const& k) const
1162 {
1163 auto const r(cont_.equal_range(
1164 k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1165 return std::make_pair(const_iterator(r.first), const_iterator(r.second));
1166 }
1167
1168 //--------------------------------------------------------------------------
1169 //
1170 // Bucket interface
1171 //
1172 //--------------------------------------------------------------------------
1173
1176 {
1177 return local_iterator(cont_.begin(n));
1178 }
1179
1182 {
1183 return const_local_iterator(cont_.begin(n));
1184 }
1185
1188 {
1189 return const_local_iterator(cont_.begin(n));
1190 }
1191
1194 {
1195 return local_iterator(cont_.end(n));
1196 }
1197
1200 {
1201 return const_local_iterator(cont_.end(n));
1202 }
1203
1206 {
1207 return const_local_iterator(cont_.end(n));
1208 }
1209
1210 size_type
1212 {
1213 return cont_.bucket_count();
1214 }
1215
1216 size_type
1218 {
1219 return buck_.maxBucketCount();
1220 }
1221
1222 size_type
1224 {
1225 return cont_.bucket_size(n);
1226 }
1227
1228 size_type
1229 bucket(Key const& k) const
1230 {
1231 XRPL_ASSERT(
1232 bucketCount() != 0,
1233 "beast::detail::AgedUnorderedContainer::bucket : nonzero bucket "
1234 "count");
1235 return cont_.bucket(k, std::cref(config_.hashFunction()));
1236 }
1237
1238 //--------------------------------------------------------------------------
1239 //
1240 // Hash policy
1241 //
1242 //--------------------------------------------------------------------------
1243
1244 float
1246 {
1247 return size() / static_cast<float>(cont_.bucket_count());
1248 }
1249
1250 float
1252 {
1253 return buck_.maxLoadFactor();
1254 }
1255
1256 void
1258 {
1259 buck_.maxLoadFactor() = std::max(ml, buck_.maxLoadFactor());
1260 }
1261
1262 void
1264 {
1266 buck_.rehash(count, cont_);
1267 }
1268
1269 void
1274
1275 //--------------------------------------------------------------------------
1276 //
1277 // Observers
1278 //
1279 //--------------------------------------------------------------------------
1280
1281 hasher const&
1283 {
1284 return config_.hashFunction();
1285 }
1286
1287 key_equal const&
1288 keyEq() const
1289 {
1290 return config_.keyEq();
1291 }
1292
1293 //--------------------------------------------------------------------------
1294 //
1295 // Comparison
1296 //
1297 //--------------------------------------------------------------------------
1298
1299 // This differs from the standard in that the comparison
1300 // is only done on the key portion of the value type, ignoring
1301 // the mapped type.
1302 //
1303 template <
1304 bool OtherIsMap,
1305 class OtherKey,
1306 class OtherT,
1307 class OtherDuration,
1308 class OtherHash,
1309 class OtherAllocator,
1310 bool MaybeMulti = IsMulti>
1311 bool
1313 false,
1314 OtherIsMap,
1315 OtherKey,
1316 OtherT,
1317 OtherDuration,
1318 OtherHash,
1319 KeyEqual,
1320 OtherAllocator> const& other) const
1321 requires(!MaybeMulti);
1322
1323 template <
1324 bool OtherIsMap,
1325 class OtherKey,
1326 class OtherT,
1327 class OtherDuration,
1328 class OtherHash,
1329 class OtherAllocator,
1330 bool MaybeMulti = IsMulti>
1331 bool
1333 true,
1334 OtherIsMap,
1335 OtherKey,
1336 OtherT,
1337 OtherDuration,
1338 OtherHash,
1339 KeyEqual,
1340 OtherAllocator> const& other) const
1341 requires MaybeMulti;
1342
1343private:
1344 bool
1345 wouldExceed(size_type additional) const
1346 {
1347 return size() + additional > bucketCount() * maxLoadFactor();
1348 }
1349
1350 void
1352 {
1353 if (wouldExceed(additional))
1354 buck_.resize(size() + additional, cont_);
1355 XRPL_ASSERT(
1357 "beast::detail::AgedUnorderedContainer::maybeRehash : maximum "
1358 "load factor");
1359 }
1360
1361 // map, set
1362 template <bool MaybeMulti = IsMulti>
1363 auto
1365 requires(!MaybeMulti);
1366
1367 // multimap, multiset
1368 template <bool MaybeMulti = IsMulti>
1369 auto
1371 requires MaybeMulti;
1372
1373 template <class InputIt>
1374 void
1375 insertUnchecked(InputIt first, InputIt last)
1376 {
1377 for (; first != last; ++first)
1378 insertUnchecked(*first);
1379 }
1380
1381 template <class InputIt>
1382 void
1383 insert(InputIt first, InputIt last, std::input_iterator_tag)
1384 {
1385 for (; first != last; ++first)
1386 insert(*first);
1387 }
1388
1389 template <class InputIt>
1390 void
1391 insert(InputIt first, InputIt last, std::random_access_iterator_tag)
1392 {
1393 auto const n(std::distance(first, last));
1394 maybeRehash(n);
1395 insertUnchecked(first, last);
1396 }
1397
1398 template <bool IsConst, class Iterator>
1399 void
1402 clock_type::time_point const& now)
1403 {
1404 auto& e(*pos.iterator());
1405 e.when = now;
1406 chronological.list_.erase(chronological.list_.iterator_to(e));
1407 chronological.list_.push_back(e);
1408 }
1409
1410 template <
1412 void
1414 requires MaybePropagate
1415 {
1416 std::swap(config_.hashFunction(), other.config_.hashFunction());
1417 std::swap(config_.keyEq(), other.config_.keyEq());
1418 std::swap(config_.alloc(), other.config_.alloc());
1419 std::swap(config_.clock, other.config_.clock);
1420 }
1421
1422 template <
1424 void
1426 requires(!MaybePropagate)
1427 {
1428 std::swap(config_.hashFunction(), other.config_.hashFunction());
1429 std::swap(config_.keyEq(), other.config_.keyEq());
1430 std::swap(config_.clock, other.config_.clock);
1431 }
1432
1433private:
1434 ConfigT config_;
1435 Buckets buck_;
1437};
1438
1439//------------------------------------------------------------------------------
1440
1441template <
1442 bool IsMulti,
1443 bool IsMap,
1444 class Key,
1445 class T,
1446 class Clock,
1447 class Hash,
1448 class KeyEqual,
1449 class Allocator>
1456
1457template <
1458 bool IsMulti,
1459 bool IsMap,
1460 class Key,
1461 class T,
1462 class Clock,
1463 class Hash,
1464 class KeyEqual,
1465 class Allocator>
1467 AgedUnorderedContainer(clock_type& clock, Hash const& hash)
1468 : config_(clock, hash)
1469 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1470{
1471}
1472
1473template <
1474 bool IsMulti,
1475 bool IsMap,
1476 class Key,
1477 class T,
1478 class Clock,
1479 class Hash,
1480 class KeyEqual,
1481 class Allocator>
1488
1489template <
1490 bool IsMulti,
1491 bool IsMap,
1492 class Key,
1493 class T,
1494 class Clock,
1495 class Hash,
1496 class KeyEqual,
1497 class Allocator>
1499 AgedUnorderedContainer(clock_type& clock, Allocator const& alloc)
1500 : config_(clock, alloc)
1501 , buck_(alloc)
1502 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1503{
1504}
1505
1506template <
1507 bool IsMulti,
1508 bool IsMap,
1509 class Key,
1510 class T,
1511 class Clock,
1512 class Hash,
1513 class KeyEqual,
1514 class Allocator>
1516 AgedUnorderedContainer(clock_type& clock, Hash const& hash, KeyEqual const& keyEq)
1517 : config_(clock, hash, keyEq)
1518 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1519{
1520}
1521
1522template <
1523 bool IsMulti,
1524 bool IsMap,
1525 class Key,
1526 class T,
1527 class Clock,
1528 class Hash,
1529 class KeyEqual,
1530 class Allocator>
1532 AgedUnorderedContainer(clock_type& clock, Hash const& hash, Allocator const& alloc)
1533 : config_(clock, hash, alloc)
1534 , buck_(alloc)
1535 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1536{
1537}
1538
1539template <
1540 bool IsMulti,
1541 bool IsMap,
1542 class Key,
1543 class T,
1544 class Clock,
1545 class Hash,
1546 class KeyEqual,
1547 class Allocator>
1549 AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq, Allocator const& alloc)
1550 : config_(clock, keyEq, alloc)
1551 , buck_(alloc)
1552 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1553{
1554}
1555
1556template <
1557 bool IsMulti,
1558 bool IsMap,
1559 class Key,
1560 class T,
1561 class Clock,
1562 class Hash,
1563 class KeyEqual,
1564 class Allocator>
1568 Hash const& hash,
1569 KeyEqual const& keyEq,
1570 Allocator const& alloc)
1571 : config_(clock, hash, keyEq, alloc)
1572 , buck_(alloc)
1573 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1574{
1575}
1576
1577template <
1578 bool IsMulti,
1579 bool IsMap,
1580 class Key,
1581 class T,
1582 class Clock,
1583 class Hash,
1584 class KeyEqual,
1585 class Allocator>
1586template <class InputIt>
1588 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock)
1589 : config_(clock)
1590 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1591{
1592 insert(first, last);
1593}
1594
1595template <
1596 bool IsMulti,
1597 bool IsMap,
1598 class Key,
1599 class T,
1600 class Clock,
1601 class Hash,
1602 class KeyEqual,
1603 class Allocator>
1604template <class InputIt>
1606 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Hash const& hash)
1607 : config_(clock, hash)
1608 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1609{
1610 insert(first, last);
1611}
1612
1613template <
1614 bool IsMulti,
1615 bool IsMap,
1616 class Key,
1617 class T,
1618 class Clock,
1619 class Hash,
1620 class KeyEqual,
1621 class Allocator>
1622template <class InputIt>
1624 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, KeyEqual const& keyEq)
1625 : config_(clock, keyEq)
1626 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1627{
1628 insert(first, last);
1629}
1630
1631template <
1632 bool IsMulti,
1633 bool IsMap,
1634 class Key,
1635 class T,
1636 class Clock,
1637 class Hash,
1638 class KeyEqual,
1639 class Allocator>
1640template <class InputIt>
1642 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc)
1643 : config_(clock, alloc)
1644 , buck_(alloc)
1645 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1646{
1647 insert(first, last);
1648}
1649
1650template <
1651 bool IsMulti,
1652 bool IsMap,
1653 class Key,
1654 class T,
1655 class Clock,
1656 class Hash,
1657 class KeyEqual,
1658 class Allocator>
1659template <class InputIt>
1662 InputIt first,
1663 InputIt last,
1665 Hash const& hash,
1666 KeyEqual const& keyEq)
1667 : config_(clock, hash, keyEq)
1668 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1669{
1670 insert(first, last);
1671}
1672
1673template <
1674 bool IsMulti,
1675 bool IsMap,
1676 class Key,
1677 class T,
1678 class Clock,
1679 class Hash,
1680 class KeyEqual,
1681 class Allocator>
1682template <class InputIt>
1685 InputIt first,
1686 InputIt last,
1688 Hash const& hash,
1689 Allocator const& alloc)
1690 : config_(clock, hash, alloc)
1691 , buck_(alloc)
1692 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1693{
1694 insert(first, last);
1695}
1696
1697template <
1698 bool IsMulti,
1699 bool IsMap,
1700 class Key,
1701 class T,
1702 class Clock,
1703 class Hash,
1704 class KeyEqual,
1705 class Allocator>
1706template <class InputIt>
1709 InputIt first,
1710 InputIt last,
1712 KeyEqual const& keyEq,
1713 Allocator const& alloc)
1714 : config_(clock, keyEq, alloc)
1715 , buck_(alloc)
1716 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1717{
1718 insert(first, last);
1719}
1720
1721template <
1722 bool IsMulti,
1723 bool IsMap,
1724 class Key,
1725 class T,
1726 class Clock,
1727 class Hash,
1728 class KeyEqual,
1729 class Allocator>
1730template <class InputIt>
1733 InputIt first,
1734 InputIt last,
1736 Hash const& hash,
1737 KeyEqual const& keyEq,
1738 Allocator const& alloc)
1739 : config_(clock, hash, keyEq, alloc)
1740 , buck_(alloc)
1741 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1742{
1743 insert(first, last);
1744}
1745
1746template <
1747 bool IsMulti,
1748 bool IsMap,
1749 class Key,
1750 class T,
1751 class Clock,
1752 class Hash,
1753 class KeyEqual,
1754 class Allocator>
1757 : config_(other.config_)
1758 , buck_(config_.alloc())
1759 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1760{
1761 insert(other.cbegin(), other.cend());
1762}
1763
1764template <
1765 bool IsMulti,
1766 bool IsMap,
1767 class Key,
1768 class T,
1769 class Clock,
1770 class Hash,
1771 class KeyEqual,
1772 class Allocator>
1774 AgedUnorderedContainer(AgedUnorderedContainer const& other, Allocator const& alloc)
1775 : config_(other.config_, alloc)
1776 , buck_(alloc)
1777 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1778{
1779 insert(other.cbegin(), other.cend());
1780}
1781
1782template <
1783 bool IsMulti,
1784 bool IsMap,
1785 class Key,
1786 class T,
1787 class Clock,
1788 class Hash,
1789 class KeyEqual,
1790 class Allocator>
1793 : config_(std::move(other.config_))
1794 , buck_(std::move(other.buck_))
1795 , cont_(std::move(other.cont_))
1796{
1797 chronological.list_ = std::move(other.chronological.list_);
1798}
1799
1800template <
1801 bool IsMulti,
1802 bool IsMap,
1803 class Key,
1804 class T,
1805 class Clock,
1806 class Hash,
1807 class KeyEqual,
1808 class Allocator>
1811 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
1812 AgedUnorderedContainer&& other,
1813 Allocator const& alloc)
1814 : config_(std::move(other.config_), alloc)
1815 , buck_(alloc)
1816 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1817{
1818 insert(other.cbegin(), other.cend());
1819 other.clear();
1820}
1821
1822template <
1823 bool IsMulti,
1824 bool IsMap,
1825 class Key,
1826 class T,
1827 class Clock,
1828 class Hash,
1829 class KeyEqual,
1830 class Allocator>
1838
1839template <
1840 bool IsMulti,
1841 bool IsMap,
1842 class Key,
1843 class T,
1844 class Clock,
1845 class Hash,
1846 class KeyEqual,
1847 class Allocator>
1852 Hash const& hash)
1853 : config_(clock, hash)
1854 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1855{
1856 insert(init.begin(), init.end());
1857}
1858
1859template <
1860 bool IsMulti,
1861 bool IsMap,
1862 class Key,
1863 class T,
1864 class Clock,
1865 class Hash,
1866 class KeyEqual,
1867 class Allocator>
1872 KeyEqual const& keyEq)
1873 : config_(clock, keyEq)
1874 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1875{
1876 insert(init.begin(), init.end());
1877}
1878
1879template <
1880 bool IsMulti,
1881 bool IsMap,
1882 class Key,
1883 class T,
1884 class Clock,
1885 class Hash,
1886 class KeyEqual,
1887 class Allocator>
1892 Allocator const& alloc)
1893 : config_(clock, alloc)
1894 , buck_(alloc)
1895 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1896{
1897 insert(init.begin(), init.end());
1898}
1899
1900template <
1901 bool IsMulti,
1902 bool IsMap,
1903 class Key,
1904 class T,
1905 class Clock,
1906 class Hash,
1907 class KeyEqual,
1908 class Allocator>
1913 Hash const& hash,
1914 KeyEqual const& keyEq)
1915 : config_(clock, hash, keyEq)
1916 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1917{
1918 insert(init.begin(), init.end());
1919}
1920
1921template <
1922 bool IsMulti,
1923 bool IsMap,
1924 class Key,
1925 class T,
1926 class Clock,
1927 class Hash,
1928 class KeyEqual,
1929 class Allocator>
1934 Hash const& hash,
1935 Allocator const& alloc)
1936 : config_(clock, hash, alloc)
1937 , buck_(alloc)
1938 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1939{
1940 insert(init.begin(), init.end());
1941}
1942
1943template <
1944 bool IsMulti,
1945 bool IsMap,
1946 class Key,
1947 class T,
1948 class Clock,
1949 class Hash,
1950 class KeyEqual,
1951 class Allocator>
1956 KeyEqual const& keyEq,
1957 Allocator const& alloc)
1958 : config_(clock, keyEq, alloc)
1959 , buck_(alloc)
1960 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1961{
1962 insert(init.begin(), init.end());
1963}
1964
1965template <
1966 bool IsMulti,
1967 bool IsMap,
1968 class Key,
1969 class T,
1970 class Clock,
1971 class Hash,
1972 class KeyEqual,
1973 class Allocator>
1978 Hash const& hash,
1979 KeyEqual const& keyEq,
1980 Allocator const& alloc)
1981 : config_(clock, hash, keyEq, alloc)
1982 , buck_(alloc)
1983 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1984{
1985 insert(init.begin(), init.end());
1986}
1987
1988template <
1989 bool IsMulti,
1990 bool IsMap,
1991 class Key,
1992 class T,
1993 class Clock,
1994 class Hash,
1995 class KeyEqual,
1996 class Allocator>
2002
2003template <
2004 bool IsMulti,
2005 bool IsMap,
2006 class Key,
2007 class T,
2008 class Clock,
2009 class Hash,
2010 class KeyEqual,
2011 class Allocator>
2012auto
2015{
2016 if (this != &other)
2017 {
2018 size_type const n(other.size());
2019 clear();
2020 config_ = other.config_;
2021 buck_ = Buckets(config_.alloc());
2022 maybeRehash(n);
2023 insertUnchecked(other.begin(), other.end());
2024 }
2025 return *this;
2026}
2027
2028template <
2029 bool IsMulti,
2030 bool IsMap,
2031 class Key,
2032 class T,
2033 class Clock,
2034 class Hash,
2035 class KeyEqual,
2036 class Allocator>
2037auto
2040{
2041 size_type const n(other.size());
2042 clear();
2043 config_ = std::move(other.config_);
2044 buck_ = Buckets(config_.alloc());
2045 maybeRehash(n);
2046 insertUnchecked(other.begin(), other.end());
2047 other.clear();
2048 return *this;
2049}
2050
2051template <
2052 bool IsMulti,
2053 bool IsMap,
2054 class Key,
2055 class T,
2056 class Clock,
2057 class Hash,
2058 class KeyEqual,
2059 class Allocator>
2060auto
2068
2069//------------------------------------------------------------------------------
2070
2071template <
2072 bool IsMulti,
2073 bool IsMap,
2074 class Key,
2075 class T,
2076 class Clock,
2077 class Hash,
2078 class KeyEqual,
2079 class Allocator>
2080template <class K, bool MaybeMulti, bool MaybeMap>
2083 requires(MaybeMap && !MaybeMulti)
2084{
2085 auto const iter(
2086 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
2087 if (iter == cont_.end())
2088 throw std::out_of_range("key not found");
2089 return iter->value.second;
2090}
2091
2092template <
2093 bool IsMulti,
2094 bool IsMap,
2095 class Key,
2096 class T,
2097 class Clock,
2098 class Hash,
2099 class KeyEqual,
2100 class Allocator>
2101template <class K, bool MaybeMulti, bool MaybeMap>
2104 K const& k) const
2105 requires(MaybeMap && !MaybeMulti)
2106{
2107 auto const iter(
2108 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
2109 if (iter == cont_.end())
2110 throw std::out_of_range("key not found");
2111 return iter->value.second;
2112}
2113
2114template <
2115 bool IsMulti,
2116 bool IsMap,
2117 class Key,
2118 class T,
2119 class Clock,
2120 class Hash,
2121 class KeyEqual,
2122 class Allocator>
2123template <bool MaybeMulti, bool MaybeMap>
2126 Key const& key)
2127 requires(MaybeMap && !MaybeMulti)
2128{
2129 maybeRehash(1);
2130 typename cont_type::insert_commit_data d;
2131 auto const result(cont_.insert_check(
2132 key, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2133 if (result.second)
2134 {
2135 Element* const p(newElement(
2137 cont_.insert_commit(*p, d);
2138 chronological.list_.push_back(*p);
2139 return p->value.second;
2140 }
2141 return result.first->value.second;
2142}
2143
2144template <
2145 bool IsMulti,
2146 bool IsMap,
2147 class Key,
2148 class T,
2149 class Clock,
2150 class Hash,
2151 class KeyEqual,
2152 class Allocator>
2153template <bool MaybeMulti, bool MaybeMap>
2156 Key&& key)
2157 requires(MaybeMap && !MaybeMulti)
2158{
2159 maybeRehash(1);
2160 typename cont_type::insert_commit_data d;
2161 auto const result(cont_.insert_check(
2162 key, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2163 if (result.second)
2164 {
2165 Element* const p(newElement(
2167 std::forward_as_tuple(std::move(key)),
2169 cont_.insert_commit(*p, d);
2170 chronological.list_.push_back(*p);
2171 return p->value.second;
2172 }
2173 return result.first->value.second;
2174}
2175
2176//------------------------------------------------------------------------------
2177
2178template <
2179 bool IsMulti,
2180 bool IsMap,
2181 class Key,
2182 class T,
2183 class Clock,
2184 class Hash,
2185 class KeyEqual,
2186 class Allocator>
2187void
2189{
2190 for (auto iter(chronological.list_.begin()); iter != chronological.list_.end();)
2191 unlinkAndDeleteElement(&*iter++);
2192 chronological.list_.clear();
2193 cont_.clear();
2194 buck_.clear();
2195}
2196
2197// map, set
2198template <
2199 bool IsMulti,
2200 bool IsMap,
2201 class Key,
2202 class T,
2203 class Clock,
2204 class Hash,
2205 class KeyEqual,
2206 class Allocator>
2207template <bool MaybeMulti>
2208auto
2210 value_type const& value) -> std::pair<iterator, bool>
2211 requires(!MaybeMulti)
2212{
2213 maybeRehash(1);
2214 typename cont_type::insert_commit_data d;
2215 auto const result(cont_.insert_check(
2216 extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2217 if (result.second)
2218 {
2219 Element* const p(newElement(value));
2220 auto const iter(cont_.insert_commit(*p, d));
2221 chronological.list_.push_back(*p);
2222 return std::make_pair(iterator(iter), true);
2223 }
2224 return std::make_pair(iterator(result.first), false);
2225}
2226
2227// multimap, multiset
2228template <
2229 bool IsMulti,
2230 bool IsMap,
2231 class Key,
2232 class T,
2233 class Clock,
2234 class Hash,
2235 class KeyEqual,
2236 class Allocator>
2237template <bool MaybeMulti>
2238auto
2240 value_type const& value) -> iterator
2241 requires MaybeMulti
2242{
2243 maybeRehash(1);
2244 Element* const p(newElement(value));
2245 chronological.list_.push_back(*p);
2246 auto const iter(cont_.insert(*p));
2247 return iterator(iter);
2248}
2249
2250// map, set
2251template <
2252 bool IsMulti,
2253 bool IsMap,
2254 class Key,
2255 class T,
2256 class Clock,
2257 class Hash,
2258 class KeyEqual,
2259 class Allocator>
2260template <bool MaybeMulti, bool MaybeMap>
2261auto
2264 requires(!MaybeMulti && !MaybeMap)
2265{
2266 maybeRehash(1);
2267 typename cont_type::insert_commit_data d;
2268 auto const result(cont_.insert_check(
2269 extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2270 if (result.second)
2271 {
2272 Element* const p(newElement(std::move(value)));
2273 auto const iter(cont_.insert_commit(*p, d));
2274 chronological.list_.push_back(*p);
2275 return std::make_pair(iterator(iter), true);
2276 }
2277 return std::make_pair(iterator(result.first), false);
2278}
2279
2280// multimap, multiset
2281template <
2282 bool IsMulti,
2283 bool IsMap,
2284 class Key,
2285 class T,
2286 class Clock,
2287 class Hash,
2288 class KeyEqual,
2289 class Allocator>
2290template <bool MaybeMulti, bool MaybeMap>
2291auto
2293 value_type&& value) -> iterator
2294 requires(MaybeMulti && !MaybeMap)
2295{
2296 maybeRehash(1);
2297 Element* const p(newElement(std::move(value)));
2298 chronological.list_.push_back(*p);
2299 auto const iter(cont_.insert(*p));
2300 return iterator(iter);
2301}
2302
2303// set, map
2304template <
2305 bool IsMulti,
2306 bool IsMap,
2307 class Key,
2308 class T,
2309 class Clock,
2310 class Hash,
2311 class KeyEqual,
2312 class Allocator>
2313template <bool MaybeMulti, class... Args>
2314auto
2316 Args&&... args) -> std::pair<iterator, bool>
2317 requires(!MaybeMulti)
2318{
2319 maybeRehash(1);
2320 // VFALCO NOTE Its unfortunate that we need to
2321 // construct element here
2322 Element* const p(newElement(std::forward<Args>(args)...));
2323 auto const result(cont_.insert(*p));
2324 if (result.second)
2325 {
2326 chronological.list_.push_back(*p);
2327 return std::make_pair(iterator(result.first), true);
2328 }
2329 deleteElement(p);
2330 return std::make_pair(iterator(result.first), false);
2331}
2332
2333// multiset, multimap
2334template <
2335 bool IsMulti,
2336 bool IsMap,
2337 class Key,
2338 class T,
2339 class Clock,
2340 class Hash,
2341 class KeyEqual,
2342 class Allocator>
2343template <bool MaybeMulti, class... Args>
2344auto
2346 Args&&... args) -> iterator
2347 requires MaybeMulti
2348{
2349 maybeRehash(1);
2350 Element* const p(newElement(std::forward<Args>(args)...));
2351 chronological.list_.push_back(*p);
2352 auto const iter(cont_.insert(*p));
2353 return iterator(iter);
2354}
2355
2356// set, map
2357template <
2358 bool IsMulti,
2359 bool IsMap,
2360 class Key,
2361 class T,
2362 class Clock,
2363 class Hash,
2364 class KeyEqual,
2365 class Allocator>
2366template <bool MaybeMulti, class... Args>
2367auto
2369 const_iterator /*hint*/,
2370 Args&&... args) -> std::pair<iterator, bool>
2371 requires(!MaybeMulti)
2372{
2373 maybeRehash(1);
2374 // VFALCO NOTE Its unfortunate that we need to
2375 // construct element here
2376 Element* const p(newElement(std::forward<Args>(args)...));
2377 typename cont_type::insert_commit_data d;
2378 auto const result(cont_.insert_check(
2379 extract(p->value),
2380 std::cref(config_.hashFunction()),
2381 std::cref(config_.keyValueEqual()),
2382 d));
2383 if (result.second)
2384 {
2385 auto const iter(cont_.insert_commit(*p, d));
2386 chronological.list_.push_back(*p);
2387 return std::make_pair(iterator(iter), true);
2388 }
2389 deleteElement(p);
2390 return std::make_pair(iterator(result.first), false);
2391}
2392
2393template <
2394 bool IsMulti,
2395 bool IsMap,
2396 class Key,
2397 class T,
2398 class Clock,
2399 class Hash,
2400 class KeyEqual,
2401 class Allocator>
2402template <bool IsConst, class Iterator>
2410
2411template <
2412 bool IsMulti,
2413 bool IsMap,
2414 class Key,
2415 class T,
2416 class Clock,
2417 class Hash,
2418 class KeyEqual,
2419 class Allocator>
2420template <bool IsConst, class Iterator>
2431
2432template <
2433 bool IsMulti,
2434 bool IsMap,
2435 class Key,
2436 class T,
2437 class Clock,
2438 class Hash,
2439 class KeyEqual,
2440 class Allocator>
2441template <class K>
2442auto
2444 -> size_type
2445{
2446 auto iter(cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
2447 if (iter == cont_.end())
2448 return 0;
2449 size_type n(0);
2450 for (;;)
2451 {
2452 auto p(&*iter++);
2453 bool const done(config_(*p, extract(iter->value)));
2455 ++n;
2456 if (done)
2457 break;
2458 }
2459 return n;
2460}
2461
2462template <
2463 bool IsMulti,
2464 bool IsMap,
2465 class Key,
2466 class T,
2467 class Clock,
2468 class Hash,
2469 class KeyEqual,
2470 class Allocator>
2471void
2479
2480template <
2481 bool IsMulti,
2482 bool IsMap,
2483 class Key,
2484 class T,
2485 class Clock,
2486 class Hash,
2487 class KeyEqual,
2488 class Allocator>
2489template <class K>
2490auto
2492 -> size_type
2493{
2494 auto const now(clock().now());
2495 size_type n(0);
2496 auto const range(equal_range(k));
2497 for (auto iter : range)
2498 {
2499 touch(iter, now);
2500 ++n;
2501 }
2502 return n;
2503}
2504
2505template <
2506 bool IsMulti,
2507 bool IsMap,
2508 class Key,
2509 class T,
2510 class Clock,
2511 class Hash,
2512 class KeyEqual,
2513 class Allocator>
2514template <
2515 bool OtherIsMap,
2516 class OtherKey,
2517 class OtherT,
2518 class OtherDuration,
2519 class OtherHash,
2520 class OtherAllocator,
2521 bool MaybeMulti>
2522bool
2525 false,
2526 OtherIsMap,
2527 OtherKey,
2528 OtherT,
2529 OtherDuration,
2530 OtherHash,
2531 KeyEqual,
2532 OtherAllocator> const& other) const
2533 requires(!MaybeMulti)
2534{
2535 if (size() != other.size())
2536 return false;
2537 for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter)
2538 {
2539 auto otherIter(other.find(extract(*iter)));
2540 if (otherIter == otherLast)
2541 return false;
2542 }
2543 return true;
2544}
2545
2546template <
2547 bool IsMulti,
2548 bool IsMap,
2549 class Key,
2550 class T,
2551 class Clock,
2552 class Hash,
2553 class KeyEqual,
2554 class Allocator>
2555template <
2556 bool OtherIsMap,
2557 class OtherKey,
2558 class OtherT,
2559 class OtherDuration,
2560 class OtherHash,
2561 class OtherAllocator,
2562 bool MaybeMulti>
2563bool
2566 true,
2567 OtherIsMap,
2568 OtherKey,
2569 OtherT,
2570 OtherDuration,
2571 OtherHash,
2572 KeyEqual,
2573 OtherAllocator> const& other) const
2574 requires MaybeMulti
2575{
2576 if (size() != other.size())
2577 return false;
2578 for (auto iter(cbegin()), last(cend()); iter != last;)
2579 {
2580 auto const& k(extract(*iter));
2581 auto const eq(equalRange(k));
2582 auto const oeq(other.equalRange(k));
2583#if BEAST_NO_CXX14_IS_PERMUTATION
2584 if (std::distance(eq.first, eq.second) != std::distance(oeq.first, oeq.second) ||
2585 !std::is_permutation(eq.first, eq.second, oeq.first))
2586 return false;
2587#else
2588 if (!std::is_permutation(eq.first, eq.second, oeq.first, oeq.second))
2589 return false;
2590#endif
2591 iter = eq.second;
2592 }
2593 return true;
2594}
2595
2596//------------------------------------------------------------------------------
2597
2598// map, set
2599template <
2600 bool IsMulti,
2601 bool IsMap,
2602 class Key,
2603 class T,
2604 class Clock,
2605 class Hash,
2606 class KeyEqual,
2607 class Allocator>
2608template <bool MaybeMulti>
2609auto
2611 value_type const& value) -> std::pair<iterator, bool>
2612 requires(!MaybeMulti)
2613{
2614 typename cont_type::insert_commit_data d;
2615 auto const result(cont_.insert_check(
2616 extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2617 if (result.second)
2618 {
2619 Element* const p(newElement(value));
2620 auto const iter(cont_.insert_commit(*p, d));
2621 chronological.list_.push_back(*p);
2622 return std::make_pair(iterator(iter), true);
2623 }
2624 return std::make_pair(iterator(result.first), false);
2625}
2626
2627// multimap, multiset
2628template <
2629 bool IsMulti,
2630 bool IsMap,
2631 class Key,
2632 class T,
2633 class Clock,
2634 class Hash,
2635 class KeyEqual,
2636 class Allocator>
2637template <bool MaybeMulti>
2638auto
2640 value_type const& value) -> iterator
2641 requires MaybeMulti
2642{
2643 Element* const p(newElement(value));
2644 chronological.list_.push_back(*p);
2645 auto const iter(cont_.insert(*p));
2646 return iterator(iter);
2647}
2648
2649//------------------------------------------------------------------------------
2650
2651} // namespace detail
2652
2653//------------------------------------------------------------------------------
2654
2655template <
2656 bool IsMulti,
2657 bool IsMap,
2658 class Key,
2659 class T,
2660 class Clock,
2661 class Hash,
2662 class KeyEqual,
2663 class Allocator>
2665 beast::detail::AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>>
2667{
2668 explicit IsAgedContainer() = default;
2669};
2670
2671// Free functions
2672
2673template <
2674 bool IsMulti,
2675 bool IsMap,
2676 class Key,
2677 class T,
2678 class Clock,
2679 class Hash,
2680 class KeyEqual,
2681 class Allocator>
2682void
2691
2695template <
2696 bool IsMulti,
2697 bool IsMap,
2698 class Key,
2699 class T,
2700 class Clock,
2701 class Hash,
2702 class KeyEqual,
2703 class Allocator,
2704 class Rep,
2705 class Period>
2709 c,
2710 std::chrono::duration<Rep, Period> const& age) noexcept
2711{
2712 std::size_t n(0);
2713 auto const expired(c.clock().now() - age);
2714 for (auto iter(c.chronological.cbegin());
2715 iter != c.chronological.cend() && iter.when() <= expired;)
2716 {
2717 iter = c.erase(iter);
2718 ++n;
2719 }
2720 return n;
2721}
2722
2723} // namespace beast
T addressof(T... args)
T ceil(T... args)
Abstract interface to a clock.
Clock::duration duration
Clock::time_point time_point
std::vector< bucket_type, typename std::allocator_traits< Allocator >::template rebind_alloc< bucket_type > > vec_type
beast::detail::AgedContainerIterator<!IsMap, typename list_type::reverse_iterator > reverse_iterator
beast::detail::AgedContainerIterator< true, typename list_type::iterator > const_iterator
const_iterator iteratorTo(value_type const &value) const
beast::detail::AgedContainerIterator<!IsMap, typename list_type::iterator > iterator
beast::detail::AgedContainerIterator< true, typename list_type::reverse_iterator > const_reverse_iterator
ConfigT(clock_type &clock, Allocator const &alloc)
ConfigT(clock_type &clock, Hash const &hash, KeyEqual const &keyEqual, Allocator const &alloc)
ConfigT(ConfigT const &other, Allocator const &alloc)
ConfigT(clock_type &clock, KeyEqual const &keyEqual)
ConfigT(ConfigT &&other, Allocator const &alloc)
ConfigT(clock_type &clock, Hash const &hash, Allocator const &alloc)
ConfigT(clock_type &clock, Hash const &hash, KeyEqual const &keyEqual)
ConfigT(clock_type &clock, KeyEqual const &keyEqual, Allocator const &alloc)
bool operator()(Element const &lhs, Element const &rhs) const
bool operator()(Key const &k, Element const &e) const
bool operator()(Element const &e, Key const &k) const
Associative container where each element is also indexed by time.
auto insert(value_type &&value) -> iterator requires(MaybeMulti &&!MaybeMap)
std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > insert(const_iterator hint, P &&value)
void touch(beast::detail::AgedContainerIterator< IsConst, Iterator > pos, clock_type::time_point const &now)
AgedUnorderedContainer & operator=(AgedUnorderedContainer const &other)
auto insert(value_type const &value) -> std::pair< iterator, bool > requires(!MaybeMulti)
bool operator==(AgedUnorderedContainer< true, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Allocator const &alloc)
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > first, beast::detail::AgedContainerIterator< IsConst, Iterator > last)
AgedUnorderedContainer(clock_type &clock, Hash const &hash, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash, Allocator const &alloc)
auto emplace(Args &&... args) -> std::pair< iterator, bool > requires(!MaybeMulti)
beast::detail::AgedContainerIterator< true, typename cont_type::iterator > const_iterator
bool operator==(AgedUnorderedContainer< false, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
std::allocator_traits< Allocator >::template rebind_alloc< Element > BucketAllocator
auto insertUnchecked(value_type const &value) -> std::pair< iterator, bool > requires(!MaybeMulti)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, Allocator const &alloc)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, KeyEqual const &keyEq)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash, KeyEqual const &keyEq)
boost::intrusive::make_list< Element, boost::intrusive::constant_time_size< false > >::type list_type
std::conditional_t< IsMulti, typename boost::intrusive::make_unordered_multiset< Element, boost::intrusive::constant_time_size< true >, boost::intrusive::hash< ValueHash >, boost::intrusive::equal< KeyValueEqual >, boost::intrusive::cache_begin< true > >::type, typename boost::intrusive::make_unordered_set< Element, boost::intrusive::constant_time_size< true >, boost::intrusive::hash< ValueHash >, boost::intrusive::equal< KeyValueEqual >, boost::intrusive::cache_begin< true > >::type > cont_type
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, KeyEqual const &keyEq)
AgedUnorderedContainer(clock_type &clock, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(clock_type &clock, Hash const &hash, Allocator const &alloc)
auto insert(value_type &&value) -> std::pair< iterator, bool > requires(!MaybeMulti &&!MaybeMap)
std::conditional< IsMap, T, void * >::type const & at(K const &k) const
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::local_iterator > local_iterator
beast::detail::AgedContainerIterator< true, typename cont_type::local_iterator > const_local_iterator
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash)
AgedUnorderedContainer & operator=(std::initializer_list< value_type > init)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock)
std::allocator_traits< Allocator >::template rebind_alloc< Element > ElementAllocator
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, KeyEqual const &keyEq, Allocator const &alloc)
std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > insert(P &&value)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(AgedUnorderedContainer const &other, Allocator const &alloc)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash)
AgedUnorderedContainer(clock_type &clock, Hash const &hash, KeyEqual const &keyEq)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, KeyEqual const &keyEq, Allocator const &alloc)
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::iterator > iterator
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, KeyEqual const &keyEq)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Allocator const &alloc)
auto emplaceHint(const_iterator, Args &&... args) -> std::pair< iterator, bool > requires(!MaybeMulti)
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > pos)
T distance(T... args)
T forward_as_tuple(T... args)
T forward(T... args)
T is_constructible_v
T is_permutation(T... args)
T is_standard_layout_v
T make_pair(T... args)
T max(T... args)
std::size_t expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
void swap(beast::detail::AgedOrderedContainer< IsMulti, IsMap, Key, T, Clock, Compare, Allocator > &lhs, beast::detail::AgedOrderedContainer< IsMulti, IsMap, Key, T, Clock, Compare, Allocator > &rhs) noexcept
STL namespace.
T piecewise_construct
T cref(T... args)
T release(T... args)
Element(time_point const &when, Args &&... args)
Element(time_point const &when, value_type const &value)
Element(time_point const &when, value_type &&value)
T swap(T... args)