rippled
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 is_boost_reverse_iterator<boost::intrusive::reverse_iterator<It>> : std::true_type
33{
34 explicit is_boost_reverse_iterator() = 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<boost::intrusive::link_mode<boost::intrusive::normal_link>>,
87 boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>
88 {
89 // Stash types here so the iterator doesn't
90 // need to see the container declaration.
91 struct stashed
92 {
93 explicit stashed() = default;
94
97 };
98
99 element(time_point const& when_, value_type const& value_) : value(value_), when(when_)
100 {
101 }
102
103 element(time_point const& when_, value_type&& value_) : value(std::move(value_)), when(when_)
104 {
105 }
106
107 template <
108 class... Args,
109 class = typename std::enable_if<std::is_constructible<value_type, Args...>::value>::type>
110 element(time_point const& when_, Args&&... args) : value(std::forward<Args>(args)...), when(when_)
111 {
112 }
113
116 };
117
118 // VFALCO TODO This should only be enabled for maps.
119 class pair_value_compare : public Compare
120 {
121 public:
124 using result_type = bool;
125
126 bool
127 operator()(value_type const& lhs, value_type const& rhs) const
128 {
129 return Compare::operator()(lhs.first, rhs.first);
130 }
131
133 {
134 }
135
136 pair_value_compare(pair_value_compare const& other) : Compare(other)
137 {
138 }
139
140 private:
142
143 pair_value_compare(Compare const& compare) : Compare(compare)
144 {
145 }
146 };
147
148 // Compares value_type against element, used in insert_check
149 // VFALCO TODO hoist to remove template argument dependencies
150 class KeyValueCompare : public Compare
151 {
152 public:
153 using first_argument = Key;
155 using result_type = bool;
156
157 KeyValueCompare() = default;
158
159 KeyValueCompare(Compare const& compare) : Compare(compare)
160 {
161 }
162
163 bool
164 operator()(Key const& k, element const& e) const
165 {
166 return Compare::operator()(k, extract(e.value));
167 }
168
169 bool
170 operator()(element const& e, Key const& k) const
171 {
172 return Compare::operator()(extract(e.value), k);
173 }
174
175 bool
176 operator()(element const& x, element const& y) const
177 {
178 return Compare::operator()(extract(x.value), extract(y.value));
179 }
180
181 Compare&
183 {
184 return *this;
185 }
186
187 Compare const&
188 compare() const
189 {
190 return *this;
191 }
192 };
193
194 using list_type = typename boost::intrusive::make_list<element, boost::intrusive::constant_time_size<false>>::type;
195
196 using cont_type = typename std::conditional<
197 IsMulti,
198 typename boost::intrusive::make_multiset<
199 element,
200 boost::intrusive::constant_time_size<true>,
201 boost::intrusive::compare<KeyValueCompare>>::type,
202 typename boost::intrusive::
203 make_set<element, boost::intrusive::constant_time_size<true>, boost::intrusive::compare<KeyValueCompare>>::
204 type>::type;
205
206 using ElementAllocator = typename std::allocator_traits<Allocator>::template rebind_alloc<element>;
207
209
210 class config_t : private KeyValueCompare, public beast::detail::empty_base_optimization<ElementAllocator>
211 {
212 public:
213 explicit config_t(clock_type& clock_) : clock(clock_)
214 {
215 }
216
217 config_t(clock_type& clock_, Compare const& comp) : KeyValueCompare(comp), clock(clock_)
218 {
219 }
220
221 config_t(clock_type& clock_, Allocator const& alloc_)
222 : beast::detail::empty_base_optimization<ElementAllocator>(alloc_), clock(clock_)
223 {
224 }
225
226 config_t(clock_type& clock_, Compare const& comp, Allocator const& alloc_)
227 : KeyValueCompare(comp), beast::detail::empty_base_optimization<ElementAllocator>(alloc_), clock(clock_)
228 {
229 }
230
231 config_t(config_t const& other)
234 ElementAllocatorTraits::select_on_container_copy_construction(other.alloc()))
235 , clock(other.clock)
236 {
237 }
238
239 config_t(config_t const& other, Allocator const& alloc)
242 , clock(other.clock)
243 {
244 }
245
247 : KeyValueCompare(std::move(other.key_compare()))
248 , beast::detail::empty_base_optimization<ElementAllocator>(std::move(other))
249 , clock(other.clock)
250 {
251 }
252
253 config_t(config_t&& other, Allocator const& alloc)
254 : KeyValueCompare(std::move(other.key_compare()))
256 , clock(other.clock)
257 {
258 }
259
260 config_t&
261 operator=(config_t const& other)
262 {
263 if (this != &other)
264 {
265 compare() = other.compare();
266 alloc() = other.alloc();
267 clock = other.clock;
268 }
269 return *this;
270 }
271
272 config_t&
274 {
275 compare() = std::move(other.compare());
276 alloc() = std::move(other.alloc());
277 clock = other.clock;
278 return *this;
279 }
280
281 Compare&
283 {
285 }
286
287 Compare const&
288 compare() const
289 {
291 }
292
295 {
296 return *this;
297 }
298
299 KeyValueCompare const&
301 {
302 return *this;
303 }
304
310
311 ElementAllocator const&
316
318 };
319
320 template <class... Args>
321 element*
322 new_element(Args&&... args)
323 {
324 struct Deleter
325 {
327 Deleter(ElementAllocator& a) : a_(a)
328 {
329 }
330
331 void
332 operator()(element* p)
333 {
334 ElementAllocatorTraits::deallocate(a_.get(), p, 1);
335 }
336 };
337
341 return p.release();
342 }
343
344 void
350
351 void
353 {
354 chronological.list.erase(chronological.list.iterator_to(*p));
355 m_cont.erase(m_cont.iterator_to(*p));
357 }
358
359public:
360 using key_compare = Compare;
362 using allocator_type = Allocator;
367
368 // A set iterator (IsMap==false) is always const
369 // because the elements of a set are immutable.
374
375 //--------------------------------------------------------------------------
376 //
377 // Chronological ordered iterators
378 //
379 // "Memberspace"
380 // http://accu.org/index.php/journals/1527
381 //
382 //--------------------------------------------------------------------------
383
385 {
386 public:
387 // A set iterator (IsMap==false) is always const
388 // because the elements of a set are immutable.
394
397 {
398 return iterator(list.begin());
399 }
400
402 begin() const
403 {
404 return const_iterator(list.begin());
405 }
406
408 cbegin() const
409 {
410 return const_iterator(list.begin());
411 }
412
415 {
416 return iterator(list.end());
417 }
418
420 end() const
421 {
422 return const_iterator(list.end());
423 }
424
426 cend() const
427 {
428 return const_iterator(list.end());
429 }
430
433 {
434 return reverse_iterator(list.rbegin());
435 }
436
438 rbegin() const
439 {
440 return const_reverse_iterator(list.rbegin());
441 }
442
444 crbegin() const
445 {
446 return const_reverse_iterator(list.rbegin());
447 }
448
451 {
452 return reverse_iterator(list.rend());
453 }
454
456 rend() const
457 {
458 return const_reverse_iterator(list.rend());
459 }
460
462 crend() const
463 {
464 return const_reverse_iterator(list.rend());
465 }
466
469 {
470 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
471 return list.iterator_to(*reinterpret_cast<element*>(
472 reinterpret_cast<uint8_t*>(&value) - ((std::size_t)std::addressof(((element*)0)->member))));
473 }
474
476 iterator_to(value_type const& value) const
477 {
478 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
479 return list.iterator_to(*reinterpret_cast<element const*>(
480 reinterpret_cast<uint8_t const*>(&value) - ((std::size_t)std::addressof(((element*)0)->member))));
481 }
482
483 private:
485 {
486 }
487
490
494
495 //--------------------------------------------------------------------------
496 //
497 // Construction
498 //
499 //--------------------------------------------------------------------------
500
502
504
506
507 aged_ordered_container(clock_type& clock, Allocator const& alloc);
508
509 aged_ordered_container(clock_type& clock, Compare const& comp, Allocator const& alloc);
510
511 template <class InputIt>
512 aged_ordered_container(InputIt first, InputIt last, clock_type& clock);
513
514 template <class InputIt>
515 aged_ordered_container(InputIt first, InputIt last, clock_type& clock, Compare const& comp);
516
517 template <class InputIt>
518 aged_ordered_container(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc);
519
520 template <class InputIt>
521 aged_ordered_container(InputIt first, InputIt last, clock_type& clock, Compare const& comp, Allocator const& alloc);
522
524
525 aged_ordered_container(aged_ordered_container const& other, Allocator const& alloc);
526
528
529 aged_ordered_container(aged_ordered_container&& other, Allocator const& alloc);
530
532
534
536
540 Compare const& comp,
541 Allocator const& alloc);
542
544
547
550
553
556 {
557 return m_config.alloc();
558 }
559
562 {
563 return m_config.clock;
564 }
565
566 clock_type const&
567 clock() const
568 {
569 return m_config.clock;
570 }
571
572 //--------------------------------------------------------------------------
573 //
574 // Element access (maps)
575 //
576 //--------------------------------------------------------------------------
577
578 template <
579 class K,
580 bool maybe_multi = IsMulti,
581 bool maybe_map = IsMap,
584 at(K const& k);
585
586 template <
587 class K,
588 bool maybe_multi = IsMulti,
589 bool maybe_map = IsMap,
592 at(K const& k) const;
593
594 template <
595 bool maybe_multi = IsMulti,
596 bool maybe_map = IsMap,
599 operator[](Key const& key);
600
601 template <
602 bool maybe_multi = IsMulti,
603 bool maybe_map = IsMap,
606 operator[](Key&& key);
607
608 //--------------------------------------------------------------------------
609 //
610 // Iterators
611 //
612 //--------------------------------------------------------------------------
613
616 {
617 return iterator(m_cont.begin());
618 }
619
621 begin() const
622 {
623 return const_iterator(m_cont.begin());
624 }
625
627 cbegin() const
628 {
629 return const_iterator(m_cont.begin());
630 }
631
634 {
635 return iterator(m_cont.end());
636 }
637
639 end() const
640 {
641 return const_iterator(m_cont.end());
642 }
643
645 cend() const
646 {
647 return const_iterator(m_cont.end());
648 }
649
652 {
653 return reverse_iterator(m_cont.rbegin());
654 }
655
657 rbegin() const
658 {
659 return const_reverse_iterator(m_cont.rbegin());
660 }
661
663 crbegin() const
664 {
665 return const_reverse_iterator(m_cont.rbegin());
666 }
667
670 {
671 return reverse_iterator(m_cont.rend());
672 }
673
675 rend() const
676 {
677 return const_reverse_iterator(m_cont.rend());
678 }
679
681 crend() const
682 {
683 return const_reverse_iterator(m_cont.rend());
684 }
685
688 {
689 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
690 return m_cont.iterator_to(*reinterpret_cast<element*>(
691 reinterpret_cast<uint8_t*>(&value) - ((std::size_t)std::addressof(((element*)0)->member))));
692 }
693
695 iterator_to(value_type const& value) const
696 {
697 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
698 return m_cont.iterator_to(*reinterpret_cast<element const*>(
699 reinterpret_cast<uint8_t const*>(&value) - ((std::size_t)std::addressof(((element*)0)->member))));
700 }
701
702 //--------------------------------------------------------------------------
703 //
704 // Capacity
705 //
706 //--------------------------------------------------------------------------
707
708 bool
709 empty() const noexcept
710 {
711 return m_cont.empty();
712 }
713
715 size() const noexcept
716 {
717 return m_cont.size();
718 }
719
721 max_size() const noexcept
722 {
723 return m_config.max_size();
724 }
725
726 //--------------------------------------------------------------------------
727 //
728 // Modifiers
729 //
730 //--------------------------------------------------------------------------
731
732 void
734
735 // map, set
736 template <bool maybe_multi = IsMulti>
737 auto
739
740 // multimap, multiset
741 template <bool maybe_multi = IsMulti>
742 auto
744
745 // set
746 template <bool maybe_multi = IsMulti, bool maybe_map = IsMap>
747 auto
749
750 // multiset
751 template <bool maybe_multi = IsMulti, bool maybe_map = IsMap>
752 auto
754
755 //---
756
757 // map, set
758 template <bool maybe_multi = IsMulti>
759 auto
761
762 // multimap, multiset
763 template <bool maybe_multi = IsMulti>
765 insert(const_iterator /*hint*/, value_type const& value)
766 {
767 // VFALCO TODO Figure out how to utilize 'hint'
768 return insert(value);
769 }
770
771 // map, set
772 template <bool maybe_multi = IsMulti>
773 auto
775
776 // multimap, multiset
777 template <bool maybe_multi = IsMulti>
780 {
781 // VFALCO TODO Figure out how to utilize 'hint'
782 return insert(std::move(value));
783 }
784
785 // map, multimap
786 template <class P, bool maybe_map = IsMap>
787 typename std::enable_if<
790 insert(P&& value)
791 {
792 return emplace(std::forward<P>(value));
793 }
794
795 // map, multimap
796 template <class P, bool maybe_map = IsMap>
797 typename std::enable_if<
800 insert(const_iterator hint, P&& value)
801 {
802 return emplace_hint(hint, std::forward<P>(value));
803 }
804
805 template <class InputIt>
806 void
807 insert(InputIt first, InputIt last)
808 {
809 for (; first != last; ++first)
810 insert(cend(), *first);
811 }
812
813 void
815 {
816 insert(init.begin(), init.end());
817 }
818
819 // map, set
820 template <bool maybe_multi = IsMulti, class... Args>
821 auto
823
824 // multiset, multimap
825 template <bool maybe_multi = IsMulti, class... Args>
826 auto
828
829 // map, set
830 template <bool maybe_multi = IsMulti, class... Args>
831 auto
832 emplace_hint(const_iterator hint, Args&&... args) ->
834
835 // multiset, multimap
836 template <bool maybe_multi = IsMulti, class... Args>
838 emplace_hint(const_iterator /*hint*/, Args&&... args)
839 {
840 // VFALCO TODO Figure out how to utilize 'hint'
841 return emplace<maybe_multi>(std::forward<Args>(args)...);
842 }
843
844 // enable_if prevents erase (reverse_iterator pos) from compiling
845 template <bool is_const, class Iterator, class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
848
849 // enable_if prevents erase (reverse_iterator first, reverse_iterator last)
850 // from compiling
851 template <bool is_const, class Iterator, class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
856
857 template <class K>
858 auto
859 erase(K const& k) -> size_type;
860
861 void
862 swap(aged_ordered_container& other) noexcept;
863
864 //--------------------------------------------------------------------------
865
866 // enable_if prevents touch (reverse_iterator pos) from compiling
867 template <bool is_const, class Iterator, class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
868 void
873
874 template <class K>
876 touch(K const& k);
877
878 //--------------------------------------------------------------------------
879 //
880 // Lookup
881 //
882 //--------------------------------------------------------------------------
883
884 // VFALCO TODO Respect is_transparent (c++14)
885 template <class K>
887 count(K const& k) const
888 {
889 return m_cont.count(k, std::cref(m_config.key_compare()));
890 }
891
892 // VFALCO TODO Respect is_transparent (c++14)
893 template <class K>
895 find(K const& k)
896 {
897 return iterator(m_cont.find(k, std::cref(m_config.key_compare())));
898 }
899
900 // VFALCO TODO Respect is_transparent (c++14)
901 template <class K>
903 find(K const& k) const
904 {
906 }
907
908 // VFALCO TODO Respect is_transparent (c++14)
909 template <class K>
911 equal_range(K const& k)
912 {
913 auto const r(m_cont.equal_range(k, std::cref(m_config.key_compare())));
914 return std::make_pair(iterator(r.first), iterator(r.second));
915 }
916
917 // VFALCO TODO Respect is_transparent (c++14)
918 template <class K>
920 equal_range(K const& k) const
921 {
922 auto const r(m_cont.equal_range(k, std::cref(m_config.key_compare())));
923 return std::make_pair(const_iterator(r.first), const_iterator(r.second));
924 }
925
926 // VFALCO TODO Respect is_transparent (c++14)
927 template <class K>
929 lower_bound(K const& k)
930 {
931 return iterator(m_cont.lower_bound(k, std::cref(m_config.key_compare())));
932 }
933
934 // VFALCO TODO Respect is_transparent (c++14)
935 template <class K>
937 lower_bound(K const& k) const
938 {
939 return const_iterator(m_cont.lower_bound(k, std::cref(m_config.key_compare())));
940 }
941
942 // VFALCO TODO Respect is_transparent (c++14)
943 template <class K>
945 upper_bound(K const& k)
946 {
947 return iterator(m_cont.upper_bound(k, std::cref(m_config.key_compare())));
948 }
949
950 // VFALCO TODO Respect is_transparent (c++14)
951 template <class K>
953 upper_bound(K const& k) const
954 {
955 return const_iterator(m_cont.upper_bound(k, std::cref(m_config.key_compare())));
956 }
957
958 //--------------------------------------------------------------------------
959 //
960 // Observers
961 //
962 //--------------------------------------------------------------------------
963
965 key_comp() const
966 {
967 return m_config.compare();
968 }
969
970 // VFALCO TODO Should this return const reference for set?
973 {
975 }
976
977 //--------------------------------------------------------------------------
978 //
979 // Comparison
980 //
981 //--------------------------------------------------------------------------
982
983 // This differs from the standard in that the comparison
984 // is only done on the key portion of the value type, ignoring
985 // the mapped type.
986 //
987 template <bool OtherIsMulti, bool OtherIsMap, class OtherT, class OtherDuration, class OtherAllocator>
988 bool
991 other) const;
992
993 template <bool OtherIsMulti, bool OtherIsMap, class OtherT, class OtherDuration, class OtherAllocator>
994 bool
1001
1002 template <bool OtherIsMulti, bool OtherIsMap, class OtherT, class OtherDuration, class OtherAllocator>
1003 bool
1004 operator<(
1006 other) const
1007 {
1008 value_compare const comp(value_comp());
1009 return std::lexicographical_compare(cbegin(), cend(), other.cbegin(), other.cend(), comp);
1010 }
1011
1012 template <bool OtherIsMulti, bool OtherIsMap, class OtherT, class OtherDuration, class OtherAllocator>
1013 bool
1014 operator<=(
1016 other) const
1017 {
1018 return !(other < *this);
1019 }
1020
1021 template <bool OtherIsMulti, bool OtherIsMap, class OtherT, class OtherDuration, class OtherAllocator>
1022 bool
1029
1030 template <bool OtherIsMulti, bool OtherIsMap, class OtherT, class OtherDuration, class OtherAllocator>
1031 bool
1034 other) const
1035 {
1036 return !(*this < other);
1037 }
1038
1039private:
1040 // enable_if prevents erase (reverse_iterator pos, now) from compiling
1041 template <bool is_const, class Iterator, class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
1042 void
1044
1045 template <bool maybe_propagate = std::allocator_traits<Allocator>::propagate_on_container_swap::value>
1048
1049 template <bool maybe_propagate = std::allocator_traits<Allocator>::propagate_on_container_swap::value>
1052
1053private:
1056};
1057
1058//------------------------------------------------------------------------------
1059
1060template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1065
1066template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1068 clock_type& clock,
1069 Compare const& comp)
1070 : m_config(clock, comp), m_cont(comp)
1071{
1072}
1073
1074template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1076 clock_type& clock,
1077 Allocator const& alloc)
1078 : m_config(clock, alloc)
1079{
1080}
1081
1082template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1084 clock_type& clock,
1085 Compare const& comp,
1086 Allocator const& alloc)
1087 : m_config(clock, comp, alloc), m_cont(comp)
1088{
1089}
1090
1091template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1092template <class InputIt>
1094 InputIt first,
1095 InputIt last,
1096 clock_type& clock)
1097 : m_config(clock)
1098{
1099 insert(first, last);
1100}
1101
1102template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1103template <class InputIt>
1105 InputIt first,
1106 InputIt last,
1107 clock_type& clock,
1108 Compare const& comp)
1109 : m_config(clock, comp), m_cont(comp)
1110{
1111 insert(first, last);
1112}
1113
1114template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1115template <class InputIt>
1117 InputIt first,
1118 InputIt last,
1119 clock_type& clock,
1120 Allocator const& alloc)
1121 : m_config(clock, alloc)
1122{
1123 insert(first, last);
1124}
1125
1126template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1127template <class InputIt>
1129 InputIt first,
1130 InputIt last,
1131 clock_type& clock,
1132 Compare const& comp,
1133 Allocator const& alloc)
1134 : m_config(clock, comp, alloc), m_cont(comp)
1135{
1136 insert(first, last);
1137}
1138
1139template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1141 aged_ordered_container const& other)
1142 : m_config(other.m_config)
1143#if BOOST_VERSION >= 108000
1144 , m_cont(other.m_cont.get_comp())
1145#else
1146 , m_cont(other.m_cont.comp())
1147#endif
1148{
1149 insert(other.cbegin(), other.cend());
1150}
1151
1152template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1154 aged_ordered_container const& other,
1155 Allocator const& alloc)
1156 : m_config(other.m_config, alloc)
1157#if BOOST_VERSION >= 108000
1158 , m_cont(other.m_cont.get_comp())
1159#else
1160 , m_cont(other.m_cont.comp())
1161#endif
1162{
1163 insert(other.cbegin(), other.cend());
1164}
1165
1166template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1168 aged_ordered_container&& other)
1169 : m_config(std::move(other.m_config)), m_cont(std::move(other.m_cont))
1170{
1171 chronological.list = std::move(other.chronological.list);
1172}
1173
1174template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1176 aged_ordered_container&& other,
1177 Allocator const& alloc)
1178 : m_config(std::move(other.m_config), alloc)
1179#if BOOST_VERSION >= 108000
1180 , m_cont(std::move(other.m_cont.get_comp()))
1181#else
1182 , m_cont(std::move(other.m_cont.comp()))
1183#endif
1184
1185{
1186 insert(other.cbegin(), other.cend());
1187 other.clear();
1188}
1189
1190template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1198
1199template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1202 clock_type& clock,
1203 Compare const& comp)
1204 : m_config(clock, comp), m_cont(comp)
1205{
1206 insert(init.begin(), init.end());
1207}
1208
1209template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1212 clock_type& clock,
1213 Allocator const& alloc)
1214 : m_config(clock, alloc)
1215{
1216 insert(init.begin(), init.end());
1217}
1218
1219template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1222 clock_type& clock,
1223 Compare const& comp,
1224 Allocator const& alloc)
1225 : m_config(clock, comp, alloc), m_cont(comp)
1226{
1227 insert(init.begin(), init.end());
1228}
1229
1230template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1235
1236template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1237auto
1240{
1241 if (this != &other)
1242 {
1243 clear();
1244 this->m_config = other.m_config;
1245 insert(other.begin(), other.end());
1246 }
1247 return *this;
1248}
1249
1250template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1251auto
1254{
1255 clear();
1256 this->m_config = std::move(other.m_config);
1257 insert(other.begin(), other.end());
1258 other.clear();
1259 return *this;
1260}
1261
1262template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1263auto
1271
1272//------------------------------------------------------------------------------
1273
1274template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1275template <class K, bool maybe_multi, bool maybe_map, class>
1278{
1279 auto const iter(m_cont.find(k, std::cref(m_config.key_compare())));
1280 if (iter == m_cont.end())
1281 throw std::out_of_range("key not found");
1282 return iter->value.second;
1283}
1284
1285template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1286template <class K, bool maybe_multi, bool maybe_map, class>
1289{
1290 auto const iter(m_cont.find(k, std::cref(m_config.key_compare())));
1291 if (iter == m_cont.end())
1292 throw std::out_of_range("key not found");
1293 return iter->value.second;
1294}
1295
1296template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1297template <bool maybe_multi, bool maybe_map, class>
1300{
1301 typename cont_type::insert_commit_data d;
1302 auto const result(m_cont.insert_check(key, std::cref(m_config.key_compare()), d));
1303 if (result.second)
1304 {
1306 m_cont.insert_commit(*p, d);
1307 chronological.list.push_back(*p);
1308 return p->value.second;
1309 }
1310 return result.first->value.second;
1311}
1312
1313template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1314template <bool maybe_multi, bool maybe_map, class>
1317{
1318 typename cont_type::insert_commit_data d;
1319 auto const result(m_cont.insert_check(key, std::cref(m_config.key_compare()), d));
1320 if (result.second)
1321 {
1322 element* const p(
1324 m_cont.insert_commit(*p, d);
1325 chronological.list.push_back(*p);
1326 return p->value.second;
1327 }
1328 return result.first->value.second;
1329}
1330
1331//------------------------------------------------------------------------------
1332
1333template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1334void
1336{
1337 for (auto iter(chronological.list.begin()); iter != chronological.list.end();)
1338 delete_element(&*iter++);
1339 chronological.list.clear();
1340 m_cont.clear();
1341}
1342
1343// map, set
1344template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1345template <bool maybe_multi>
1346auto
1349{
1350 typename cont_type::insert_commit_data d;
1351 auto const result(m_cont.insert_check(extract(value), std::cref(m_config.key_compare()), d));
1352 if (result.second)
1353 {
1354 element* const p(new_element(value));
1355 auto const iter(m_cont.insert_commit(*p, d));
1356 chronological.list.push_back(*p);
1357 return std::make_pair(iterator(iter), true);
1358 }
1359 return std::make_pair(iterator(result.first), false);
1360}
1361
1362// multimap, multiset
1363template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1364template <bool maybe_multi>
1365auto
1368{
1369 auto const before(m_cont.upper_bound(extract(value), std::cref(m_config.key_compare())));
1370 element* const p(new_element(value));
1371 chronological.list.push_back(*p);
1372 auto const iter(m_cont.insert_before(before, *p));
1373 return iterator(iter);
1374}
1375
1376// set
1377template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1378template <bool maybe_multi, bool maybe_map>
1379auto
1382{
1383 typename cont_type::insert_commit_data d;
1384 auto const result(m_cont.insert_check(extract(value), std::cref(m_config.key_compare()), d));
1385 if (result.second)
1386 {
1387 element* const p(new_element(std::move(value)));
1388 auto const iter(m_cont.insert_commit(*p, d));
1389 chronological.list.push_back(*p);
1390 return std::make_pair(iterator(iter), true);
1391 }
1392 return std::make_pair(iterator(result.first), false);
1393}
1394
1395// multiset
1396template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1397template <bool maybe_multi, bool maybe_map>
1398auto
1401{
1402 auto const before(m_cont.upper_bound(extract(value), std::cref(m_config.key_compare())));
1403 element* const p(new_element(std::move(value)));
1404 chronological.list.push_back(*p);
1405 auto const iter(m_cont.insert_before(before, *p));
1406 return iterator(iter);
1407}
1408
1409//---
1410
1411// map, set
1412template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1413template <bool maybe_multi>
1414auto
1416 const_iterator hint,
1418{
1419 typename cont_type::insert_commit_data d;
1420 auto const result(m_cont.insert_check(hint.iterator(), extract(value), std::cref(m_config.key_compare()), d));
1421 if (result.second)
1422 {
1423 element* const p(new_element(value));
1424 auto const iter(m_cont.insert_commit(*p, d));
1425 chronological.list.push_back(*p);
1426 return iterator(iter);
1427 }
1428 return iterator(result.first);
1429}
1430
1431// map, set
1432template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1433template <bool maybe_multi>
1434auto
1436 const_iterator hint,
1438{
1439 typename cont_type::insert_commit_data d;
1440 auto const result(m_cont.insert_check(hint.iterator(), extract(value), std::cref(m_config.key_compare()), d));
1441 if (result.second)
1442 {
1443 element* const p(new_element(std::move(value)));
1444 auto const iter(m_cont.insert_commit(*p, d));
1445 chronological.list.push_back(*p);
1446 return iterator(iter);
1447 }
1448 return iterator(result.first);
1449}
1450
1451// map, set
1452template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1453template <bool maybe_multi, class... Args>
1454auto
1457{
1458 // VFALCO NOTE Its unfortunate that we need to
1459 // construct element here
1460 element* const p(new_element(std::forward<Args>(args)...));
1461 typename cont_type::insert_commit_data d;
1462 auto const result(m_cont.insert_check(extract(p->value), std::cref(m_config.key_compare()), d));
1463 if (result.second)
1464 {
1465 auto const iter(m_cont.insert_commit(*p, d));
1466 chronological.list.push_back(*p);
1467 return std::make_pair(iterator(iter), true);
1468 }
1469 delete_element(p);
1470 return std::make_pair(iterator(result.first), false);
1471}
1472
1473// multiset, multimap
1474template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1475template <bool maybe_multi, class... Args>
1476auto
1479{
1480 element* const p(new_element(std::forward<Args>(args)...));
1481 auto const before(m_cont.upper_bound(extract(p->value), std::cref(m_config.key_compare())));
1482 chronological.list.push_back(*p);
1483 auto const iter(m_cont.insert_before(before, *p));
1484 return iterator(iter);
1485}
1486
1487// map, set
1488template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1489template <bool maybe_multi, class... Args>
1490auto
1492 const_iterator hint,
1493 Args&&... args) -> typename std::enable_if<!maybe_multi, std::pair<iterator, bool>>::type
1494{
1495 // VFALCO NOTE Its unfortunate that we need to
1496 // construct element here
1497 element* const p(new_element(std::forward<Args>(args)...));
1498 typename cont_type::insert_commit_data d;
1499 auto const result(m_cont.insert_check(hint.iterator(), extract(p->value), std::cref(m_config.key_compare()), d));
1500 if (result.second)
1501 {
1502 auto const iter(m_cont.insert_commit(*p, d));
1503 chronological.list.push_back(*p);
1504 return std::make_pair(iterator(iter), true);
1505 }
1506 delete_element(p);
1507 return std::make_pair(iterator(result.first), false);
1508}
1509
1510template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1511template <bool is_const, class Iterator, class>
1519
1520template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1521template <bool is_const, class Iterator, class>
1532
1533template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1534template <class K>
1535auto
1537{
1538 auto iter(m_cont.find(k, std::cref(m_config.key_compare())));
1539 if (iter == m_cont.end())
1540 return 0;
1541 size_type n(0);
1542 for (;;)
1543 {
1544 auto p(&*iter++);
1545 bool const done(m_config(*p, extract(iter->value)));
1546 unlink_and_delete_element(p);
1547 ++n;
1548 if (done)
1549 break;
1550 }
1551 return n;
1552}
1553
1554template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1555void
1557{
1558 swap_data(other);
1559 std::swap(chronological, other.chronological);
1560 std::swap(m_cont, other.m_cont);
1561}
1562
1563//------------------------------------------------------------------------------
1564
1565template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1566template <class K>
1567auto
1569{
1570 auto const now(clock().now());
1571 size_type n(0);
1572 auto const range(equal_range(k));
1573 for (auto iter : range)
1574 {
1575 touch(iter, now);
1576 ++n;
1577 }
1578 return n;
1579}
1580
1581//------------------------------------------------------------------------------
1582
1583template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1584template <bool OtherIsMulti, bool OtherIsMap, class OtherT, class OtherDuration, class OtherAllocator>
1585bool
1588 const
1589{
1591 if (size() != other.size())
1592 return false;
1594 return std::equal(
1595 cbegin(),
1596 cend(),
1597 other.cbegin(),
1598 other.cend(),
1599 [&eq, &other](value_type const& lhs, typename Other::value_type const& rhs) {
1600 return eq(extract(lhs), other.extract(rhs));
1601 });
1602}
1603
1604//------------------------------------------------------------------------------
1605
1606template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1607template <bool is_const, class Iterator, class>
1608void
1611 typename clock_type::time_point const& now)
1612{
1613 auto& e(*pos.iterator());
1614 e.when = now;
1615 chronological.list.erase(chronological.list.iterator_to(e));
1616 chronological.list.push_back(e);
1617}
1618
1619template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1620template <bool maybe_propagate>
1623 aged_ordered_container& other) noexcept
1624{
1625 std::swap(m_config.key_compare(), other.m_config.key_compare());
1626 std::swap(m_config.alloc(), other.m_config.alloc());
1627 std::swap(m_config.clock, other.m_config.clock);
1628}
1629
1630template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1631template <bool maybe_propagate>
1634 aged_ordered_container& other) noexcept
1635{
1636 std::swap(m_config.key_compare(), other.m_config.key_compare());
1637 std::swap(m_config.clock, other.m_config.clock);
1638}
1639
1640} // namespace detail
1641
1642//------------------------------------------------------------------------------
1643
1644template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1645struct is_aged_container<beast::detail::aged_ordered_container<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>>
1647{
1648 explicit is_aged_container() = default;
1649};
1650
1651// Free functions
1652
1653template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
1654void
1661
1663template <
1664 bool IsMulti,
1665 bool IsMap,
1666 class Key,
1667 class T,
1668 class Clock,
1669 class Compare,
1670 class Allocator,
1671 class Rep,
1672 class Period>
1677{
1678 std::size_t n(0);
1679 auto const expired(c.clock().now() - age);
1680 for (auto iter(c.chronological.cbegin()); iter != c.chronological.cend() && iter.when() <= expired;)
1681 {
1682 iter = c.erase(iter);
1683 ++n;
1684 }
1685 return n;
1686}
1687
1688} // namespace beast
T addressof(T... args)
T allocate(T... args)
Abstract interface to a clock.
typename Clock::time_point time_point
virtual time_point now() const =0
Returns the current time.
typename Clock::duration duration
bool operator()(element const &e, Key const &k) const
bool operator()(element const &x, element const &y) const
bool operator()(Key const &k, element const &e) const
const_iterator iterator_to(value_type const &value) const
beast::detail::aged_container_iterator< true, typename list_type::reverse_iterator > const_reverse_iterator
beast::detail::aged_container_iterator<!IsMap, typename list_type::reverse_iterator > reverse_iterator
beast::detail::aged_container_iterator<!IsMap, typename list_type::iterator > iterator
beast::detail::aged_container_iterator< true, typename list_type::iterator > const_iterator
config_t(config_t const &other, Allocator const &alloc)
config_t(clock_type &clock_, Allocator const &alloc_)
config_t(clock_type &clock_, Compare const &comp, Allocator const &alloc_)
config_t(config_t &&other, Allocator const &alloc)
config_t(clock_type &clock_, Compare const &comp)
bool operator()(value_type const &lhs, value_type const &rhs) const
Associative container where each element is also indexed by time.
std::conditional< IsMap, T, void * >::type & operator[](Key const &key)
aged_ordered_container(aged_ordered_container &&other, Allocator const &alloc)
typename std::conditional< 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 >::type cont_type
std::enable_if< maybe_multi, iterator >::type emplace_hint(const_iterator, Args &&... args)
typename std::allocator_traits< Allocator >::const_pointer const_pointer
aged_ordered_container(aged_ordered_container &&other)
auto insert(const_iterator hint, value_type const &value) -> typename std::enable_if<!maybe_multi, iterator >::type
std::conditional< IsMap, T, void * >::type & at(K const &k)
typename std::allocator_traits< Allocator >::pointer pointer
aged_ordered_container & operator=(std::initializer_list< value_type > init)
typename std::allocator_traits< Allocator >::template rebind_alloc< element > ElementAllocator
auto insert(value_type const &value) -> typename std::enable_if< maybe_multi, iterator >::type
const_iterator find(K const &k) const
beast::detail::aged_container_iterator< true, typename cont_type::reverse_iterator > const_reverse_iterator
typename boost::intrusive::make_list< element, boost::intrusive::constant_time_size< false > >::type list_type
typename std::conditional< IsMap, pair_value_compare, Compare >::type value_compare
void swap(aged_ordered_container &other) noexcept
beast::detail::aged_container_iterator< false, Iterator > erase(beast::detail::aged_container_iterator< is_const, Iterator > pos)
auto insert(value_type &&value) -> typename std::enable_if<!maybe_multi &&!maybe_map, std::pair< iterator, bool > >::type
aged_ordered_container(clock_type &clock, Compare const &comp)
aged_ordered_container(aged_ordered_container const &other, Allocator const &alloc)
aged_ordered_container(std::initializer_list< value_type > init, clock_type &clock, Compare const &comp, Allocator const &alloc)
aged_ordered_container(std::initializer_list< value_type > init, clock_type &clock, Allocator const &alloc)
bool operator<=(aged_ordered_container< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
aged_ordered_container(std::initializer_list< value_type > init, clock_type &clock)
aged_ordered_container & operator=(aged_ordered_container const &other)
aged_ordered_container(InputIt first, InputIt last, clock_type &clock, Allocator const &alloc)
bool operator>(aged_ordered_container< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
void insert(InputIt first, InputIt last)
std::pair< iterator, iterator > equal_range(K const &k)
bool operator==(aged_ordered_container< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
aged_ordered_container(clock_type &clock, Compare const &comp, Allocator const &alloc)
std::enable_if< maybe_map &&std::is_constructible< value_type, P && >::value, typenamestd::conditional< IsMulti, iterator, std::pair< iterator, bool > >::type >::type insert(P &&value)
void insert(std::initializer_list< value_type > init)
aged_ordered_container(aged_ordered_container const &other)
beast::detail::aged_container_iterator<!IsMap, typename cont_type::iterator > iterator
aged_ordered_container(std::initializer_list< value_type > init, clock_type &clock, Compare const &comp)
std::enable_if< maybe_map &&std::is_constructible< value_type, P && >::value, typenamestd::conditional< IsMulti, iterator, std::pair< iterator, bool > >::type >::type insert(const_iterator hint, P &&value)
const_iterator lower_bound(K const &k) const
const_iterator upper_bound(K const &k) const
bool operator!=(aged_ordered_container< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
const_iterator iterator_to(value_type const &value) const
std::enable_if< maybe_propagate >::type swap_data(aged_ordered_container &other) noexcept
auto insert(value_type &&value) -> typename std::enable_if< maybe_multi &&!maybe_map, iterator >::type
auto insert(value_type const &value) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
beast::detail::aged_container_iterator< false, Iterator > erase(beast::detail::aged_container_iterator< is_const, Iterator > first, beast::detail::aged_container_iterator< is_const, Iterator > last)
std::enable_if< maybe_multi, iterator >::type insert(const_iterator, value_type const &value)
auto emplace(Args &&... args) -> typename std::enable_if< maybe_multi, iterator >::type
bool operator<(aged_ordered_container< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
auto insert(const_iterator hint, value_type &&value) -> typename std::enable_if<!maybe_multi, iterator >::type
void touch(beast::detail::aged_container_iterator< is_const, Iterator > pos, typename clock_type::time_point const &now)
void touch(beast::detail::aged_container_iterator< is_const, Iterator > pos)
class beast::detail::aged_ordered_container::chronological_t chronological
aged_ordered_container(clock_type &clock, Allocator const &alloc)
aged_ordered_container(InputIt first, InputIt last, clock_type &clock, Compare const &comp)
beast::detail::aged_container_iterator<!IsMap, typename cont_type::reverse_iterator > reverse_iterator
aged_ordered_container(InputIt first, InputIt last, clock_type &clock, Compare const &comp, Allocator const &alloc)
aged_ordered_container & operator=(aged_ordered_container &&other)
std::enable_if< maybe_multi, iterator >::type insert(const_iterator, value_type &&value)
beast::detail::aged_container_iterator< true, typename cont_type::iterator > const_iterator
bool operator>=(aged_ordered_container< OtherIsMulti, OtherIsMap, Key, OtherT, OtherDuration, Compare, OtherAllocator > const &other) const
auto emplace_hint(const_iterator hint, Args &&... args) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
std::conditional< IsMap, T, void * >::type const & at(K const &k) const
aged_ordered_container(InputIt first, InputIt last, clock_type &clock)
typename std::conditional< IsMap, std::pair< Key const, T >, Key >::type value_type
auto emplace(Args &&... args) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
std::conditional< IsMap, T, void * >::type & operator[](Key &&key)
static Key const & extract(value_type const &value)
std::pair< const_iterator, const_iterator > equal_range(K const &k) const
typename clock_type::time_point time_point
T construct(T... args)
T deallocate(T... args)
T destroy(T... args)
T equal(T... args)
T forward_as_tuple(T... args)
T is_same_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< is_aged_container< AgedContainer >::value, std::size_t >::type expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
void swap(beast::detail::aged_ordered_container< IsMulti, IsMap, Key, T, Clock, Compare, Allocator > &lhs, beast::detail::aged_ordered_container< IsMulti, IsMap, Key, T, Clock, Compare, Allocator > &rhs) noexcept
STL namespace.
T piecewise_construct
T cref(T... args)
T release(T... args)
typename aged_ordered_container::time_point time_point
typename aged_ordered_container::value_type value_type
element(time_point const &when_, value_type const &value_)
element(time_point const &when_, value_type &&value_)
element(time_point const &when_, Args &&... args)
T swap(T... args)