xrpld
Loading...
Searching...
No Matches
aged_ordered_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
9#include <boost/intrusive/list.hpp>
10#include <boost/intrusive/set.hpp>
11#include <boost/version.hpp>
12
13#include <algorithm>
14#include <chrono>
15#include <cstddef>
16#include <cstdint>
17#include <functional>
18#include <initializer_list>
19#include <memory>
20#include <stdexcept>
21#include <tuple>
22#include <type_traits>
23#include <utility>
24
25namespace beast {
26namespace detail {
27
28// Traits templates used to discern reverse_iterators, which are disallowed
29// for mutating operations.
30template <class It>
35
36template <class It>
37struct IsBoostReverseIterator<boost::intrusive::reverse_iterator<It>> : std::true_type
38{
39 explicit IsBoostReverseIterator() = default;
40};
41
59template <
60 bool IsMulti,
61 bool IsMap,
62 class Key,
63 class T,
64 class Clock = std::chrono::steady_clock,
65 class Compare = std::less<Key>,
68{
69public:
73 using key_type = Key;
74 using mapped_type = T;
78
79 // Introspection (for unit tests)
83
84private:
85 static Key const&
86 extract(value_type const& value)
87 {
89 }
90
91 // VFALCO TODO hoist to remove template argument dependencies
92 struct Element : boost::intrusive::set_base_hook<
93 boost::intrusive::link_mode<boost::intrusive::normal_link>>,
94 boost::intrusive::list_base_hook<
95 boost::intrusive::link_mode<boost::intrusive::normal_link>>
96 {
97 // Stash types here so the iterator doesn't
98 // need to see the container declaration.
106
108 {
109 }
110
112 {
113 }
114
115 template <class... Args>
116 Element(time_point const& when, Args&&... args)
117 requires(std::is_constructible_v<value_type, Args...>)
118 : value(std::forward<Args>(args)...), when(when)
119 {
120 }
121
124 };
125
126 // VFALCO TODO This should only be enabled for maps.
127 class PairValueCompare : public Compare
128 {
129 public:
132 using result_type = bool;
133
134 bool
135 operator()(value_type const& lhs, value_type const& rhs) const
136 {
137 return Compare::operator()(lhs.first, rhs.first);
138 }
139
140 PairValueCompare() = default;
141
142 PairValueCompare(PairValueCompare const& other) : Compare(other)
143 {
144 }
145
146 private:
148
149 PairValueCompare(Compare const& compare) : Compare(compare)
150 {
151 }
152 };
153
154 // Compares value_type against element, used in insert_check
155 // VFALCO TODO hoist to remove template argument dependencies
156 class KeyValueCompare : public Compare
157 {
158 public:
159 using first_argument = Key;
161 using result_type = bool;
162
163 KeyValueCompare() = default;
164
165 KeyValueCompare(Compare const& compare) : Compare(compare)
166 {
167 }
168
169 bool
170 operator()(Key const& k, Element const& e) const
171 {
172 return Compare::operator()(k, extract(e.value));
173 }
174
175 bool
176 operator()(Element const& e, Key const& k) const
177 {
178 return Compare::operator()(extract(e.value), k);
179 }
180
181 bool
182 operator()(Element const& x, Element const& y) const
183 {
184 return Compare::operator()(extract(x.value), extract(y.value));
185 }
186
187 Compare&
189 {
190 return *this;
191 }
192
193 [[nodiscard]] Compare const&
194 compare() const
195 {
196 return *this;
197 }
198 };
199
200 using list_type =
201 boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
202
204 IsMulti,
205 typename boost::intrusive::make_multiset<
206 Element,
207 boost::intrusive::constant_time_size<true>,
208 boost::intrusive::compare<KeyValueCompare>>::type,
209 typename boost::intrusive::make_set<
210 Element,
211 boost::intrusive::constant_time_size<true>,
212 boost::intrusive::compare<KeyValueCompare>>::type>;
213
215
217
218 class ConfigT : private KeyValueCompare,
219 public beast::detail::EmptyBaseOptimization<ElementAllocator>
220 {
221 public:
223 {
224 }
225
226 ConfigT(clock_type& clock, Compare const& comp) : KeyValueCompare(comp), clock(clock)
227 {
228 }
229
234
235 ConfigT(clock_type& clock, Compare const& comp, Allocator const& alloc)
236 : KeyValueCompare(comp)
238 , clock(clock)
239 {
240 }
241
242 ConfigT(ConfigT const& other)
243 : KeyValueCompare(other.keyCompare())
245 ElementAllocatorTraits::select_on_container_copy_construction(other.alloc()))
246 , clock(other.clock)
247 {
248 }
249
250 ConfigT(ConfigT const& other, Allocator const& alloc)
251 : KeyValueCompare(other.keyCompare())
253 , clock(other.clock)
254 {
255 }
256
258 : KeyValueCompare(std::move(other.keyCompare()))
260 static_cast<beast::detail::EmptyBaseOptimization<ElementAllocator>&>(other)))
261 , clock(other.clock)
262 {
263 }
264
266 ConfigT&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
267 Allocator const& alloc)
268 : KeyValueCompare(std::move(other.keyCompare()))
270 , clock(other.clock)
271 {
272 }
273
274 ConfigT&
275 operator=(ConfigT const& other)
276 {
277 if (this != &other)
278 {
279 compare() = other.compare();
280 alloc() = other.alloc();
281 clock = other.clock;
282 }
283 return *this;
284 }
285
286 ConfigT&
288 {
289 compare() = std::move(other.compare());
290 alloc() = std::move(other.alloc());
291 clock = other.clock;
292 return *this;
293 }
294
295 Compare&
297 {
299 }
300
301 [[nodiscard]] Compare const&
302 compare() const
303 {
305 }
306
309 {
310 return *this;
311 }
312
313 [[nodiscard]] KeyValueCompare const&
315 {
316 return *this;
317 }
318
324
325 [[nodiscard]] ElementAllocator const&
330
332 };
333
334 template <class... Args>
335 Element*
336 newElement(Args&&... args)
337 {
338 struct Deleter
339 {
341 Deleter(ElementAllocator& a) : a(a)
342 {
343 }
344
345 void
346 operator()(Element* p)
347 {
349 }
350 };
351
353 ElementAllocatorTraits::allocate(config_.alloc(), 1), Deleter(config_.alloc()));
355 config_.alloc(), p.get(), clock().now(), std::forward<Args>(args)...);
356 return p.release();
357 }
358
359 void
360 deleteElement(Element const* p)
361 {
363 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
364 ElementAllocatorTraits::deallocate(config_.alloc(), const_cast<Element*>(p), 1);
365 }
366
367 void
368 unlinkAndDeleteElement(Element const* p)
369 {
370 chronological.list_.erase(chronological.list_.iterator_to(*p));
371 cont_.erase(cont_.iterator_to(*p));
372 deleteElement(p);
373 }
374
375public:
376 using key_compare = Compare;
378 using allocator_type = Allocator;
383
384 // A set iterator (IsMap==false) is always const
385 // because the elements of a set are immutable.
392
393 //--------------------------------------------------------------------------
394 //
395 // Chronological ordered iterators
396 //
397 // "Memberspace"
398 // http://accu.org/index.php/journals/1527
399 //
400 //--------------------------------------------------------------------------
401
403 {
404 ChronologicalT() = default;
405
406 public:
407 // A set iterator (IsMap==false) is always const
408 // because the elements of a set are immutable.
416
419 {
420 return iterator(list_.begin());
421 }
422
424 begin() const
425 {
426 return const_iterator(list_.begin());
427 }
428
430 cbegin() const
431 {
432 return const_iterator(list_.begin());
433 }
434
437 {
438 return iterator(list_.end());
439 }
440
442 end() const
443 {
444 return const_iterator(list_.end());
445 }
446
448 cend() const
449 {
450 return const_iterator(list_.end());
451 }
452
455 {
456 return reverse_iterator(list_.rbegin());
457 }
458
460 rbegin() const
461 {
462 return const_reverse_iterator(list_.rbegin());
463 }
464
466 crbegin() const
467 {
468 return const_reverse_iterator(list_.rbegin());
469 }
470
473 {
474 return reverse_iterator(list_.rend());
475 }
476
478 rend() const
479 {
480 return const_reverse_iterator(list_.rend());
481 }
482
484 crend() const
485 {
486 return const_reverse_iterator(list_.rend());
487 }
488
491 {
492 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
493 return list_.iterator_to(*reinterpret_cast<Element*>(
494 reinterpret_cast<uint8_t*>(&value) -
495 ((std::size_t)std::addressof(((Element*)0)->member))));
496 }
497
499 iteratorTo(value_type const& value) const
500 {
501 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
502 return list_.iterator_to(*reinterpret_cast<Element const*>(
503 reinterpret_cast<uint8_t const*>(&value) -
504 ((std::size_t)std::addressof(((Element*)0)->member))));
505 }
506
509
510 private:
514
515 //--------------------------------------------------------------------------
516 //
517 // Construction
518 //
519 //--------------------------------------------------------------------------
520
522
524
525 AgedOrderedContainer(clock_type& clock, Compare const& comp);
526
527 AgedOrderedContainer(clock_type& clock, Allocator const& alloc);
528
529 AgedOrderedContainer(clock_type& clock, Compare const& comp, Allocator const& alloc);
530
531 template <class InputIt>
532 AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock);
533
534 template <class InputIt>
535 AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock, Compare const& comp);
536
537 template <class InputIt>
538 AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc);
539
540 template <class InputIt>
542 InputIt first,
543 InputIt last,
545 Compare const& comp,
546 Allocator const& alloc);
547
549
550 AgedOrderedContainer(AgedOrderedContainer const& other, Allocator const& alloc);
551
553
555 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
556 AgedOrderedContainer&& other,
557 Allocator const& alloc);
558
560
564 Compare const& comp);
565
569 Allocator const& alloc);
570
574 Compare const& comp,
575 Allocator const& alloc);
576
578
581
584
587
590 {
591 return config_.alloc();
592 }
593
596 {
597 return config_.clock;
598 }
599
600 clock_type const&
601 clock() const
602 {
603 return config_.clock;
604 }
605
606 //--------------------------------------------------------------------------
607 //
608 // Element access (maps)
609 //
610 //--------------------------------------------------------------------------
611
612 template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
614 at(K const& k)
615 requires(MaybeMap && !MaybeMulti);
616
617 template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
619 at(K const& k) const
620 requires(MaybeMap && !MaybeMulti);
621
622 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
624 operator[](Key const& key)
625 requires(MaybeMap && !MaybeMulti);
626
627 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
629 operator[](Key&& key)
630 requires(MaybeMap && !MaybeMulti);
631
632 //--------------------------------------------------------------------------
633 //
634 // Iterators
635 //
636 //--------------------------------------------------------------------------
637
640 {
641 return iterator(cont_.begin());
642 }
643
645 begin() const
646 {
647 return const_iterator(cont_.begin());
648 }
649
651 cbegin() const
652 {
653 return const_iterator(cont_.begin());
654 }
655
658 {
659 return iterator(cont_.end());
660 }
661
663 end() const
664 {
665 return const_iterator(cont_.end());
666 }
667
669 cend() const
670 {
671 return const_iterator(cont_.end());
672 }
673
676 {
677 return reverse_iterator(cont_.rbegin());
678 }
679
681 rbegin() const
682 {
683 return const_reverse_iterator(cont_.rbegin());
684 }
685
687 crbegin() const
688 {
689 return const_reverse_iterator(cont_.rbegin());
690 }
691
694 {
695 return reverse_iterator(cont_.rend());
696 }
697
699 rend() const
700 {
701 return const_reverse_iterator(cont_.rend());
702 }
703
705 crend() const
706 {
707 return const_reverse_iterator(cont_.rend());
708 }
709
712 {
713 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
714 return cont_.iterator_to(*reinterpret_cast<Element*>(
715 reinterpret_cast<uint8_t*>(&value) -
716 ((std::size_t)std::addressof(((Element*)0)->member))));
717 }
718
720 iteratorTo(value_type const& value) const
721 {
722 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
723 return cont_.iterator_to(*reinterpret_cast<Element const*>(
724 reinterpret_cast<uint8_t const*>(&value) -
725 ((std::size_t)std::addressof(((Element*)0)->member))));
726 }
727
728 //--------------------------------------------------------------------------
729 //
730 // Capacity
731 //
732 //--------------------------------------------------------------------------
733
734 bool
735 empty() const noexcept
736 {
737 return cont_.empty();
738 }
739
741 size() const noexcept
742 {
743 return cont_.size();
744 }
745
747 maxSize() const noexcept
748 {
749 return config_.max_size();
750 }
751
752 //--------------------------------------------------------------------------
753 //
754 // Modifiers
755 //
756 //--------------------------------------------------------------------------
757
758 void
760
761 // map, set
762 template <bool MaybeMulti = IsMulti>
763 auto
765 requires(!MaybeMulti);
766
767 // multimap, multiset
768 template <bool MaybeMulti = IsMulti>
769 auto
770 insert(value_type const& value) -> iterator
771 requires MaybeMulti;
772
773 // set
774 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
775 auto
777 requires(!MaybeMulti && !MaybeMap);
778
779 // multiset
780 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
781 auto
783 requires(MaybeMulti && !MaybeMap);
784
785 //---
786
787 // map, set
788 template <bool MaybeMulti = IsMulti>
789 auto
791 requires(!MaybeMulti);
792
793 // multimap, multiset
794 template <bool MaybeMulti = IsMulti>
796 insert(const_iterator /*hint*/, value_type const& value)
797 requires MaybeMulti
798 {
799 // VFALCO TODO Figure out how to utilize 'hint'
800 return insert(value);
801 }
802
803 // map, set
804 template <bool MaybeMulti = IsMulti>
805 auto
807 requires(!MaybeMulti);
808
809 // multimap, multiset
810 template <bool MaybeMulti = IsMulti>
813 requires MaybeMulti
814 {
815 // VFALCO TODO Figure out how to utilize 'hint'
816 return insert(std::move(value));
817 }
818
819 // map, multimap
820 template <class P, bool MaybeMap = IsMap>
822 insert(P&& value)
824 {
825 return emplace(std::forward<P>(value));
826 }
827
828 // map, multimap
829 template <class P, bool MaybeMap = IsMap>
831 insert(const_iterator hint, P&& value)
833 {
834 return emplaceHint(hint, std::forward<P>(value));
835 }
836
837 template <class InputIt>
838 void
839 insert(InputIt first, InputIt last)
840 {
841 for (; first != last; ++first)
842 insert(cend(), *first);
843 }
844
845 void
847 {
848 insert(init.begin(), init.end());
849 }
850
851 // map, set
852 template <bool MaybeMulti = IsMulti, class... Args>
853 auto
855 requires(!MaybeMulti);
856
857 // multiset, multimap
858 template <bool MaybeMulti = IsMulti, class... Args>
859 auto
860 emplace(Args&&... args) -> iterator
861 requires MaybeMulti;
862
863 // map, set
864 template <bool MaybeMulti = IsMulti, class... Args>
865 auto
867 requires(!MaybeMulti);
868
869 // multiset, multimap
870 template <bool MaybeMulti = IsMulti, class... Args>
872 emplaceHint(const_iterator /*hint*/, Args&&... args)
873 requires MaybeMulti
874 {
875 // VFALCO TODO Figure out how to utilize 'hint'
877 }
878
879 // The constraint prevents erase (reverse_iterator pos) from compiling
880 template <bool IsConst, class Iterator>
884
885 // The constraint prevents erase (reverse_iterator first, reverse_iterator last)
886 // from compiling
887 template <bool IsConst, class Iterator>
893
894 template <class K>
895 auto
896 erase(K const& k) -> size_type;
897
898 void
899 swap(AgedOrderedContainer& other) noexcept;
900
901 //--------------------------------------------------------------------------
902
903 // The constraint prevents touch (reverse_iterator pos) from compiling
904 template <bool IsConst, class Iterator>
905 void
911
912 template <class K>
914 touch(K const& k);
915
916 //--------------------------------------------------------------------------
917 //
918 // Lookup
919 //
920 //--------------------------------------------------------------------------
921
922 // VFALCO TODO Respect is_transparent (c++14)
923 template <class K>
925 count(K const& k) const
926 {
927 return cont_.count(k, std::cref(config_.keyCompare()));
928 }
929
930 // VFALCO TODO Respect is_transparent (c++14)
931 template <class K>
933 find(K const& k)
934 {
935 return iterator(cont_.find(k, std::cref(config_.keyCompare())));
936 }
937
938 // VFALCO TODO Respect is_transparent (c++14)
939 template <class K>
941 find(K const& k) const
942 {
943 return const_iterator(cont_.find(k, std::cref(config_.keyCompare())));
944 }
945
946 // VFALCO TODO Respect is_transparent (c++14)
947 template <class K>
949 equalRange(K const& k)
950 {
951 auto const r(cont_.equal_range(k, std::cref(config_.keyCompare())));
952 return std::make_pair(iterator(r.first), iterator(r.second));
953 }
954
955 // VFALCO TODO Respect is_transparent (c++14)
956 template <class K>
958 equalRange(K const& k) const
959 {
960 auto const r(cont_.equal_range(k, std::cref(config_.keyCompare())));
961 return std::make_pair(const_iterator(r.first), const_iterator(r.second));
962 }
963
964 // VFALCO TODO Respect is_transparent (c++14)
965 template <class K>
967 lowerBound(K const& k)
968 {
969 return iterator(cont_.lower_bound(k, std::cref(config_.keyCompare())));
970 }
971
972 // VFALCO TODO Respect is_transparent (c++14)
973 template <class K>
975 lowerBound(K const& k) const
976 {
977 return const_iterator(cont_.lower_bound(k, std::cref(config_.keyCompare())));
978 }
979
980 // VFALCO TODO Respect is_transparent (c++14)
981 template <class K>
983 upperBound(K const& k)
984 {
985 return iterator(cont_.upper_bound(k, std::cref(config_.keyCompare())));
986 }
987
988 // VFALCO TODO Respect is_transparent (c++14)
989 template <class K>
991 upperBound(K const& k) const
992 {
993 return const_iterator(cont_.upper_bound(k, std::cref(config_.keyCompare())));
994 }
995
996 //--------------------------------------------------------------------------
997 //
998 // Observers
999 //
1000 //--------------------------------------------------------------------------
1001
1003 keyComp() const
1004 {
1005 return config_.compare();
1006 }
1007
1008 // VFALCO TODO Should this return const reference for set?
1011 {
1012 return value_compare(config_.compare());
1013 }
1014
1015 //--------------------------------------------------------------------------
1016 //
1017 // Comparison
1018 //
1019 //--------------------------------------------------------------------------
1020
1021 // This differs from the standard in that the comparison
1022 // is only done on the key portion of the value type, ignoring
1023 // the mapped type.
1024 //
1025 template <
1026 bool OtherIsMulti,
1027 bool OtherIsMap,
1028 class OtherT,
1029 class OtherDuration,
1030 class OtherAllocator>
1031 bool
1033 OtherIsMulti,
1034 OtherIsMap,
1035 Key,
1036 OtherT,
1037 OtherDuration,
1038 Compare,
1039 OtherAllocator> const& other) const;
1040
1041 template <
1042 bool OtherIsMulti,
1043 bool OtherIsMap,
1044 class OtherT,
1045 class OtherDuration,
1046 class OtherAllocator>
1047 bool
1049 OtherIsMulti,
1050 OtherIsMap,
1051 Key,
1052 OtherT,
1053 OtherDuration,
1054 Compare,
1055 OtherAllocator> const& other) const
1056 {
1057 value_compare const comp(valueComp());
1058 return std::lexicographical_compare(cbegin(), cend(), other.cbegin(), other.cend(), comp);
1059 }
1060
1061 template <
1062 bool OtherIsMulti,
1063 bool OtherIsMap,
1064 class OtherT,
1065 class OtherDuration,
1066 class OtherAllocator>
1067 bool
1069 OtherIsMulti,
1070 OtherIsMap,
1071 Key,
1072 OtherT,
1073 OtherDuration,
1074 Compare,
1075 OtherAllocator> const& other) const
1076 {
1077 return !(other < *this);
1078 }
1079
1080 template <
1081 bool OtherIsMulti,
1082 bool OtherIsMap,
1083 class OtherT,
1084 class OtherDuration,
1085 class OtherAllocator>
1086 bool
1088 OtherIsMulti,
1089 OtherIsMap,
1090 Key,
1091 OtherT,
1092 OtherDuration,
1093 Compare,
1094 OtherAllocator> const& other) const
1095 {
1096 return other < *this;
1097 }
1098
1099 template <
1100 bool OtherIsMulti,
1101 bool OtherIsMap,
1102 class OtherT,
1103 class OtherDuration,
1104 class OtherAllocator>
1105 bool
1107 OtherIsMulti,
1108 OtherIsMap,
1109 Key,
1110 OtherT,
1111 OtherDuration,
1112 Compare,
1113 OtherAllocator> const& other) const
1114 {
1115 return !(*this < other);
1116 }
1117
1118private:
1119 // The constraint prevents erase (reverse_iterator pos, now) from compiling
1120 template <bool IsConst, class Iterator>
1121 void
1124 clock_type::time_point const& now)
1126
1127 template <
1129 void
1131 requires MaybePropagate;
1132
1133 template <
1135 void
1137 requires(!MaybePropagate);
1138
1139private:
1140 ConfigT config_;
1142};
1143
1144//------------------------------------------------------------------------------
1145
1146template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1152
1153template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1160
1161template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1168
1169template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1172 Compare const& comp,
1173 Allocator const& alloc)
1174 : config_(clock, comp, alloc), cont_(comp)
1175{
1176}
1177
1178template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1179template <class InputIt>
1181 InputIt first,
1182 InputIt last,
1184 : config_(clock)
1185{
1186 insert(first, last);
1187}
1188
1189template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1190template <class InputIt>
1192 InputIt first,
1193 InputIt last,
1195 Compare const& comp)
1196 : config_(clock, comp), cont_(comp)
1197{
1198 insert(first, last);
1199}
1200
1201template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1202template <class InputIt>
1204 InputIt first,
1205 InputIt last,
1207 Allocator const& alloc)
1208 : config_(clock, alloc)
1209{
1210 insert(first, last);
1211}
1212
1213template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1214template <class InputIt>
1216 InputIt first,
1217 InputIt last,
1219 Compare const& comp,
1220 Allocator const& alloc)
1221 : config_(clock, comp, alloc), cont_(comp)
1222{
1223 insert(first, last);
1224}
1225
1226template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1233
1234template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1236 AgedOrderedContainer const& other,
1237 Allocator const& alloc)
1238 : config_(other.config_, alloc), cont_(other.cont_.get_comp())
1239{
1240 insert(other.cbegin(), other.cend());
1241}
1242
1243template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1245 AgedOrderedContainer&& other)
1246 : config_(std::move(other.config_)), cont_(std::move(other.cont_))
1247{
1248 chronological.list_ = std::move(other.chronological.list_);
1249}
1250
1251template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1253 AgedOrderedContainer&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
1254 Allocator const& alloc)
1255 : config_(std::move(other.config_), alloc), cont_(std::move(other.cont_.get_comp()))
1256{
1257 insert(other.cbegin(), other.cend());
1258 other.clear();
1259}
1260
1261template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1269
1270template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1279
1280template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1289
1290template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1294 Compare const& comp,
1295 Allocator const& alloc)
1296 : config_(clock, comp, alloc), cont_(comp)
1297{
1298 insert(init.begin(), init.end());
1299}
1300
1301template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1306
1307template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1308auto
1311{
1312 if (this != &other)
1313 {
1314 clear();
1315 this->config_ = other.config_;
1316 insert(other.begin(), other.end());
1317 }
1318 return *this;
1319}
1320
1321template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1322auto
1325{
1326 clear();
1327 this->config_ = std::move(other.config_);
1328 insert(other.begin(), other.end());
1329 other.clear();
1330 return *this;
1331}
1332
1333template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1334auto
1342
1343//------------------------------------------------------------------------------
1344
1345template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1346template <class K, bool MaybeMulti, bool MaybeMap>
1349 requires(MaybeMap && !MaybeMulti)
1350{
1351 auto const iter(cont_.find(k, std::cref(config_.keyCompare())));
1352 if (iter == cont_.end())
1353 throw std::out_of_range("key not found");
1354 return iter->value.second;
1355}
1356
1357template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1358template <class K, bool MaybeMulti, bool MaybeMap>
1361 requires(MaybeMap && !MaybeMulti)
1362{
1363 auto const iter(cont_.find(k, std::cref(config_.keyCompare())));
1364 if (iter == cont_.end())
1365 throw std::out_of_range("key not found");
1366 return iter->value.second;
1367}
1368
1369template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1370template <bool MaybeMulti, bool MaybeMap>
1373 requires(MaybeMap && !MaybeMulti)
1374{
1375 typename cont_type::insert_commit_data d;
1376 auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
1377 if (result.second)
1378 {
1379 Element* const p(newElement(
1381 cont_.insert_commit(*p, d);
1382 chronological.list_.push_back(*p);
1383 return p->value.second;
1384 }
1385 return result.first->value.second;
1386}
1387
1388template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1389template <bool MaybeMulti, bool MaybeMap>
1392 requires(MaybeMap && !MaybeMulti)
1393{
1394 typename cont_type::insert_commit_data d;
1395 auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
1396 if (result.second)
1397 {
1398 Element* const p(newElement(
1400 std::forward_as_tuple(std::move(key)),
1402 cont_.insert_commit(*p, d);
1403 chronological.list_.push_back(*p);
1404 return p->value.second;
1405 }
1406 return result.first->value.second;
1407}
1408
1409//------------------------------------------------------------------------------
1410
1411template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1412void
1414{
1415 for (auto iter(chronological.list_.begin()); iter != chronological.list_.end();)
1416 deleteElement(&*iter++);
1417 chronological.list_.clear();
1418 cont_.clear();
1419}
1420
1421// map, set
1422template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1423template <bool MaybeMulti>
1424auto
1426 value_type const& value) -> std::pair<iterator, bool>
1427 requires(!MaybeMulti)
1428{
1429 typename cont_type::insert_commit_data d;
1430 auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
1431 if (result.second)
1432 {
1433 Element* const p(newElement(value));
1434 auto const iter(cont_.insert_commit(*p, d));
1435 chronological.list_.push_back(*p);
1436 return std::make_pair(iterator(iter), true);
1437 }
1438 return std::make_pair(iterator(result.first), false);
1439}
1440
1441// multimap, multiset
1442template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1443template <bool MaybeMulti>
1444auto
1446 value_type const& value) -> iterator
1447 requires MaybeMulti
1448{
1449 auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare())));
1450 Element* const p(newElement(value));
1451 chronological.list_.push_back(*p);
1452 auto const iter(cont_.insert_before(before, *p));
1453 return iterator(iter);
1454}
1455
1456// set
1457template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1458template <bool MaybeMulti, bool MaybeMap>
1459auto
1462 requires(!MaybeMulti && !MaybeMap)
1463{
1464 typename cont_type::insert_commit_data d;
1465 auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
1466 if (result.second)
1467 {
1468 Element* const p(newElement(std::move(value)));
1469 auto const iter(cont_.insert_commit(*p, d));
1470 chronological.list_.push_back(*p);
1471 return std::make_pair(iterator(iter), true);
1472 }
1473 return std::make_pair(iterator(result.first), false);
1474}
1475
1476// multiset
1477template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1478template <bool MaybeMulti, bool MaybeMap>
1479auto
1481 -> iterator
1482 requires(MaybeMulti && !MaybeMap)
1483{
1484 auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare())));
1485 Element* const p(newElement(std::move(value)));
1486 chronological.list_.push_back(*p);
1487 auto const iter(cont_.insert_before(before, *p));
1488 return iterator(iter);
1489}
1490
1491//---
1492
1493// map, set
1494template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1495template <bool MaybeMulti>
1496auto
1498 const_iterator hint,
1499 value_type const& value) -> iterator
1500 requires(!MaybeMulti)
1501{
1502 typename cont_type::insert_commit_data d;
1503 auto const result(
1504 cont_.insert_check(hint.iterator(), extract(value), std::cref(config_.keyCompare()), d));
1505 if (result.second)
1506 {
1507 Element* const p(newElement(value));
1508 auto const iter(cont_.insert_commit(*p, d));
1509 chronological.list_.push_back(*p);
1510 return iterator(iter);
1511 }
1512 return iterator(result.first);
1513}
1514
1515// map, set
1516template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1517template <bool MaybeMulti>
1518auto
1520 const_iterator hint,
1521 value_type&& value) -> iterator
1522 requires(!MaybeMulti)
1523{
1524 typename cont_type::insert_commit_data d;
1525 auto const result(
1526 cont_.insert_check(hint.iterator(), extract(value), std::cref(config_.keyCompare()), d));
1527 if (result.second)
1528 {
1529 Element* const p(newElement(std::move(value)));
1530 auto const iter(cont_.insert_commit(*p, d));
1531 chronological.list_.push_back(*p);
1532 return iterator(iter);
1533 }
1534 return iterator(result.first);
1535}
1536
1537// map, set
1538template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1539template <bool MaybeMulti, class... Args>
1540auto
1543 requires(!MaybeMulti)
1544{
1545 // VFALCO NOTE Its unfortunate that we need to
1546 // construct element here
1547 Element* const p(newElement(std::forward<Args>(args)...));
1548 typename cont_type::insert_commit_data d;
1549 auto const result(cont_.insert_check(extract(p->value), std::cref(config_.keyCompare()), d));
1550 if (result.second)
1551 {
1552 auto const iter(cont_.insert_commit(*p, d));
1553 chronological.list_.push_back(*p);
1554 return std::make_pair(iterator(iter), true);
1555 }
1556 deleteElement(p);
1557 return std::make_pair(iterator(result.first), false);
1558}
1559
1560// multiset, multimap
1561template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1562template <bool MaybeMulti, class... Args>
1563auto
1565 -> iterator
1566 requires MaybeMulti
1567{
1568 Element* const p(newElement(std::forward<Args>(args)...));
1569 auto const before(cont_.upper_bound(extract(p->value), std::cref(config_.keyCompare())));
1570 chronological.list_.push_back(*p);
1571 auto const iter(cont_.insert_before(before, *p));
1572 return iterator(iter);
1573}
1574
1575// map, set
1576template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1577template <bool MaybeMulti, class... Args>
1578auto
1580 const_iterator hint,
1581 Args&&... args) -> std::pair<iterator, bool>
1582 requires(!MaybeMulti)
1583{
1584 // VFALCO NOTE Its unfortunate that we need to
1585 // construct element here
1586 Element* const p(newElement(std::forward<Args>(args)...));
1587 typename cont_type::insert_commit_data d;
1588 auto const result(
1589 cont_.insert_check(hint.iterator(), extract(p->value), std::cref(config_.keyCompare()), d));
1590 if (result.second)
1591 {
1592 auto const iter(cont_.insert_commit(*p, d));
1593 chronological.list_.push_back(*p);
1594 return std::make_pair(iterator(iter), true);
1595 }
1596 deleteElement(p);
1597 return std::make_pair(iterator(result.first), false);
1598}
1599
1600template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1601template <bool IsConst, class Iterator>
1610
1611template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1612template <bool IsConst, class Iterator>
1624
1625template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1626template <class K>
1627auto
1629 -> size_type
1630{
1631 auto iter(cont_.find(k, std::cref(config_.keyCompare())));
1632 if (iter == cont_.end())
1633 return 0;
1634 size_type n(0);
1635 for (;;)
1636 {
1637 auto p(&*iter++);
1638 bool const done(config_(*p, extract(iter->value)));
1640 ++n;
1641 if (done)
1642 break;
1643 }
1644 return n;
1645}
1646
1647template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1648void
1650 AgedOrderedContainer& other) noexcept
1651{
1652 swapData(other);
1653 std::swap(chronological, other.chronological);
1654 std::swap(cont_, other.cont_);
1655}
1656
1657//------------------------------------------------------------------------------
1658
1659template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1660template <class K>
1661auto
1663 -> size_type
1664{
1665 auto const now(clock().now());
1666 size_type n(0);
1667 auto const range(equalRange(k));
1668 for (auto iter : range)
1669 {
1670 touch(iter, now);
1671 ++n;
1672 }
1673 return n;
1674}
1675
1676//------------------------------------------------------------------------------
1677
1678template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1679template <
1680 bool OtherIsMulti,
1681 bool OtherIsMap,
1682 class OtherT,
1683 class OtherDuration,
1684 class OtherAllocator>
1685bool
1688 OtherIsMulti,
1689 OtherIsMap,
1690 Key,
1691 OtherT,
1692 OtherDuration,
1693 Compare,
1694 OtherAllocator> const& other) const
1695{
1696 using Other = AgedOrderedContainer<
1697 OtherIsMulti,
1698 OtherIsMap,
1699 Key,
1700 OtherT,
1701 OtherDuration,
1702 Compare,
1703 OtherAllocator>;
1704 if (size() != other.size())
1705 return false;
1707 return std::equal(
1708 cbegin(),
1709 cend(),
1710 other.cbegin(),
1711 other.cend(),
1712 [&eq, &other](value_type const& lhs, Other::value_type const& rhs) {
1713 return eq(extract(lhs), other.extract(rhs));
1714 });
1715}
1716
1717//------------------------------------------------------------------------------
1718
1719template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1720template <bool IsConst, class Iterator>
1721void
1724 clock_type::time_point const& now)
1726{
1727 auto& e(*pos.iterator());
1728 e.when = now;
1729 chronological.list_.erase(chronological.list_.iterator_to(e));
1730 chronological.list_.push_back(e);
1731}
1732
1733template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1734template <bool MaybePropagate>
1735void
1737 AgedOrderedContainer& other) noexcept
1738 requires MaybePropagate
1739{
1740 std::swap(config_.keyCompare(), other.config_.keyCompare());
1741 std::swap(config_.alloc(), other.config_.alloc());
1742 std::swap(config_.clock, other.config_.clock);
1743}
1744
1745template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1746template <bool MaybePropagate>
1747void
1749 AgedOrderedContainer& other) noexcept
1750 requires(!MaybePropagate)
1751{
1752 std::swap(config_.keyCompare(), other.config_.keyCompare());
1753 std::swap(config_.clock, other.config_.clock);
1754}
1755
1756} // namespace detail
1757
1758//------------------------------------------------------------------------------
1759
1760template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1762 beast::detail::AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>>
1764{
1765 explicit IsAgedContainer() = default;
1766};
1767
1768// Free functions
1769
1770template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1771void
1779
1783template <
1784 bool IsMulti,
1785 bool IsMap,
1786 class Key,
1787 class T,
1788 class Clock,
1789 class Compare,
1790 class Allocator,
1791 class Rep,
1792 class Period>
1797{
1798 std::size_t n(0);
1799 auto const expired(c.clock().now() - age);
1800 for (auto iter(c.chronological.cbegin());
1801 iter != c.chronological.cend() && iter.when() <= expired;)
1802 {
1803 iter = c.erase(iter);
1804 ++n;
1805 }
1806 return n;
1807}
1808
1809} // namespace beast
T addressof(T... args)
Abstract interface to a clock.
Clock::duration duration
Clock::time_point time_point
virtual time_point now() const =0
Returns the current time.
beast::detail::AgedContainerIterator<!IsMap, typename list_type::reverse_iterator > reverse_iterator
const_iterator iteratorTo(value_type const &value) const
beast::detail::AgedContainerIterator< true, typename list_type::reverse_iterator > const_reverse_iterator
beast::detail::AgedContainerIterator<!IsMap, typename list_type::iterator > iterator
ChronologicalT(ChronologicalT const &)=delete
beast::detail::AgedContainerIterator< true, typename list_type::iterator > const_iterator
ConfigT(ConfigT const &other, Allocator const &alloc)
ConfigT(clock_type &clock, Compare const &comp, Allocator const &alloc)
ConfigT(ConfigT &&other, Allocator const &alloc)
std::reference_wrapper< clock_type > clock
ConfigT(clock_type &clock, Compare const &comp)
ConfigT(clock_type &clock, Allocator const &alloc)
bool operator()(Key const &k, Element const &e) const
bool operator()(Element const &x, Element const &y) const
bool operator()(Element const &e, Key const &k) const
bool operator()(value_type const &lhs, value_type const &rhs) const
Associative container where each element is also indexed by time.
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::iterator > iterator
AgedOrderedContainer(InputIt first, InputIt last, clock_type &clock, Compare const &comp)
AgedOrderedContainer(InputIt first, InputIt last, clock_type &clock, Compare const &comp, Allocator const &alloc)
beast::detail::AgedContainerIterator< true, typename cont_type::iterator > const_iterator
bool operator>=(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > first, beast::detail::AgedContainerIterator< IsConst, Iterator > last)
std::conditional< IsMap, T, void * >::type const & at(K const &k) const
auto emplaceHint(const_iterator hint, Args &&... args) -> std::pair< iterator, bool > requires(!MaybeMulti)
auto insert(value_type const &value) -> std::pair< iterator, bool > requires(!MaybeMulti)
bool operator<=(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
boost::intrusive::make_list< Element, boost::intrusive::constant_time_size< false > >::type list_type
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::reverse_iterator > reverse_iterator
AgedOrderedContainer & operator=(AgedOrderedContainer const &other)
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > pos)
bool operator<(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
void touch(beast::detail::AgedContainerIterator< IsConst, Iterator > pos, clock_type::time_point const &now)
AgedOrderedContainer(std::initializer_list< value_type > init, clock_type &clock, Compare const &comp, Allocator const &alloc)
AgedOrderedContainer & operator=(std::initializer_list< value_type > init)
beast::detail::AgedContainerIterator< true, typename cont_type::reverse_iterator > const_reverse_iterator
std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > insert(const_iterator hint, P &&value)
auto insert(const_iterator hint, value_type &&value) -> iterator requires(!MaybeMulti)
std::conditional_t< IsMulti, typename boost::intrusive::make_multiset< Element, boost::intrusive::constant_time_size< true >, boost::intrusive::compare< KeyValueCompare > >::type, typename boost::intrusive::make_set< Element, boost::intrusive::constant_time_size< true >, boost::intrusive::compare< KeyValueCompare > >::type > cont_type
AgedOrderedContainer(clock_type &clock, Compare const &comp, Allocator const &alloc)
auto emplace(Args &&... args) -> std::pair< iterator, bool > requires(!MaybeMulti)
AgedOrderedContainer(std::initializer_list< value_type > init, clock_type &clock, Compare const &comp)
AgedOrderedContainer(AgedOrderedContainer const &other, Allocator const &alloc)
auto insert(const_iterator hint, value_type const &value) -> iterator requires(!MaybeMulti)
bool operator>(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
bool operator==(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
std::conditional_t< IsMap, T, void * > & operator[](Key const &key)
auto insert(value_type &&value) -> iterator requires(MaybeMulti &&!MaybeMap)
std::allocator_traits< Allocator >::template rebind_alloc< Element > ElementAllocator
auto insert(value_type &&value) -> std::pair< iterator, bool > requires(!MaybeMulti &&!MaybeMap)
AgedOrderedContainer(std::initializer_list< value_type > init, clock_type &clock)
std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > insert(P &&value)
void touch(beast::detail::AgedContainerIterator< IsConst, Iterator > pos)
AgedOrderedContainer(InputIt first, InputIt last, clock_type &clock, Allocator const &alloc)
AgedOrderedContainer(std::initializer_list< value_type > init, clock_type &clock, Allocator const &alloc)
AgedOrderedContainer(AgedOrderedContainer &&other, Allocator const &alloc)
T equal(T... args)
T forward_as_tuple(T... args)
T forward(T... args)
T is_constructible_v
T is_standard_layout_v
T lexicographical_compare(T... args)
T make_pair(T... args)
int compare(SemanticVersion const &lhs, SemanticVersion const &rhs)
Compare two SemanticVersions against each other.
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 &&value)
Element(time_point const &when, value_type const &value)
T swap(T... args)