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 <functional>
15#include <initializer_list>
16#include <memory>
17#include <type_traits>
18#include <utility>
19
20namespace beast {
21namespace detail {
22
23// Traits templates used to discern reverse_iterators, which are disallowed
24// for mutating operations.
25template <class It>
30
31template <class It>
32struct IsBoostReverseIterator<boost::intrusive::reverse_iterator<It>> : std::true_type
33{
34 explicit IsBoostReverseIterator() = default;
35};
36
53template <
54 bool IsMulti,
55 bool IsMap,
56 class Key,
57 class T,
58 class Clock = std::chrono::steady_clock,
59 class Compare = std::less<Key>,
62{
63public:
67 using key_type = Key;
68 using mapped_type = T;
72
73 // Introspection (for unit tests)
77
78private:
79 static Key const&
80 extract(value_type const& value)
81 {
83 }
84
85 // VFALCO TODO hoist to remove template argument dependencies
86 struct Element : boost::intrusive::set_base_hook<
87 boost::intrusive::link_mode<boost::intrusive::normal_link>>,
88 boost::intrusive::list_base_hook<
89 boost::intrusive::link_mode<boost::intrusive::normal_link>>
90 {
91 // Stash types here so the iterator doesn't
92 // need to see the container declaration.
100
102 {
103 }
104
106 {
107 }
108
109 template <
110 class... Args,
112 Element(time_point const& when, Args&&... args)
113 : value(std::forward<Args>(args)...), when(when)
114 {
115 }
116
119 };
120
121 // VFALCO TODO This should only be enabled for maps.
122 class PairValueCompare : public Compare
123 {
124 public:
127 using result_type = bool;
128
129 bool
130 operator()(value_type const& lhs, value_type const& rhs) const
131 {
132 return Compare::operator()(lhs.first, rhs.first);
133 }
134
135 PairValueCompare() = default;
136
137 PairValueCompare(PairValueCompare const& other) : Compare(other)
138 {
139 }
140
141 private:
143
144 PairValueCompare(Compare const& compare) : Compare(compare)
145 {
146 }
147 };
148
149 // Compares value_type against element, used in insert_check
150 // VFALCO TODO hoist to remove template argument dependencies
151 class KeyValueCompare : public Compare
152 {
153 public:
154 using first_argument = Key;
156 using result_type = bool;
157
158 KeyValueCompare() = default;
159
160 KeyValueCompare(Compare const& compare) : Compare(compare)
161 {
162 }
163
164 bool
165 operator()(Key const& k, Element const& e) const
166 {
167 return Compare::operator()(k, extract(e.value));
168 }
169
170 bool
171 operator()(Element const& e, Key const& k) const
172 {
173 return Compare::operator()(extract(e.value), k);
174 }
175
176 bool
177 operator()(Element const& x, Element const& y) const
178 {
179 return Compare::operator()(extract(x.value), extract(y.value));
180 }
181
182 Compare&
184 {
185 return *this;
186 }
187
188 [[nodiscard]] Compare const&
189 compare() const
190 {
191 return *this;
192 }
193 };
194
195 using list_type =
196 boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
197
199 IsMulti,
200 typename boost::intrusive::make_multiset<
201 Element,
202 boost::intrusive::constant_time_size<true>,
203 boost::intrusive::compare<KeyValueCompare>>::type,
204 typename boost::intrusive::make_set<
205 Element,
206 boost::intrusive::constant_time_size<true>,
207 boost::intrusive::compare<KeyValueCompare>>::type>;
208
210
212
213 class ConfigT : private KeyValueCompare,
214 public beast::detail::EmptyBaseOptimization<ElementAllocator>
215 {
216 public:
218 {
219 }
220
221 ConfigT(clock_type& clock, Compare const& comp) : KeyValueCompare(comp), clock(clock)
222 {
223 }
224
229
230 ConfigT(clock_type& clock, Compare const& comp, Allocator const& alloc)
231 : KeyValueCompare(comp)
233 , clock(clock)
234 {
235 }
236
237 ConfigT(ConfigT const& other)
238 : KeyValueCompare(other.keyCompare())
240 ElementAllocatorTraits::select_on_container_copy_construction(other.alloc()))
241 , clock(other.clock)
242 {
243 }
244
245 ConfigT(ConfigT const& other, Allocator const& alloc)
246 : KeyValueCompare(other.keyCompare())
248 , clock(other.clock)
249 {
250 }
251
253 : KeyValueCompare(std::move(other.keyCompare()))
255 static_cast<beast::detail::EmptyBaseOptimization<ElementAllocator>&>(other)))
256 , clock(other.clock)
257 {
258 }
259
261 ConfigT&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
262 Allocator const& alloc)
263 : KeyValueCompare(std::move(other.keyCompare()))
265 , clock(other.clock)
266 {
267 }
268
269 ConfigT&
270 operator=(ConfigT const& other)
271 {
272 if (this != &other)
273 {
274 compare() = other.compare();
275 alloc() = other.alloc();
276 clock = other.clock;
277 }
278 return *this;
279 }
280
281 ConfigT&
283 {
284 compare() = std::move(other.compare());
285 alloc() = std::move(other.alloc());
286 clock = other.clock;
287 return *this;
288 }
289
290 Compare&
292 {
294 }
295
296 [[nodiscard]] Compare const&
297 compare() const
298 {
300 }
301
304 {
305 return *this;
306 }
307
308 [[nodiscard]] KeyValueCompare const&
310 {
311 return *this;
312 }
313
319
320 [[nodiscard]] ElementAllocator const&
325
327 };
328
329 template <class... Args>
330 Element*
331 newElement(Args&&... args)
332 {
333 struct Deleter
334 {
336 Deleter(ElementAllocator& a) : a(a)
337 {
338 }
339
340 void
341 operator()(Element* p)
342 {
344 }
345 };
346
348 ElementAllocatorTraits::allocate(config_.alloc(), 1), Deleter(config_.alloc()));
350 config_.alloc(), p.get(), clock().now(), std::forward<Args>(args)...);
351 return p.release();
352 }
353
354 void
355 deleteElement(Element const* p)
356 {
358 ElementAllocatorTraits::deallocate(config_.alloc(), const_cast<Element*>(p), 1);
359 }
360
361 void
362 unlinkAndDeleteElement(Element const* p)
363 {
364 chronological.list_.erase(chronological.list_.iterator_to(*p));
365 cont_.erase(cont_.iterator_to(*p));
366 deleteElement(p);
367 }
368
369public:
370 using key_compare = Compare;
372 using allocator_type = Allocator;
377
378 // A set iterator (IsMap==false) is always const
379 // because the elements of a set are immutable.
386
387 //--------------------------------------------------------------------------
388 //
389 // Chronological ordered iterators
390 //
391 // "Memberspace"
392 // http://accu.org/index.php/journals/1527
393 //
394 //--------------------------------------------------------------------------
395
397 {
398 ChronologicalT() = default;
399
400 public:
401 // A set iterator (IsMap==false) is always const
402 // because the elements of a set are immutable.
410
413 {
414 return iterator(list_.begin());
415 }
416
418 begin() const
419 {
420 return const_iterator(list_.begin());
421 }
422
424 cbegin() const
425 {
426 return const_iterator(list_.begin());
427 }
428
431 {
432 return iterator(list_.end());
433 }
434
436 end() const
437 {
438 return const_iterator(list_.end());
439 }
440
442 cend() const
443 {
444 return const_iterator(list_.end());
445 }
446
449 {
450 return reverse_iterator(list_.rbegin());
451 }
452
454 rbegin() const
455 {
456 return const_reverse_iterator(list_.rbegin());
457 }
458
460 crbegin() const
461 {
462 return const_reverse_iterator(list_.rbegin());
463 }
464
467 {
468 return reverse_iterator(list_.rend());
469 }
470
472 rend() const
473 {
474 return const_reverse_iterator(list_.rend());
475 }
476
478 crend() const
479 {
480 return const_reverse_iterator(list_.rend());
481 }
482
485 {
486 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
487 return list_.iterator_to(*reinterpret_cast<Element*>(
488 reinterpret_cast<uint8_t*>(&value) -
489 ((std::size_t)std::addressof(((Element*)0)->member))));
490 }
491
493 iteratorTo(value_type const& value) const
494 {
495 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
496 return list_.iterator_to(*reinterpret_cast<Element const*>(
497 reinterpret_cast<uint8_t const*>(&value) -
498 ((std::size_t)std::addressof(((Element*)0)->member))));
499 }
500
503
504 private:
508
509 //--------------------------------------------------------------------------
510 //
511 // Construction
512 //
513 //--------------------------------------------------------------------------
514
516
518
519 AgedOrderedContainer(clock_type& clock, Compare const& comp);
520
521 AgedOrderedContainer(clock_type& clock, Allocator const& alloc);
522
523 AgedOrderedContainer(clock_type& clock, Compare const& comp, Allocator const& alloc);
524
525 template <class InputIt>
526 AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock);
527
528 template <class InputIt>
529 AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock, Compare const& comp);
530
531 template <class InputIt>
532 AgedOrderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc);
533
534 template <class InputIt>
536 InputIt first,
537 InputIt last,
539 Compare const& comp,
540 Allocator const& alloc);
541
543
544 AgedOrderedContainer(AgedOrderedContainer const& other, Allocator const& alloc);
545
547
549 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
550 AgedOrderedContainer&& other,
551 Allocator const& alloc);
552
554
558 Compare const& comp);
559
563 Allocator const& alloc);
564
568 Compare const& comp,
569 Allocator const& alloc);
570
572
575
578
581
584 {
585 return config_.alloc();
586 }
587
590 {
591 return config_.clock;
592 }
593
594 clock_type const&
595 clock() const
596 {
597 return config_.clock;
598 }
599
600 //--------------------------------------------------------------------------
601 //
602 // Element access (maps)
603 //
604 //--------------------------------------------------------------------------
605
606 template <
607 class K,
608 bool MaybeMulti = IsMulti,
609 bool MaybeMap = IsMap,
612 at(K const& k);
613
614 template <
615 class K,
616 bool MaybeMulti = IsMulti,
617 bool MaybeMap = IsMap,
620 at(K const& k) const;
621
622 template <
623 bool MaybeMulti = IsMulti,
624 bool MaybeMap = IsMap,
627 operator[](Key const& key);
628
629 template <
630 bool MaybeMulti = IsMulti,
631 bool MaybeMap = IsMap,
634 operator[](Key&& key);
635
636 //--------------------------------------------------------------------------
637 //
638 // Iterators
639 //
640 //--------------------------------------------------------------------------
641
644 {
645 return iterator(cont_.begin());
646 }
647
649 begin() const
650 {
651 return const_iterator(cont_.begin());
652 }
653
655 cbegin() const
656 {
657 return const_iterator(cont_.begin());
658 }
659
662 {
663 return iterator(cont_.end());
664 }
665
667 end() const
668 {
669 return const_iterator(cont_.end());
670 }
671
673 cend() const
674 {
675 return const_iterator(cont_.end());
676 }
677
680 {
681 return reverse_iterator(cont_.rbegin());
682 }
683
685 rbegin() const
686 {
687 return const_reverse_iterator(cont_.rbegin());
688 }
689
691 crbegin() const
692 {
693 return const_reverse_iterator(cont_.rbegin());
694 }
695
698 {
699 return reverse_iterator(cont_.rend());
700 }
701
703 rend() const
704 {
705 return const_reverse_iterator(cont_.rend());
706 }
707
709 crend() const
710 {
711 return const_reverse_iterator(cont_.rend());
712 }
713
716 {
717 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
718 return cont_.iterator_to(*reinterpret_cast<Element*>(
719 reinterpret_cast<uint8_t*>(&value) -
720 ((std::size_t)std::addressof(((Element*)0)->member))));
721 }
722
724 iteratorTo(value_type const& value) const
725 {
726 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
727 return cont_.iterator_to(*reinterpret_cast<Element const*>(
728 reinterpret_cast<uint8_t const*>(&value) -
729 ((std::size_t)std::addressof(((Element*)0)->member))));
730 }
731
732 //--------------------------------------------------------------------------
733 //
734 // Capacity
735 //
736 //--------------------------------------------------------------------------
737
738 bool
739 empty() const noexcept
740 {
741 return cont_.empty();
742 }
743
745 size() const noexcept
746 {
747 return cont_.size();
748 }
749
751 maxSize() const noexcept
752 {
753 return config_.max_size();
754 }
755
756 //--------------------------------------------------------------------------
757 //
758 // Modifiers
759 //
760 //--------------------------------------------------------------------------
761
762 void
764
765 // map, set
766 template <bool MaybeMulti = IsMulti>
767 auto
769
770 // multimap, multiset
771 template <bool MaybeMulti = IsMulti>
772 auto
774
775 // set
776 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
777 auto
780
781 // multiset
782 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
783 auto
785
786 //---
787
788 // map, set
789 template <bool MaybeMulti = IsMulti>
790 auto
792
793 // multimap, multiset
794 template <bool MaybeMulti = IsMulti>
796 insert(const_iterator /*hint*/, value_type const& value)
797 {
798 // VFALCO TODO Figure out how to utilize 'hint'
799 return insert(value);
800 }
801
802 // map, set
803 template <bool MaybeMulti = IsMulti>
804 auto
806
807 // multimap, multiset
808 template <bool MaybeMulti = IsMulti>
811 {
812 // VFALCO TODO Figure out how to utilize 'hint'
813 return insert(std::move(value));
814 }
815
816 // map, multimap
817 template <class P, bool MaybeMap = IsMap>
821 insert(P&& value)
822 {
823 return emplace(std::forward<P>(value));
824 }
825
826 // map, multimap
827 template <class P, bool MaybeMap = IsMap>
831 insert(const_iterator hint, P&& value)
832 {
833 return emplaceHint(hint, std::forward<P>(value));
834 }
835
836 template <class InputIt>
837 void
838 insert(InputIt first, InputIt last)
839 {
840 for (; first != last; ++first)
841 insert(cend(), *first);
842 }
843
844 void
846 {
847 insert(init.begin(), init.end());
848 }
849
850 // map, set
851 template <bool MaybeMulti = IsMulti, class... Args>
852 auto
854
855 // multiset, multimap
856 template <bool MaybeMulti = IsMulti, class... Args>
857 auto
859
860 // map, set
861 template <bool MaybeMulti = IsMulti, class... Args>
862 auto
863 emplaceHint(const_iterator hint, Args&&... args)
865
866 // multiset, multimap
867 template <bool MaybeMulti = IsMulti, class... Args>
869 emplaceHint(const_iterator /*hint*/, Args&&... args)
870 {
871 // VFALCO TODO Figure out how to utilize 'hint'
873 }
874
875 // enable_if prevents erase (reverse_iterator pos) from compiling
876 template <
877 bool IsConst,
878 class Iterator,
882
883 // enable_if prevents erase (reverse_iterator first, reverse_iterator last)
884 // from compiling
885 template <
886 bool IsConst,
887 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 // enable_if prevents touch (reverse_iterator pos) from compiling
904 template <
905 bool IsConst,
906 class Iterator,
908 void
913
914 template <class K>
916 touch(K const& k);
917
918 //--------------------------------------------------------------------------
919 //
920 // Lookup
921 //
922 //--------------------------------------------------------------------------
923
924 // VFALCO TODO Respect is_transparent (c++14)
925 template <class K>
927 count(K const& k) const
928 {
929 return cont_.count(k, std::cref(config_.keyCompare()));
930 }
931
932 // VFALCO TODO Respect is_transparent (c++14)
933 template <class K>
935 find(K const& k)
936 {
937 return iterator(cont_.find(k, std::cref(config_.keyCompare())));
938 }
939
940 // VFALCO TODO Respect is_transparent (c++14)
941 template <class K>
943 find(K const& k) const
944 {
945 return const_iterator(cont_.find(k, std::cref(config_.keyCompare())));
946 }
947
948 // VFALCO TODO Respect is_transparent (c++14)
949 template <class K>
951 equalRange(K const& k)
952 {
953 auto const r(cont_.equal_range(k, std::cref(config_.keyCompare())));
954 return std::make_pair(iterator(r.first), iterator(r.second));
955 }
956
957 // VFALCO TODO Respect is_transparent (c++14)
958 template <class K>
960 equalRange(K const& k) const
961 {
962 auto const r(cont_.equal_range(k, std::cref(config_.keyCompare())));
963 return std::make_pair(const_iterator(r.first), const_iterator(r.second));
964 }
965
966 // VFALCO TODO Respect is_transparent (c++14)
967 template <class K>
969 lowerBound(K const& k)
970 {
971 return iterator(cont_.lower_bound(k, std::cref(config_.keyCompare())));
972 }
973
974 // VFALCO TODO Respect is_transparent (c++14)
975 template <class K>
977 lowerBound(K const& k) const
978 {
979 return const_iterator(cont_.lower_bound(k, std::cref(config_.keyCompare())));
980 }
981
982 // VFALCO TODO Respect is_transparent (c++14)
983 template <class K>
985 upperBound(K const& k)
986 {
987 return iterator(cont_.upper_bound(k, std::cref(config_.keyCompare())));
988 }
989
990 // VFALCO TODO Respect is_transparent (c++14)
991 template <class K>
993 upperBound(K const& k) const
994 {
995 return const_iterator(cont_.upper_bound(k, std::cref(config_.keyCompare())));
996 }
997
998 //--------------------------------------------------------------------------
999 //
1000 // Observers
1001 //
1002 //--------------------------------------------------------------------------
1003
1005 keyComp() const
1006 {
1007 return config_.compare();
1008 }
1009
1010 // VFALCO TODO Should this return const reference for set?
1013 {
1014 return value_compare(config_.compare());
1015 }
1016
1017 //--------------------------------------------------------------------------
1018 //
1019 // Comparison
1020 //
1021 //--------------------------------------------------------------------------
1022
1023 // This differs from the standard in that the comparison
1024 // is only done on the key portion of the value type, ignoring
1025 // the mapped type.
1026 //
1027 template <
1028 bool OtherIsMulti,
1029 bool OtherIsMap,
1030 class OtherT,
1031 class OtherDuration,
1032 class OtherAllocator>
1033 bool
1035 OtherIsMulti,
1036 OtherIsMap,
1037 Key,
1038 OtherT,
1039 OtherDuration,
1040 Compare,
1041 OtherAllocator> const& other) const;
1042
1043 template <
1044 bool OtherIsMulti,
1045 bool OtherIsMap,
1046 class OtherT,
1047 class OtherDuration,
1048 class OtherAllocator>
1049 bool
1051 OtherIsMulti,
1052 OtherIsMap,
1053 Key,
1054 OtherT,
1055 OtherDuration,
1056 Compare,
1057 OtherAllocator> const& other) const
1058 {
1059 return !(this->operator==(other));
1060 }
1061
1062 template <
1063 bool OtherIsMulti,
1064 bool OtherIsMap,
1065 class OtherT,
1066 class OtherDuration,
1067 class OtherAllocator>
1068 bool
1070 OtherIsMulti,
1071 OtherIsMap,
1072 Key,
1073 OtherT,
1074 OtherDuration,
1075 Compare,
1076 OtherAllocator> const& other) const
1077 {
1078 value_compare const comp(valueComp());
1079 return std::lexicographical_compare(cbegin(), cend(), other.cbegin(), other.cend(), comp);
1080 }
1081
1082 template <
1083 bool OtherIsMulti,
1084 bool OtherIsMap,
1085 class OtherT,
1086 class OtherDuration,
1087 class OtherAllocator>
1088 bool
1090 OtherIsMulti,
1091 OtherIsMap,
1092 Key,
1093 OtherT,
1094 OtherDuration,
1095 Compare,
1096 OtherAllocator> const& other) const
1097 {
1098 return !(other < *this);
1099 }
1100
1101 template <
1102 bool OtherIsMulti,
1103 bool OtherIsMap,
1104 class OtherT,
1105 class OtherDuration,
1106 class OtherAllocator>
1107 bool
1109 OtherIsMulti,
1110 OtherIsMap,
1111 Key,
1112 OtherT,
1113 OtherDuration,
1114 Compare,
1115 OtherAllocator> const& other) const
1116 {
1117 return other < *this;
1118 }
1119
1120 template <
1121 bool OtherIsMulti,
1122 bool OtherIsMap,
1123 class OtherT,
1124 class OtherDuration,
1125 class OtherAllocator>
1126 bool
1128 OtherIsMulti,
1129 OtherIsMap,
1130 Key,
1131 OtherT,
1132 OtherDuration,
1133 Compare,
1134 OtherAllocator> const& other) const
1135 {
1136 return !(*this < other);
1137 }
1138
1139private:
1140 // enable_if prevents erase (reverse_iterator pos, now) from compiling
1141 template <
1142 bool IsConst,
1143 class Iterator,
1145 void
1148 clock_type::time_point const& now);
1149
1150 template <
1154
1155 template <
1159
1160private:
1161 ConfigT config_;
1163};
1164
1165//------------------------------------------------------------------------------
1166
1167template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1173
1174template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1181
1182template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1189
1190template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1193 Compare const& comp,
1194 Allocator const& alloc)
1195 : config_(clock, comp, alloc), cont_(comp)
1196{
1197}
1198
1199template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1200template <class InputIt>
1202 InputIt first,
1203 InputIt last,
1205 : config_(clock)
1206{
1207 insert(first, last);
1208}
1209
1210template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1211template <class InputIt>
1213 InputIt first,
1214 InputIt last,
1216 Compare const& comp)
1217 : config_(clock, comp), cont_(comp)
1218{
1219 insert(first, last);
1220}
1221
1222template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1223template <class InputIt>
1225 InputIt first,
1226 InputIt last,
1228 Allocator const& alloc)
1229 : config_(clock, alloc)
1230{
1231 insert(first, last);
1232}
1233
1234template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1235template <class InputIt>
1237 InputIt first,
1238 InputIt last,
1240 Compare const& comp,
1241 Allocator const& alloc)
1242 : config_(clock, comp, alloc), cont_(comp)
1243{
1244 insert(first, last);
1245}
1246
1247template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1249 AgedOrderedContainer const& other)
1250 : config_(other.config_)
1251#if BOOST_VERSION >= 108000
1252 , cont_(other.cont_.get_comp())
1253#else
1254 , cont_(other.cont_.comp())
1255#endif
1256{
1257 insert(other.cbegin(), other.cend());
1258}
1259
1260template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1262 AgedOrderedContainer const& other,
1263 Allocator const& alloc)
1264 : config_(other.config_, alloc)
1265#if BOOST_VERSION >= 108000
1266 , cont_(other.cont_.get_comp())
1267#else
1268 , cont_(other.cont_.comp())
1269#endif
1270{
1271 insert(other.cbegin(), other.cend());
1272}
1273
1274template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1276 AgedOrderedContainer&& other)
1277 : config_(std::move(other.config_)), cont_(std::move(other.cont_))
1278{
1279 chronological.list_ = std::move(other.chronological.list_);
1280}
1281
1282template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1284 AgedOrderedContainer&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
1285 Allocator const& alloc)
1286 : config_(std::move(other.config_), alloc)
1287#if BOOST_VERSION >= 108000
1288 , cont_(std::move(other.cont_.get_comp()))
1289#else
1290 , cont_(std::move(other.cont_.comp()))
1291#endif
1292
1293{
1294 insert(other.cbegin(), other.cend());
1295 other.clear();
1296}
1297
1298template <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>
1316
1317template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1326
1327template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1331 Compare const& comp,
1332 Allocator const& alloc)
1333 : config_(clock, comp, alloc), cont_(comp)
1334{
1335 insert(init.begin(), init.end());
1336}
1337
1338template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1343
1344template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1345auto
1348{
1349 if (this != &other)
1350 {
1351 clear();
1352 this->config_ = other.config_;
1353 insert(other.begin(), other.end());
1354 }
1355 return *this;
1356}
1357
1358template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1359auto
1362{
1363 clear();
1364 this->config_ = std::move(other.config_);
1365 insert(other.begin(), other.end());
1366 other.clear();
1367 return *this;
1368}
1369
1370template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1371auto
1379
1380//------------------------------------------------------------------------------
1381
1382template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1383template <class K, bool MaybeMulti, bool MaybeMap, class>
1386{
1387 auto const iter(cont_.find(k, std::cref(config_.keyCompare())));
1388 if (iter == cont_.end())
1389 throw std::out_of_range("key not found");
1390 return iter->value.second;
1391}
1392
1393template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1394template <class K, bool MaybeMulti, bool MaybeMap, class>
1397{
1398 auto const iter(cont_.find(k, std::cref(config_.keyCompare())));
1399 if (iter == cont_.end())
1400 throw std::out_of_range("key not found");
1401 return iter->value.second;
1402}
1403
1404template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1405template <bool MaybeMulti, bool MaybeMap, class>
1408{
1409 typename cont_type::insert_commit_data d;
1410 auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
1411 if (result.second)
1412 {
1413 Element* const p(newElement(
1415 cont_.insert_commit(*p, d);
1416 chronological.list_.push_back(*p);
1417 return p->value.second;
1418 }
1419 return result.first->value.second;
1420}
1421
1422template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1423template <bool MaybeMulti, bool MaybeMap, class>
1426{
1427 typename cont_type::insert_commit_data d;
1428 auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
1429 if (result.second)
1430 {
1431 Element* const p(newElement(
1433 std::forward_as_tuple(std::move(key)),
1435 cont_.insert_commit(*p, d);
1436 chronological.list_.push_back(*p);
1437 return p->value.second;
1438 }
1439 return result.first->value.second;
1440}
1441
1442//------------------------------------------------------------------------------
1443
1444template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1445void
1447{
1448 for (auto iter(chronological.list_.begin()); iter != chronological.list_.end();)
1449 deleteElement(&*iter++);
1450 chronological.list_.clear();
1451 cont_.clear();
1452}
1453
1454// map, set
1455template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1456template <bool MaybeMulti>
1457auto
1460{
1461 typename cont_type::insert_commit_data d;
1462 auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
1463 if (result.second)
1464 {
1465 Element* const p(newElement(value));
1466 auto const iter(cont_.insert_commit(*p, d));
1467 chronological.list_.push_back(*p);
1468 return std::make_pair(iterator(iter), true);
1469 }
1470 return std::make_pair(iterator(result.first), false);
1471}
1472
1473// multimap, multiset
1474template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1475template <bool MaybeMulti>
1476auto
1479{
1480 auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare())));
1481 Element* const p(newElement(value));
1482 chronological.list_.push_back(*p);
1483 auto const iter(cont_.insert_before(before, *p));
1484 return iterator(iter);
1485}
1486
1487// set
1488template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1489template <bool MaybeMulti, bool MaybeMap>
1490auto
1493{
1494 typename cont_type::insert_commit_data d;
1495 auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
1496 if (result.second)
1497 {
1498 Element* const p(newElement(std::move(value)));
1499 auto const iter(cont_.insert_commit(*p, d));
1500 chronological.list_.push_back(*p);
1501 return std::make_pair(iterator(iter), true);
1502 }
1503 return std::make_pair(iterator(result.first), false);
1504}
1505
1506// multiset
1507template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1508template <bool MaybeMulti, bool MaybeMap>
1509auto
1512{
1513 auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare())));
1514 Element* const p(newElement(std::move(value)));
1515 chronological.list_.push_back(*p);
1516 auto const iter(cont_.insert_before(before, *p));
1517 return iterator(iter);
1518}
1519
1520//---
1521
1522// map, set
1523template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1524template <bool MaybeMulti>
1525auto
1527 const_iterator hint,
1529{
1530 typename cont_type::insert_commit_data d;
1531 auto const result(
1532 cont_.insert_check(hint.iterator(), extract(value), std::cref(config_.keyCompare()), d));
1533 if (result.second)
1534 {
1535 Element* const p(newElement(value));
1536 auto const iter(cont_.insert_commit(*p, d));
1537 chronological.list_.push_back(*p);
1538 return iterator(iter);
1539 }
1540 return iterator(result.first);
1541}
1542
1543// map, set
1544template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1545template <bool MaybeMulti>
1546auto
1548 const_iterator hint,
1550{
1551 typename cont_type::insert_commit_data d;
1552 auto const result(
1553 cont_.insert_check(hint.iterator(), extract(value), std::cref(config_.keyCompare()), d));
1554 if (result.second)
1555 {
1556 Element* const p(newElement(std::move(value)));
1557 auto const iter(cont_.insert_commit(*p, d));
1558 chronological.list_.push_back(*p);
1559 return iterator(iter);
1560 }
1561 return iterator(result.first);
1562}
1563
1564// map, set
1565template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1566template <bool MaybeMulti, class... Args>
1567auto
1570{
1571 // VFALCO NOTE Its unfortunate that we need to
1572 // construct element here
1573 Element* const p(newElement(std::forward<Args>(args)...));
1574 typename cont_type::insert_commit_data d;
1575 auto const result(cont_.insert_check(extract(p->value), std::cref(config_.keyCompare()), d));
1576 if (result.second)
1577 {
1578 auto const iter(cont_.insert_commit(*p, d));
1579 chronological.list_.push_back(*p);
1580 return std::make_pair(iterator(iter), true);
1581 }
1582 deleteElement(p);
1583 return std::make_pair(iterator(result.first), false);
1584}
1585
1586// multiset, multimap
1587template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1588template <bool MaybeMulti, class... Args>
1589auto
1592{
1593 Element* const p(newElement(std::forward<Args>(args)...));
1594 auto const before(cont_.upper_bound(extract(p->value), std::cref(config_.keyCompare())));
1595 chronological.list_.push_back(*p);
1596 auto const iter(cont_.insert_before(before, *p));
1597 return iterator(iter);
1598}
1599
1600// map, set
1601template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1602template <bool MaybeMulti, class... Args>
1603auto
1605 const_iterator hint,
1607{
1608 // VFALCO NOTE Its unfortunate that we need to
1609 // construct element here
1610 Element* const p(newElement(std::forward<Args>(args)...));
1611 typename cont_type::insert_commit_data d;
1612 auto const result(
1613 cont_.insert_check(hint.iterator(), extract(p->value), std::cref(config_.keyCompare()), d));
1614 if (result.second)
1615 {
1616 auto const iter(cont_.insert_commit(*p, d));
1617 chronological.list_.push_back(*p);
1618 return std::make_pair(iterator(iter), true);
1619 }
1620 deleteElement(p);
1621 return std::make_pair(iterator(result.first), false);
1622}
1623
1624template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1625template <bool IsConst, class Iterator, class>
1633
1634template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1635template <bool IsConst, class Iterator, class>
1646
1647template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1648template <class K>
1649auto
1651 -> size_type
1652{
1653 auto iter(cont_.find(k, std::cref(config_.keyCompare())));
1654 if (iter == cont_.end())
1655 return 0;
1656 size_type n(0);
1657 for (;;)
1658 {
1659 auto p(&*iter++);
1660 bool const done(config_(*p, extract(iter->value)));
1662 ++n;
1663 if (done)
1664 break;
1665 }
1666 return n;
1667}
1668
1669template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1670void
1672 AgedOrderedContainer& other) noexcept
1673{
1674 swapData(other);
1675 std::swap(chronological, other.chronological);
1676 std::swap(cont_, other.cont_);
1677}
1678
1679//------------------------------------------------------------------------------
1680
1681template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1682template <class K>
1683auto
1685 -> size_type
1686{
1687 auto const now(clock().now());
1688 size_type n(0);
1689 auto const range(equalRange(k));
1690 for (auto iter : range)
1691 {
1692 touch(iter, now);
1693 ++n;
1694 }
1695 return n;
1696}
1697
1698//------------------------------------------------------------------------------
1699
1700template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1701template <
1702 bool OtherIsMulti,
1703 bool OtherIsMap,
1704 class OtherT,
1705 class OtherDuration,
1706 class OtherAllocator>
1707bool
1710 OtherIsMulti,
1711 OtherIsMap,
1712 Key,
1713 OtherT,
1714 OtherDuration,
1715 Compare,
1716 OtherAllocator> const& other) const
1717{
1718 using Other = AgedOrderedContainer<
1719 OtherIsMulti,
1720 OtherIsMap,
1721 Key,
1722 OtherT,
1723 OtherDuration,
1724 Compare,
1725 OtherAllocator>;
1726 if (size() != other.size())
1727 return false;
1729 return std::equal(
1730 cbegin(),
1731 cend(),
1732 other.cbegin(),
1733 other.cend(),
1734 [&eq, &other](value_type const& lhs, Other::value_type const& rhs) {
1735 return eq(extract(lhs), other.extract(rhs));
1736 });
1737}
1738
1739//------------------------------------------------------------------------------
1740
1741template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1742template <bool IsConst, class Iterator, class>
1743void
1746 clock_type::time_point const& now)
1747{
1748 auto& e(*pos.iterator());
1749 e.when = now;
1750 chronological.list_.erase(chronological.list_.iterator_to(e));
1751 chronological.list_.push_back(e);
1752}
1753
1754template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1755template <bool MaybePropagate>
1758 AgedOrderedContainer& other) noexcept
1759{
1760 std::swap(config_.keyCompare(), other.config_.keyCompare());
1761 std::swap(config_.alloc(), other.config_.alloc());
1762 std::swap(config_.clock, other.config_.clock);
1763}
1764
1765template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1766template <bool MaybePropagate>
1769 AgedOrderedContainer& other) noexcept
1770{
1771 std::swap(config_.keyCompare(), other.config_.keyCompare());
1772 std::swap(config_.clock, other.config_.clock);
1773}
1774
1775} // namespace detail
1776
1777//------------------------------------------------------------------------------
1778
1779template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1781 beast::detail::AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>>
1783{
1784 explicit IsAgedContainer() = default;
1785};
1786
1787// Free functions
1788
1789template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1790void
1798
1800template <
1801 bool IsMulti,
1802 bool IsMap,
1803 class Key,
1804 class T,
1805 class Clock,
1806 class Compare,
1807 class Allocator,
1808 class Rep,
1809 class Period>
1814{
1815 std::size_t n(0);
1816 auto const expired(c.clock().now() - age);
1817 for (auto iter(c.chronological.cbegin());
1818 iter != c.chronological.cend() && iter.when() <= expired;)
1819 {
1820 iter = c.erase(iter);
1821 ++n;
1822 }
1823 return n;
1824}
1825
1826} // 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.
std::enable_if_t< MaybeMap &&std::is_constructible_v< value_type, P && >, std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > > insert(const_iterator hint, P &&value)
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::iterator > iterator
std::enable_if_t<!MaybePropagate > swapData(AgedOrderedContainer &other) noexcept
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)
auto insert(const_iterator hint, value_type const &value) -> std::enable_if_t<!MaybeMulti, iterator >
beast::detail::AgedContainerIterator< true, typename cont_type::iterator > const_iterator
void touch(beast::detail::AgedContainerIterator< IsConst, Iterator > pos)
bool operator>=(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
std::enable_if_t< MaybeMap &&std::is_constructible_v< value_type, P && >, std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > > insert(P &&value)
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)
auto emplaceHint(const_iterator hint, Args &&... args) -> std::enable_if_t<!MaybeMulti, std::pair< iterator, bool > >
bool operator<(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
auto insert(value_type &&value) -> std::enable_if_t< MaybeMulti &&!MaybeMap, iterator >
auto emplace(Args &&... args) -> std::enable_if_t<!MaybeMulti, std::pair< iterator, bool > >
AgedOrderedContainer(std::initializer_list< value_type > init, clock_type &clock, Compare const &comp, Allocator const &alloc)
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > pos)
void touch(beast::detail::AgedContainerIterator< IsConst, Iterator > pos, clock_type::time_point const &now)
AgedOrderedContainer & operator=(std::initializer_list< value_type > init)
auto insert(value_type const &value) -> std::enable_if_t< MaybeMulti, iterator >
beast::detail::AgedContainerIterator< true, typename cont_type::reverse_iterator > const_reverse_iterator
std::enable_if_t< MaybePropagate > swapData(AgedOrderedContainer &other) noexcept
std::conditional_t< IsMap, T, void * > & operator[](Key const &key)
std::enable_if_t< MaybeMulti, iterator > insert(const_iterator, value_type &&value)
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)
AgedOrderedContainer(std::initializer_list< value_type > init, clock_type &clock, Compare const &comp)
AgedOrderedContainer(AgedOrderedContainer const &other, Allocator const &alloc)
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
bool operator!=(AgedOrderedContainer< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
auto insert(const_iterator hint, value_type &&value) -> std::enable_if_t<!MaybeMulti, iterator >
auto insert(value_type const &value) -> std::enable_if_t<!MaybeMulti, std::pair< iterator, bool > >
std::allocator_traits< Allocator >::template rebind_alloc< Element > ElementAllocator
auto insert(value_type &&value) -> std::enable_if_t<!MaybeMulti &&!MaybeMap, std::pair< iterator, bool > >
AgedOrderedContainer(std::initializer_list< value_type > init, clock_type &clock)
auto emplace(Args &&... args) -> std::enable_if_t< MaybeMulti, iterator >
std::conditional< IsMap, T, void * >::type const & at(K const &k) const
std::enable_if_t< MaybeMulti, iterator > emplaceHint(const_iterator, Args &&... args)
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > first, beast::detail::AgedContainerIterator< IsConst, Iterator > last)
AgedOrderedContainer(InputIt first, InputIt last, clock_type &clock, Allocator const &alloc)
std::enable_if_t< MaybeMulti, iterator > insert(const_iterator, value_type const &value)
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::enable_if_t< IsAgedContainer< AgedContainer >::value, 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, value_type &&value)
Element(time_point const &when, value_type const &value)
Element(time_point const &when, Args &&... args)
T swap(T... args)