rippled
Loading...
Searching...
No Matches
aged_unordered_container.h
1#pragma once
2
3#include <xrpl/beast/clock/abstract_clock.h>
4#include <xrpl/beast/container/aged_container.h>
5#include <xrpl/beast/container/detail/aged_associative_container.h>
6#include <xrpl/beast/container/detail/aged_container_iterator.h>
7#include <xrpl/beast/container/detail/empty_base_optimization.h>
8
9#include <boost/intrusive/list.hpp>
10#include <boost/intrusive/unordered_set.hpp>
11
12#include <algorithm>
13#include <cmath>
14#include <functional>
15#include <initializer_list>
16#include <iterator>
17#include <memory>
18#include <type_traits>
19#include <utility>
20
21/*
22
23TODO
24
25- Add constructor variations that take a bucket count
26
27- Review for noexcept and exception guarantees
28
29- Call the safe version of is_permutation that takes 4 iterators
30
31*/
32
33#ifndef BEAST_NO_CXX14_IS_PERMUTATION
34#define BEAST_NO_CXX14_IS_PERMUTATION 1
35#endif
36
37namespace beast {
38namespace detail {
39
57template <
58 bool IsMulti,
59 bool IsMap,
60 class Key,
61 class T,
62 class Clock = std::chrono::steady_clock,
63 class Hash = std::hash<Key>,
64 class KeyEqual = std::equal_to<Key>,
65 class Allocator =
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::unordered_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.
99 struct stashed
100 {
101 explicit stashed() = default;
102
105 };
106
107 element(time_point const& when_, value_type const& value_) : value(value_), when(when_)
108 {
109 }
110
111 element(time_point const& when_, value_type&& value_)
112 : value(std::move(value_)), when(when_)
113 {
114 }
115
116 template <
117 class... Args,
118 class =
120 element(time_point const& when_, Args&&... args)
121 : value(std::forward<Args>(args)...), when(when_)
122 {
123 }
124
127 };
128
129 // VFALCO TODO hoist to remove template argument dependencies
130 class ValueHash : public Hash
131 {
132 public:
134 using result_type = size_t;
135
137 {
138 }
139
140 ValueHash(Hash const& h) : Hash(h)
141 {
142 }
143
145 operator()(element const& e) const
146 {
147 return Hash::operator()(extract(e.value));
148 }
149
150 Hash&
152 {
153 return *this;
154 }
155
156 Hash const&
158 {
159 return *this;
160 }
161 };
162
163 // Compares value_type against element, used in find/insert_check
164 // VFALCO TODO hoist to remove template argument dependencies
165 class KeyValueEqual : public KeyEqual
166 {
167 public:
170 using result_type = bool;
171
173 {
174 }
175
176 KeyValueEqual(KeyEqual const& keyEqual) : KeyEqual(keyEqual)
177 {
178 }
179
180 bool
181 operator()(Key const& k, element const& e) const
182 {
183 return KeyEqual::operator()(k, extract(e.value));
184 }
185
186 bool
187 operator()(element const& e, Key const& k) const
188 {
189 return KeyEqual::operator()(extract(e.value), k);
190 }
191
192 bool
193 operator()(element const& lhs, element const& rhs) const
194 {
195 return KeyEqual::operator()(extract(lhs.value), extract(rhs.value));
196 }
197
198 KeyEqual&
200 {
201 return *this;
202 }
203
204 KeyEqual const&
205 key_eq() const
206 {
207 return *this;
208 }
209 };
210
211 using list_type = typename boost::intrusive::
212 make_list<element, boost::intrusive::constant_time_size<false>>::type;
213
214 using cont_type = typename std::conditional<
215 IsMulti,
216 typename boost::intrusive::make_unordered_multiset<
217 element,
218 boost::intrusive::constant_time_size<true>,
219 boost::intrusive::hash<ValueHash>,
220 boost::intrusive::equal<KeyValueEqual>,
221 boost::intrusive::cache_begin<true>>::type,
222 typename boost::intrusive::make_unordered_set<
223 element,
224 boost::intrusive::constant_time_size<true>,
225 boost::intrusive::hash<ValueHash>,
226 boost::intrusive::equal<KeyValueEqual>,
227 boost::intrusive::cache_begin<true>>::type>::type;
228
229 using bucket_type = typename cont_type::bucket_type;
230 using bucket_traits = typename cont_type::bucket_traits;
231
233 typename std::allocator_traits<Allocator>::template rebind_alloc<element>;
234
236
238 typename std::allocator_traits<Allocator>::template rebind_alloc<element>;
239
241
242 class config_t : private ValueHash,
243 private KeyValueEqual,
244 private beast::detail::empty_base_optimization<ElementAllocator>
245 {
246 public:
247 explicit config_t(clock_type& clock_) : clock(clock_)
248 {
249 }
250
251 config_t(clock_type& clock_, Hash const& hash) : ValueHash(hash), clock(clock_)
252 {
253 }
254
255 config_t(clock_type& clock_, KeyEqual const& keyEqual)
256 : KeyValueEqual(keyEqual), clock(clock_)
257 {
258 }
259
260 config_t(clock_type& clock_, Allocator const& alloc_)
261 : beast::detail::empty_base_optimization<ElementAllocator>(alloc_), clock(clock_)
262 {
263 }
264
265 config_t(clock_type& clock_, Hash const& hash, KeyEqual const& keyEqual)
266 : ValueHash(hash), KeyValueEqual(keyEqual), clock(clock_)
267 {
268 }
269
270 config_t(clock_type& clock_, Hash const& hash, Allocator const& alloc_)
271 : ValueHash(hash)
273 , clock(clock_)
274 {
275 }
276
277 config_t(clock_type& clock_, KeyEqual const& keyEqual, Allocator const& alloc_)
278 : KeyValueEqual(keyEqual)
280 , clock(clock_)
281 {
282 }
283
285 clock_type& clock_,
286 Hash const& hash,
287 KeyEqual const& keyEqual,
288 Allocator const& alloc_)
289 : ValueHash(hash)
290 , KeyValueEqual(keyEqual)
292 , clock(clock_)
293 {
294 }
295
296 config_t(config_t const& other)
297 : ValueHash(other.hash_function())
298 , KeyValueEqual(other.key_eq())
300 ElementAllocatorTraits::select_on_container_copy_construction(other.alloc()))
301 , clock(other.clock)
302 {
303 }
304
305 config_t(config_t const& other, Allocator const& alloc)
306 : ValueHash(other.hash_function())
307 , KeyValueEqual(other.key_eq())
309 , clock(other.clock)
310 {
311 }
312
314 : ValueHash(std::move(other.hash_function()))
315 , KeyValueEqual(std::move(other.key_eq()))
316 , beast::detail::empty_base_optimization<ElementAllocator>(std::move(other.alloc()))
317 , clock(other.clock)
318 {
319 }
320
322 config_t&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
323 Allocator const& alloc)
324 : ValueHash(std::move(other.hash_function()))
325 , KeyValueEqual(std::move(other.key_eq()))
327 , clock(other.clock)
328 {
329 }
330
331 config_t&
332 operator=(config_t const& other)
333 {
334 hash_function() = other.hash_function();
335 key_eq() = other.key_eq();
336 alloc() = other.alloc();
337 clock = other.clock;
338 return *this;
339 }
340
341 config_t&
343 {
344 hash_function() = std::move(other.hash_function());
345 key_eq() = std::move(other.key_eq());
346 alloc() = std::move(other.alloc());
347 clock = other.clock;
348 return *this;
349 }
350
351 ValueHash&
353 {
354 return *this;
355 }
356
357 ValueHash const&
359 {
360 return *this;
361 }
362
363 Hash&
365 {
367 }
368
369 Hash const&
371 {
373 }
374
377 {
378 return *this;
379 }
380
381 KeyValueEqual const&
383 {
384 return *this;
385 }
386
387 KeyEqual&
389 {
390 return key_value_equal().key_eq();
391 }
392
393 KeyEqual const&
394 key_eq() const
395 {
396 return key_value_equal().key_eq();
397 }
398
404
405 ElementAllocator const&
410
412 };
413
415 {
416 public:
419 typename std::allocator_traits<Allocator>::template rebind_alloc<bucket_type>>;
420
422 {
423 m_vec.resize(cont_type::suggested_upper_bucket_count(0));
424 }
425
426 Buckets(Allocator const& alloc) : m_max_load_factor(1.f), m_vec(alloc)
427 {
428 m_vec.resize(cont_type::suggested_upper_bucket_count(0));
429 }
430
431 operator bucket_traits()
432 {
433 return bucket_traits(&m_vec[0], m_vec.size());
434 }
435
436 void
438 {
439 m_vec.clear();
440 }
441
444 {
445 return m_vec.max_size();
446 }
447
448 float&
450 {
451 return m_max_load_factor;
452 }
453
454 float const&
456 {
457 return m_max_load_factor;
458 }
459
460 // count is the number of buckets
461 template <class Container>
462 void
463 rehash(size_type count, Container& c)
464 {
465 size_type const size(m_vec.size());
466 if (count == size)
467 return;
468 if (count > m_vec.capacity())
469 {
470 // Need two vectors otherwise we
471 // will destroy non-empty buckets.
473 std::swap(m_vec, vec);
475 c.rehash(bucket_traits(&m_vec[0], m_vec.size()));
476 return;
477 }
478 // Rehash in place.
479 if (count > size)
480 {
481 // This should not reallocate since
482 // we checked capacity earlier.
484 c.rehash(bucket_traits(&m_vec[0], count));
485 return;
486 }
487 // Resize must happen after rehash otherwise
488 // we might destroy non-empty buckets.
489 c.rehash(bucket_traits(&m_vec[0], count));
491 }
492
493 // Resize the buckets to accommodate at least n items.
494 template <class Container>
495 void
496 resize(size_type n, Container& c)
497 {
498 size_type const suggested(cont_type::suggested_upper_bucket_count(n));
499 rehash(suggested, c);
500 }
501
502 private:
505 };
506
507 template <class... Args>
508 element*
509 new_element(Args&&... args)
510 {
511 struct Deleter
512 {
514 Deleter(ElementAllocator& a) : a_(a)
515 {
516 }
517
518 void
519 operator()(element* p)
520 {
521 ElementAllocatorTraits::deallocate(a_.get(), p, 1);
522 }
523 };
524
528 m_config.alloc(), p.get(), clock().now(), std::forward<Args>(args)...);
529 return p.release();
530 }
531
532 void
538
539 void
541 {
542 chronological.list.erase(chronological.list.iterator_to(*p));
543 m_cont.erase(m_cont.iterator_to(*p));
545 }
546
547public:
548 using hasher = Hash;
549 using key_equal = KeyEqual;
550 using allocator_type = Allocator;
555
556 // A set iterator (IsMap==false) is always const
557 // because the elements of a set are immutable.
561
566
567 //--------------------------------------------------------------------------
568 //
569 // Chronological ordered iterators
570 //
571 // "Memberspace"
572 // http://accu.org/index.php/journals/1527
573 //
574 //--------------------------------------------------------------------------
575
577 {
578 public:
579 // A set iterator (IsMap==false) is always const
580 // because the elements of a set are immutable.
581 using iterator =
589
592 {
593 return iterator(list.begin());
594 }
595
597 begin() const
598 {
599 return const_iterator(list.begin());
600 }
601
603 cbegin() const
604 {
605 return const_iterator(list.begin());
606 }
607
610 {
611 return iterator(list.end());
612 }
613
615 end() const
616 {
617 return const_iterator(list.end());
618 }
619
621 cend() const
622 {
623 return const_iterator(list.end());
624 }
625
628 {
629 return reverse_iterator(list.rbegin());
630 }
631
633 rbegin() const
634 {
635 return const_reverse_iterator(list.rbegin());
636 }
637
639 crbegin() const
640 {
641 return const_reverse_iterator(list.rbegin());
642 }
643
646 {
647 return reverse_iterator(list.rend());
648 }
649
651 rend() const
652 {
653 return const_reverse_iterator(list.rend());
654 }
655
657 crend() const
658 {
659 return const_reverse_iterator(list.rend());
660 }
661
664 {
665 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
666 return list.iterator_to(*reinterpret_cast<element*>(
667 reinterpret_cast<uint8_t*>(&value) -
668 ((std::size_t)std::addressof(((element*)0)->member))));
669 }
670
672 iterator_to(value_type const& value) const
673 {
674 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
675 return list.iterator_to(*reinterpret_cast<element const*>(
676 reinterpret_cast<uint8_t const*>(&value) -
677 ((std::size_t)std::addressof(((element*)0)->member))));
678 }
679
680 private:
682 {
683 }
684
687
691
692 //--------------------------------------------------------------------------
693 //
694 // Construction
695 //
696 //--------------------------------------------------------------------------
697
699
701
703
705
706 aged_unordered_container(clock_type& clock, Allocator const& alloc);
707
708 aged_unordered_container(clock_type& clock, Hash const& hash, KeyEqual const& key_eq);
709
710 aged_unordered_container(clock_type& clock, Hash const& hash, Allocator const& alloc);
711
712 aged_unordered_container(clock_type& clock, KeyEqual const& key_eq, Allocator const& alloc);
713
716 Hash const& hash,
717 KeyEqual const& key_eq,
718 Allocator const& alloc);
719
720 template <class InputIt>
721 aged_unordered_container(InputIt first, InputIt last, clock_type& clock);
722
723 template <class InputIt>
724 aged_unordered_container(InputIt first, InputIt last, clock_type& clock, Hash const& hash);
725
726 template <class InputIt>
728 InputIt first,
729 InputIt last,
731 KeyEqual const& key_eq);
732
733 template <class InputIt>
735 InputIt first,
736 InputIt last,
738 Allocator const& alloc);
739
740 template <class InputIt>
742 InputIt first,
743 InputIt last,
745 Hash const& hash,
746 KeyEqual const& key_eq);
747
748 template <class InputIt>
750 InputIt first,
751 InputIt last,
753 Hash const& hash,
754 Allocator const& alloc);
755
756 template <class InputIt>
758 InputIt first,
759 InputIt last,
761 KeyEqual const& key_eq,
762 Allocator const& alloc);
763
764 template <class InputIt>
766 InputIt first,
767 InputIt last,
769 Hash const& hash,
770 KeyEqual const& key_eq,
771 Allocator const& alloc);
772
774
775 aged_unordered_container(aged_unordered_container const& other, Allocator const& alloc);
776
778
780 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
782 Allocator const& alloc);
783
785
789 Hash const& hash);
790
794 KeyEqual const& key_eq);
795
799 Allocator const& alloc);
800
804 Hash const& hash,
805 KeyEqual const& key_eq);
806
810 Hash const& hash,
811 Allocator const& alloc);
812
816 KeyEqual const& key_eq,
817 Allocator const& alloc);
818
822 Hash const& hash,
823 KeyEqual const& key_eq,
824 Allocator const& alloc);
825
827
830
833
836
839 {
840 return m_config.alloc();
841 }
842
845 {
846 return m_config.clock;
847 }
848
849 clock_type const&
850 clock() const
851 {
852 return m_config.clock;
853 }
854
855 //--------------------------------------------------------------------------
856 //
857 // Element access (maps)
858 //
859 //--------------------------------------------------------------------------
860
861 template <
862 class K,
863 bool maybe_multi = IsMulti,
864 bool maybe_map = IsMap,
867 at(K const& k);
868
869 template <
870 class K,
871 bool maybe_multi = IsMulti,
872 bool maybe_map = IsMap,
875 at(K const& k) const;
876
877 template <
878 bool maybe_multi = IsMulti,
879 bool maybe_map = IsMap,
882 operator[](Key const& key);
883
884 template <
885 bool maybe_multi = IsMulti,
886 bool maybe_map = IsMap,
889 operator[](Key&& key);
890
891 //--------------------------------------------------------------------------
892 //
893 // Iterators
894 //
895 //--------------------------------------------------------------------------
896
899 {
900 return iterator(m_cont.begin());
901 }
902
904 begin() const
905 {
906 return const_iterator(m_cont.begin());
907 }
908
910 cbegin() const
911 {
912 return const_iterator(m_cont.begin());
913 }
914
917 {
918 return iterator(m_cont.end());
919 }
920
922 end() const
923 {
924 return const_iterator(m_cont.end());
925 }
926
928 cend() const
929 {
930 return const_iterator(m_cont.end());
931 }
932
935 {
936 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
937 return m_cont.iterator_to(*reinterpret_cast<element*>(
938 reinterpret_cast<uint8_t*>(&value) -
939 ((std::size_t)std::addressof(((element*)0)->member))));
940 }
941
943 iterator_to(value_type const& value) const
944 {
945 static_assert(std::is_standard_layout<element>::value, "must be standard layout");
946 return m_cont.iterator_to(*reinterpret_cast<element const*>(
947 reinterpret_cast<uint8_t const*>(&value) -
948 ((std::size_t)std::addressof(((element*)0)->member))));
949 }
950
951 //--------------------------------------------------------------------------
952 //
953 // Capacity
954 //
955 //--------------------------------------------------------------------------
956
957 bool
958 empty() const noexcept
959 {
960 return m_cont.empty();
961 }
962
964 size() const noexcept
965 {
966 return m_cont.size();
967 }
968
970 max_size() const noexcept
971 {
972 return m_config.max_size();
973 }
974
975 //--------------------------------------------------------------------------
976 //
977 // Modifiers
978 //
979 //--------------------------------------------------------------------------
980
981 void
983
984 // map, set
985 template <bool maybe_multi = IsMulti>
986 auto
987 insert(value_type const& value) ->
989
990 // multimap, multiset
991 template <bool maybe_multi = IsMulti>
992 auto
994
995 // map, set
996 template <bool maybe_multi = IsMulti, bool maybe_map = IsMap>
997 auto
998 insert(value_type&& value) ->
1000
1001 // multimap, multiset
1002 template <bool maybe_multi = IsMulti, bool maybe_map = IsMap>
1003 auto
1004 insert(value_type&& value) ->
1006
1007 // map, set
1008 template <bool maybe_multi = IsMulti>
1010 insert(const_iterator /*hint*/, value_type const& value)
1011 {
1012 // Hint is ignored but we provide the interface so
1013 // callers may use ordered and unordered interchangeably.
1014 return insert(value).first;
1015 }
1016
1017 // multimap, multiset
1018 template <bool maybe_multi = IsMulti>
1020 insert(const_iterator /*hint*/, value_type const& value)
1021 {
1022 // VFALCO TODO The hint could be used to let
1023 // the client order equal ranges
1024 return insert(value);
1025 }
1026
1027 // map, set
1028 template <bool maybe_multi = IsMulti>
1031 {
1032 // Hint is ignored but we provide the interface so
1033 // callers may use ordered and unordered interchangeably.
1034 return insert(std::move(value)).first;
1035 }
1036
1037 // multimap, multiset
1038 template <bool maybe_multi = IsMulti>
1041 {
1042 // VFALCO TODO The hint could be used to let
1043 // the client order equal ranges
1044 return insert(std::move(value));
1045 }
1046
1047 // map, multimap
1048 template <class P, bool maybe_map = IsMap>
1049 typename std::enable_if<
1052 insert(P&& value)
1053 {
1054 return emplace(std::forward<P>(value));
1055 }
1056
1057 // map, multimap
1058 template <class P, bool maybe_map = IsMap>
1059 typename std::enable_if<
1062 insert(const_iterator hint, P&& value)
1063 {
1064 return emplace_hint(hint, std::forward<P>(value));
1065 }
1066
1067 template <class InputIt>
1068 void
1069 insert(InputIt first, InputIt last)
1070 {
1072 }
1073
1074 void
1076 {
1077 insert(init.begin(), init.end());
1078 }
1079
1080 // set, map
1081 template <bool maybe_multi = IsMulti, class... Args>
1082 auto
1083 emplace(Args&&... args) ->
1085
1086 // multiset, multimap
1087 template <bool maybe_multi = IsMulti, class... Args>
1088 auto
1090
1091 // set, map
1092 template <bool maybe_multi = IsMulti, class... Args>
1093 auto
1094 emplace_hint(const_iterator /*hint*/, Args&&... args) ->
1096
1097 // multiset, multimap
1098 template <bool maybe_multi = IsMulti, class... Args>
1100 emplace_hint(const_iterator /*hint*/, Args&&... args)
1101 {
1102 // VFALCO TODO The hint could be used for multi, to let
1103 // the client order equal ranges
1104 return emplace<maybe_multi>(std::forward<Args>(args)...);
1105 }
1106
1107 template <bool is_const, class Iterator>
1110
1111 template <bool is_const, class Iterator>
1116
1117 template <class K>
1118 auto
1119 erase(K const& k) -> size_type;
1120
1121 void
1123
1124 template <bool is_const, class Iterator>
1125 void
1130
1131 template <class K>
1132 auto
1133 touch(K const& k) -> size_type;
1134
1135 //--------------------------------------------------------------------------
1136 //
1137 // Lookup
1138 //
1139 //--------------------------------------------------------------------------
1140
1141 // VFALCO TODO Respect is_transparent (c++14)
1142 template <class K>
1143 size_type
1144 count(K const& k) const
1145 {
1146 return m_cont.count(
1148 }
1149
1150 // VFALCO TODO Respect is_transparent (c++14)
1151 template <class K>
1152 iterator
1153 find(K const& k)
1154 {
1155 return iterator(m_cont.find(
1157 }
1158
1159 // VFALCO TODO Respect is_transparent (c++14)
1160 template <class K>
1162 find(K const& k) const
1163 {
1164 return const_iterator(m_cont.find(
1166 }
1167
1168 // VFALCO TODO Respect is_transparent (c++14)
1169 template <class K>
1171 equal_range(K const& k)
1172 {
1173 auto const r(m_cont.equal_range(
1175 return std::make_pair(iterator(r.first), iterator(r.second));
1176 }
1177
1178 // VFALCO TODO Respect is_transparent (c++14)
1179 template <class K>
1181 equal_range(K const& k) const
1182 {
1183 auto const r(m_cont.equal_range(
1185 return std::make_pair(const_iterator(r.first), const_iterator(r.second));
1186 }
1187
1188 //--------------------------------------------------------------------------
1189 //
1190 // Bucket interface
1191 //
1192 //--------------------------------------------------------------------------
1193
1196 {
1197 return local_iterator(m_cont.begin(n));
1198 }
1199
1202 {
1203 return const_local_iterator(m_cont.begin(n));
1204 }
1205
1208 {
1209 return const_local_iterator(m_cont.begin(n));
1210 }
1211
1214 {
1215 return local_iterator(m_cont.end(n));
1216 }
1217
1220 {
1221 return const_local_iterator(m_cont.end(n));
1222 }
1223
1226 {
1227 return const_local_iterator(m_cont.end(n));
1228 }
1229
1230 size_type
1232 {
1233 return m_cont.bucket_count();
1234 }
1235
1236 size_type
1238 {
1239 return m_buck.max_bucket_count();
1240 }
1241
1242 size_type
1244 {
1245 return m_cont.bucket_size(n);
1246 }
1247
1248 size_type
1249 bucket(Key const& k) const
1250 {
1251 XRPL_ASSERT(
1252 bucket_count() != 0,
1253 "beast::detail::aged_unordered_container::bucket : nonzero bucket "
1254 "count");
1255 return m_cont.bucket(k, std::cref(m_config.hash_function()));
1256 }
1257
1258 //--------------------------------------------------------------------------
1259 //
1260 // Hash policy
1261 //
1262 //--------------------------------------------------------------------------
1263
1264 float
1266 {
1267 return size() / static_cast<float>(m_cont.bucket_count());
1268 }
1269
1270 float
1272 {
1273 return m_buck.max_load_factor();
1274 }
1275
1276 void
1278 {
1280 }
1281
1282 void
1288
1289 void
1294
1295 //--------------------------------------------------------------------------
1296 //
1297 // Observers
1298 //
1299 //--------------------------------------------------------------------------
1300
1301 hasher const&
1303 {
1304 return m_config.hash_function();
1305 }
1306
1307 key_equal const&
1308 key_eq() const
1309 {
1310 return m_config.key_eq();
1311 }
1312
1313 //--------------------------------------------------------------------------
1314 //
1315 // Comparison
1316 //
1317 //--------------------------------------------------------------------------
1318
1319 // This differs from the standard in that the comparison
1320 // is only done on the key portion of the value type, ignoring
1321 // the mapped type.
1322 //
1323 template <
1324 bool OtherIsMap,
1325 class OtherKey,
1326 class OtherT,
1327 class OtherDuration,
1328 class OtherHash,
1329 class OtherAllocator,
1330 bool maybe_multi = IsMulti>
1333 false,
1334 OtherIsMap,
1335 OtherKey,
1336 OtherT,
1337 OtherDuration,
1338 OtherHash,
1339 KeyEqual,
1340 OtherAllocator> const& other) const;
1341
1342 template <
1343 bool OtherIsMap,
1344 class OtherKey,
1345 class OtherT,
1346 class OtherDuration,
1347 class OtherHash,
1348 class OtherAllocator,
1349 bool maybe_multi = IsMulti>
1352 true,
1353 OtherIsMap,
1354 OtherKey,
1355 OtherT,
1356 OtherDuration,
1357 OtherHash,
1358 KeyEqual,
1359 OtherAllocator> const& other) const;
1360
1361 template <
1362 bool OtherIsMulti,
1363 bool OtherIsMap,
1364 class OtherKey,
1365 class OtherT,
1366 class OtherDuration,
1367 class OtherHash,
1368 class OtherAllocator>
1369 bool
1371 OtherIsMulti,
1372 OtherIsMap,
1373 OtherKey,
1374 OtherT,
1375 OtherDuration,
1376 OtherHash,
1377 KeyEqual,
1378 OtherAllocator> const& other) const
1379 {
1380 return !(this->operator==(other));
1381 }
1382
1383private:
1384 bool
1385 would_exceed(size_type additional) const
1386 {
1387 return size() + additional > bucket_count() * max_load_factor();
1388 }
1389
1390 void
1392 {
1393 if (would_exceed(additional))
1394 m_buck.resize(size() + additional, m_cont);
1395 XRPL_ASSERT(
1397 "beast::detail::aged_unordered_container::maybe_rehash : maximum "
1398 "load factor");
1399 }
1400
1401 // map, set
1402 template <bool maybe_multi = IsMulti>
1403 auto
1406
1407 // multimap, multiset
1408 template <bool maybe_multi = IsMulti>
1409 auto
1412
1413 template <class InputIt>
1414 void
1415 insert_unchecked(InputIt first, InputIt last)
1416 {
1417 for (; first != last; ++first)
1418 insert_unchecked(*first);
1419 }
1420
1421 template <class InputIt>
1422 void
1423 insert(InputIt first, InputIt last, std::input_iterator_tag)
1424 {
1425 for (; first != last; ++first)
1426 insert(*first);
1427 }
1428
1429 template <class InputIt>
1430 void
1431 insert(InputIt first, InputIt last, std::random_access_iterator_tag)
1432 {
1433 auto const n(std::distance(first, last));
1434 maybe_rehash(n);
1435 insert_unchecked(first, last);
1436 }
1437
1438 template <bool is_const, class Iterator>
1439 void
1442 typename clock_type::time_point const& now)
1443 {
1444 auto& e(*pos.iterator());
1445 e.when = now;
1446 chronological.list.erase(chronological.list.iterator_to(e));
1447 chronological.list.push_back(e);
1448 }
1449
1450 template <
1454 {
1455 std::swap(m_config.key_compare(), other.m_config.key_compare());
1456 std::swap(m_config.alloc(), other.m_config.alloc());
1457 std::swap(m_config.clock, other.m_config.clock);
1458 }
1459
1460 template <
1464 {
1465 std::swap(m_config.key_compare(), other.m_config.key_compare());
1466 std::swap(m_config.clock, other.m_config.clock);
1467 }
1468
1469private:
1473};
1474
1475//------------------------------------------------------------------------------
1476
1477template <
1478 bool IsMulti,
1479 bool IsMap,
1480 class Key,
1481 class T,
1482 class Clock,
1483 class Hash,
1484 class KeyEqual,
1485 class Allocator>
1488 : m_config(clock)
1489 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1490{
1491}
1492
1493template <
1494 bool IsMulti,
1495 bool IsMap,
1496 class Key,
1497 class T,
1498 class Clock,
1499 class Hash,
1500 class KeyEqual,
1501 class Allocator>
1503 aged_unordered_container(clock_type& clock, Hash const& hash)
1504 : m_config(clock, hash)
1505 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1506{
1507}
1508
1509template <
1510 bool IsMulti,
1511 bool IsMap,
1512 class Key,
1513 class T,
1514 class Clock,
1515 class Hash,
1516 class KeyEqual,
1517 class Allocator>
1519 aged_unordered_container(clock_type& clock, KeyEqual const& key_eq)
1520 : m_config(clock, key_eq)
1521 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1522{
1523}
1524
1525template <
1526 bool IsMulti,
1527 bool IsMap,
1528 class Key,
1529 class T,
1530 class Clock,
1531 class Hash,
1532 class KeyEqual,
1533 class Allocator>
1535 aged_unordered_container(clock_type& clock, Allocator const& alloc)
1536 : m_config(clock, alloc)
1537 , m_buck(alloc)
1538 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1539{
1540}
1541
1542template <
1543 bool IsMulti,
1544 bool IsMap,
1545 class Key,
1546 class T,
1547 class Clock,
1548 class Hash,
1549 class KeyEqual,
1550 class Allocator>
1552 aged_unordered_container(clock_type& clock, Hash const& hash, KeyEqual const& key_eq)
1553 : m_config(clock, hash, key_eq)
1554 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1555{
1556}
1557
1558template <
1559 bool IsMulti,
1560 bool IsMap,
1561 class Key,
1562 class T,
1563 class Clock,
1564 class Hash,
1565 class KeyEqual,
1566 class Allocator>
1568 aged_unordered_container(clock_type& clock, Hash const& hash, Allocator const& alloc)
1569 : m_config(clock, hash, alloc)
1570 , m_buck(alloc)
1571 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1572{
1573}
1574
1575template <
1576 bool IsMulti,
1577 bool IsMap,
1578 class Key,
1579 class T,
1580 class Clock,
1581 class Hash,
1582 class KeyEqual,
1583 class Allocator>
1585 aged_unordered_container(clock_type& clock, KeyEqual const& key_eq, Allocator const& alloc)
1586 : m_config(clock, key_eq, alloc)
1587 , m_buck(alloc)
1588 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1589{
1590}
1591
1592template <
1593 bool IsMulti,
1594 bool IsMap,
1595 class Key,
1596 class T,
1597 class Clock,
1598 class Hash,
1599 class KeyEqual,
1600 class Allocator>
1603 clock_type& clock,
1604 Hash const& hash,
1605 KeyEqual const& key_eq,
1606 Allocator const& alloc)
1607 : m_config(clock, hash, key_eq, alloc)
1608 , m_buck(alloc)
1609 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1610{
1611}
1612
1613template <
1614 bool IsMulti,
1615 bool IsMap,
1616 class Key,
1617 class T,
1618 class Clock,
1619 class Hash,
1620 class KeyEqual,
1621 class Allocator>
1622template <class InputIt>
1624 aged_unordered_container(InputIt first, InputIt last, clock_type& clock)
1625 : m_config(clock)
1626 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1627{
1628 insert(first, last);
1629}
1630
1631template <
1632 bool IsMulti,
1633 bool IsMap,
1634 class Key,
1635 class T,
1636 class Clock,
1637 class Hash,
1638 class KeyEqual,
1639 class Allocator>
1640template <class InputIt>
1642 aged_unordered_container(InputIt first, InputIt last, clock_type& clock, Hash const& hash)
1643 : m_config(clock, hash)
1644 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1645{
1646 insert(first, last);
1647}
1648
1649template <
1650 bool IsMulti,
1651 bool IsMap,
1652 class Key,
1653 class T,
1654 class Clock,
1655 class Hash,
1656 class KeyEqual,
1657 class Allocator>
1658template <class InputIt>
1660 aged_unordered_container(InputIt first, InputIt last, clock_type& clock, KeyEqual const& key_eq)
1661 : m_config(clock, key_eq)
1662 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1663{
1664 insert(first, last);
1665}
1666
1667template <
1668 bool IsMulti,
1669 bool IsMap,
1670 class Key,
1671 class T,
1672 class Clock,
1673 class Hash,
1674 class KeyEqual,
1675 class Allocator>
1676template <class InputIt>
1678 aged_unordered_container(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc)
1679 : m_config(clock, alloc)
1680 , m_buck(alloc)
1681 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1682{
1683 insert(first, last);
1684}
1685
1686template <
1687 bool IsMulti,
1688 bool IsMap,
1689 class Key,
1690 class T,
1691 class Clock,
1692 class Hash,
1693 class KeyEqual,
1694 class Allocator>
1695template <class InputIt>
1698 InputIt first,
1699 InputIt last,
1700 clock_type& clock,
1701 Hash const& hash,
1702 KeyEqual const& key_eq)
1703 : m_config(clock, hash, key_eq)
1704 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1705{
1706 insert(first, last);
1707}
1708
1709template <
1710 bool IsMulti,
1711 bool IsMap,
1712 class Key,
1713 class T,
1714 class Clock,
1715 class Hash,
1716 class KeyEqual,
1717 class Allocator>
1718template <class InputIt>
1721 InputIt first,
1722 InputIt last,
1723 clock_type& clock,
1724 Hash const& hash,
1725 Allocator const& alloc)
1726 : m_config(clock, hash, alloc)
1727 , m_buck(alloc)
1728 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1729{
1730 insert(first, last);
1731}
1732
1733template <
1734 bool IsMulti,
1735 bool IsMap,
1736 class Key,
1737 class T,
1738 class Clock,
1739 class Hash,
1740 class KeyEqual,
1741 class Allocator>
1742template <class InputIt>
1745 InputIt first,
1746 InputIt last,
1747 clock_type& clock,
1748 KeyEqual const& key_eq,
1749 Allocator const& alloc)
1750 : m_config(clock, key_eq, alloc)
1751 , m_buck(alloc)
1752 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1753{
1754 insert(first, last);
1755}
1756
1757template <
1758 bool IsMulti,
1759 bool IsMap,
1760 class Key,
1761 class T,
1762 class Clock,
1763 class Hash,
1764 class KeyEqual,
1765 class Allocator>
1766template <class InputIt>
1769 InputIt first,
1770 InputIt last,
1771 clock_type& clock,
1772 Hash const& hash,
1773 KeyEqual const& key_eq,
1774 Allocator const& alloc)
1775 : m_config(clock, hash, key_eq, alloc)
1776 , m_buck(alloc)
1777 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1778{
1779 insert(first, last);
1780}
1781
1782template <
1783 bool IsMulti,
1784 bool IsMap,
1785 class Key,
1786 class T,
1787 class Clock,
1788 class Hash,
1789 class KeyEqual,
1790 class Allocator>
1793 : m_config(other.m_config)
1794 , m_buck(m_config.alloc())
1795 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1796{
1797 insert(other.cbegin(), other.cend());
1798}
1799
1800template <
1801 bool IsMulti,
1802 bool IsMap,
1803 class Key,
1804 class T,
1805 class Clock,
1806 class Hash,
1807 class KeyEqual,
1808 class Allocator>
1810 aged_unordered_container(aged_unordered_container const& other, Allocator const& alloc)
1811 : m_config(other.m_config, alloc)
1812 , m_buck(alloc)
1813 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1814{
1815 insert(other.cbegin(), other.cend());
1816}
1817
1818template <
1819 bool IsMulti,
1820 bool IsMap,
1821 class Key,
1822 class T,
1823 class Clock,
1824 class Hash,
1825 class KeyEqual,
1826 class Allocator>
1829 : m_config(std::move(other.m_config))
1830 , m_buck(std::move(other.m_buck))
1831 , m_cont(std::move(other.m_cont))
1832{
1833 chronological.list = std::move(other.chronological.list);
1834}
1835
1836template <
1837 bool IsMulti,
1838 bool IsMap,
1839 class Key,
1840 class T,
1841 class Clock,
1842 class Hash,
1843 class KeyEqual,
1844 class Allocator>
1847 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
1849 Allocator const& alloc)
1850 : m_config(std::move(other.m_config), alloc)
1851 , m_buck(alloc)
1852 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1853{
1854 insert(other.cbegin(), other.cend());
1855 other.clear();
1856}
1857
1858template <
1859 bool IsMulti,
1860 bool IsMap,
1861 class Key,
1862 class T,
1863 class Clock,
1864 class Hash,
1865 class KeyEqual,
1866 class Allocator>
1869 : m_config(clock)
1870 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1871{
1872 insert(init.begin(), init.end());
1873}
1874
1875template <
1876 bool IsMulti,
1877 bool IsMap,
1878 class Key,
1879 class T,
1880 class Clock,
1881 class Hash,
1882 class KeyEqual,
1883 class Allocator>
1887 clock_type& clock,
1888 Hash const& hash)
1889 : m_config(clock, hash)
1890 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1891{
1892 insert(init.begin(), init.end());
1893}
1894
1895template <
1896 bool IsMulti,
1897 bool IsMap,
1898 class Key,
1899 class T,
1900 class Clock,
1901 class Hash,
1902 class KeyEqual,
1903 class Allocator>
1907 clock_type& clock,
1908 KeyEqual const& key_eq)
1909 : m_config(clock, key_eq)
1910 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1911{
1912 insert(init.begin(), init.end());
1913}
1914
1915template <
1916 bool IsMulti,
1917 bool IsMap,
1918 class Key,
1919 class T,
1920 class Clock,
1921 class Hash,
1922 class KeyEqual,
1923 class Allocator>
1927 clock_type& clock,
1928 Allocator const& alloc)
1929 : m_config(clock, alloc)
1930 , m_buck(alloc)
1931 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1932{
1933 insert(init.begin(), init.end());
1934}
1935
1936template <
1937 bool IsMulti,
1938 bool IsMap,
1939 class Key,
1940 class T,
1941 class Clock,
1942 class Hash,
1943 class KeyEqual,
1944 class Allocator>
1948 clock_type& clock,
1949 Hash const& hash,
1950 KeyEqual const& key_eq)
1951 : m_config(clock, hash, key_eq)
1952 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1953{
1954 insert(init.begin(), init.end());
1955}
1956
1957template <
1958 bool IsMulti,
1959 bool IsMap,
1960 class Key,
1961 class T,
1962 class Clock,
1963 class Hash,
1964 class KeyEqual,
1965 class Allocator>
1969 clock_type& clock,
1970 Hash const& hash,
1971 Allocator const& alloc)
1972 : m_config(clock, hash, alloc)
1973 , m_buck(alloc)
1974 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1975{
1976 insert(init.begin(), init.end());
1977}
1978
1979template <
1980 bool IsMulti,
1981 bool IsMap,
1982 class Key,
1983 class T,
1984 class Clock,
1985 class Hash,
1986 class KeyEqual,
1987 class Allocator>
1991 clock_type& clock,
1992 KeyEqual const& key_eq,
1993 Allocator const& alloc)
1994 : m_config(clock, key_eq, alloc)
1995 , m_buck(alloc)
1996 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
1997{
1998 insert(init.begin(), init.end());
1999}
2000
2001template <
2002 bool IsMulti,
2003 bool IsMap,
2004 class Key,
2005 class T,
2006 class Clock,
2007 class Hash,
2008 class KeyEqual,
2009 class Allocator>
2013 clock_type& clock,
2014 Hash const& hash,
2015 KeyEqual const& key_eq,
2016 Allocator const& alloc)
2017 : m_config(clock, hash, key_eq, alloc)
2018 , m_buck(alloc)
2019 , m_cont(m_buck, std::cref(m_config.value_hash()), std::cref(m_config.key_value_equal()))
2020{
2021 insert(init.begin(), init.end());
2022}
2023
2024template <
2025 bool IsMulti,
2026 bool IsMap,
2027 class Key,
2028 class T,
2029 class Clock,
2030 class Hash,
2031 class KeyEqual,
2032 class Allocator>
2038
2039template <
2040 bool IsMulti,
2041 bool IsMap,
2042 class Key,
2043 class T,
2044 class Clock,
2045 class Hash,
2046 class KeyEqual,
2047 class Allocator>
2048auto
2051{
2052 if (this != &other)
2053 {
2054 size_type const n(other.size());
2055 clear();
2056 m_config = other.m_config;
2057 m_buck = Buckets(m_config.alloc());
2058 maybe_rehash(n);
2059 insert_unchecked(other.begin(), other.end());
2060 }
2061 return *this;
2062}
2063
2064template <
2065 bool IsMulti,
2066 bool IsMap,
2067 class Key,
2068 class T,
2069 class Clock,
2070 class Hash,
2071 class KeyEqual,
2072 class Allocator>
2073auto
2076{
2077 size_type const n(other.size());
2078 clear();
2079 m_config = std::move(other.m_config);
2080 m_buck = Buckets(m_config.alloc());
2081 maybe_rehash(n);
2082 insert_unchecked(other.begin(), other.end());
2083 other.clear();
2084 return *this;
2085}
2086
2087template <
2088 bool IsMulti,
2089 bool IsMap,
2090 class Key,
2091 class T,
2092 class Clock,
2093 class Hash,
2094 class KeyEqual,
2095 class Allocator>
2096auto
2104
2105//------------------------------------------------------------------------------
2106
2107template <
2108 bool IsMulti,
2109 bool IsMap,
2110 class Key,
2111 class T,
2112 class Clock,
2113 class Hash,
2114 class KeyEqual,
2115 class Allocator>
2116template <class K, bool maybe_multi, bool maybe_map, class>
2119{
2120 auto const iter(
2121 m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal())));
2122 if (iter == m_cont.end())
2123 throw std::out_of_range("key not found");
2124 return iter->value.second;
2125}
2126
2127template <
2128 bool IsMulti,
2129 bool IsMap,
2130 class Key,
2131 class T,
2132 class Clock,
2133 class Hash,
2134 class KeyEqual,
2135 class Allocator>
2136template <class K, bool maybe_multi, bool maybe_map, class>
2139 K const& k) const
2140{
2141 auto const iter(
2142 m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal())));
2143 if (iter == m_cont.end())
2144 throw std::out_of_range("key not found");
2145 return iter->value.second;
2146}
2147
2148template <
2149 bool IsMulti,
2150 bool IsMap,
2151 class Key,
2152 class T,
2153 class Clock,
2154 class Hash,
2155 class KeyEqual,
2156 class Allocator>
2157template <bool maybe_multi, bool maybe_map, class>
2160 Key const& key)
2161{
2162 maybe_rehash(1);
2163 typename cont_type::insert_commit_data d;
2164 auto const result(m_cont.insert_check(
2165 key, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d));
2166 if (result.second)
2167 {
2168 element* const p(new_element(
2170 m_cont.insert_commit(*p, d);
2171 chronological.list.push_back(*p);
2172 return p->value.second;
2173 }
2174 return result.first->value.second;
2175}
2176
2177template <
2178 bool IsMulti,
2179 bool IsMap,
2180 class Key,
2181 class T,
2182 class Clock,
2183 class Hash,
2184 class KeyEqual,
2185 class Allocator>
2186template <bool maybe_multi, bool maybe_map, class>
2189 Key&& key)
2190{
2191 maybe_rehash(1);
2192 typename cont_type::insert_commit_data d;
2193 auto const result(m_cont.insert_check(
2194 key, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal()), d));
2195 if (result.second)
2196 {
2197 element* const p(new_element(
2199 std::forward_as_tuple(std::move(key)),
2201 m_cont.insert_commit(*p, d);
2202 chronological.list.push_back(*p);
2203 return p->value.second;
2204 }
2205 return result.first->value.second;
2206}
2207
2208//------------------------------------------------------------------------------
2209
2210template <
2211 bool IsMulti,
2212 bool IsMap,
2213 class Key,
2214 class T,
2215 class Clock,
2216 class Hash,
2217 class KeyEqual,
2218 class Allocator>
2219void
2221{
2222 for (auto iter(chronological.list.begin()); iter != chronological.list.end();)
2223 unlink_and_delete_element(&*iter++);
2224 chronological.list.clear();
2225 m_cont.clear();
2226 m_buck.clear();
2227}
2228
2229// map, set
2230template <
2231 bool IsMulti,
2232 bool IsMap,
2233 class Key,
2234 class T,
2235 class Clock,
2236 class Hash,
2237 class KeyEqual,
2238 class Allocator>
2239template <bool maybe_multi>
2240auto
2242 value_type const& value) ->
2244{
2245 maybe_rehash(1);
2246 typename cont_type::insert_commit_data d;
2247 auto const result(m_cont.insert_check(
2248 extract(value),
2249 std::cref(m_config.hash_function()),
2250 std::cref(m_config.key_value_equal()),
2251 d));
2252 if (result.second)
2253 {
2254 element* const p(new_element(value));
2255 auto const iter(m_cont.insert_commit(*p, d));
2256 chronological.list.push_back(*p);
2257 return std::make_pair(iterator(iter), true);
2258 }
2259 return std::make_pair(iterator(result.first), false);
2260}
2261
2262// multimap, multiset
2263template <
2264 bool IsMulti,
2265 bool IsMap,
2266 class Key,
2267 class T,
2268 class Clock,
2269 class Hash,
2270 class KeyEqual,
2271 class Allocator>
2272template <bool maybe_multi>
2273auto
2275 value_type const& value) -> typename std::enable_if<maybe_multi, iterator>::type
2276{
2277 maybe_rehash(1);
2278 element* const p(new_element(value));
2279 chronological.list.push_back(*p);
2280 auto const iter(m_cont.insert(*p));
2281 return iterator(iter);
2282}
2283
2284// map, set
2285template <
2286 bool IsMulti,
2287 bool IsMap,
2288 class Key,
2289 class T,
2290 class Clock,
2291 class Hash,
2292 class KeyEqual,
2293 class Allocator>
2294template <bool maybe_multi, bool maybe_map>
2295auto
2297 value_type&& value) ->
2299{
2300 maybe_rehash(1);
2301 typename cont_type::insert_commit_data d;
2302 auto const result(m_cont.insert_check(
2303 extract(value),
2304 std::cref(m_config.hash_function()),
2305 std::cref(m_config.key_value_equal()),
2306 d));
2307 if (result.second)
2308 {
2309 element* const p(new_element(std::move(value)));
2310 auto const iter(m_cont.insert_commit(*p, d));
2311 chronological.list.push_back(*p);
2312 return std::make_pair(iterator(iter), true);
2313 }
2314 return std::make_pair(iterator(result.first), false);
2315}
2316
2317// multimap, multiset
2318template <
2319 bool IsMulti,
2320 bool IsMap,
2321 class Key,
2322 class T,
2323 class Clock,
2324 class Hash,
2325 class KeyEqual,
2326 class Allocator>
2327template <bool maybe_multi, bool maybe_map>
2328auto
2330 value_type&& value) -> typename std::enable_if<maybe_multi && !maybe_map, iterator>::type
2331{
2332 maybe_rehash(1);
2333 element* const p(new_element(std::move(value)));
2334 chronological.list.push_back(*p);
2335 auto const iter(m_cont.insert(*p));
2336 return iterator(iter);
2337}
2338
2339#if 1 // Use insert() instead of insert_check() insert_commit()
2340// set, map
2341template <
2342 bool IsMulti,
2343 bool IsMap,
2344 class Key,
2345 class T,
2346 class Clock,
2347 class Hash,
2348 class KeyEqual,
2349 class Allocator>
2350template <bool maybe_multi, class... Args>
2351auto
2353 Args&&... args) -> typename std::enable_if<!maybe_multi, std::pair<iterator, bool>>::type
2354{
2355 maybe_rehash(1);
2356 // VFALCO NOTE Its unfortunate that we need to
2357 // construct element here
2358 element* const p(new_element(std::forward<Args>(args)...));
2359 auto const result(m_cont.insert(*p));
2360 if (result.second)
2361 {
2362 chronological.list.push_back(*p);
2363 return std::make_pair(iterator(result.first), true);
2364 }
2365 delete_element(p);
2366 return std::make_pair(iterator(result.first), false);
2367}
2368#else // As original, use insert_check() / insert_commit () pair.
2369// set, map
2370template <
2371 bool IsMulti,
2372 bool IsMap,
2373 class Key,
2374 class T,
2375 class Clock,
2376 class Hash,
2377 class KeyEqual,
2378 class Allocator>
2379template <bool maybe_multi, class... Args>
2380auto
2382 Args&&... args) -> typename std::enable_if<!maybe_multi, std::pair<iterator, bool>>::type
2383{
2384 maybe_rehash(1);
2385 // VFALCO NOTE Its unfortunate that we need to
2386 // construct element here
2387 element* const p(new_element(std::forward<Args>(args)...));
2388 typename cont_type::insert_commit_data d;
2389 auto const result(m_cont.insert_check(
2390 extract(p->value),
2391 std::cref(m_config.hash_function()),
2392 std::cref(m_config.key_value_equal()),
2393 d));
2394 if (result.second)
2395 {
2396 auto const iter(m_cont.insert_commit(*p, d));
2397 chronological.list.push_back(*p);
2398 return std::make_pair(iterator(iter), true);
2399 }
2400 delete_element(p);
2401 return std::make_pair(iterator(result.first), false);
2402}
2403#endif // 0
2404
2405// multiset, multimap
2406template <
2407 bool IsMulti,
2408 bool IsMap,
2409 class Key,
2410 class T,
2411 class Clock,
2412 class Hash,
2413 class KeyEqual,
2414 class Allocator>
2415template <bool maybe_multi, class... Args>
2416auto
2418 Args&&... args) -> typename std::enable_if<maybe_multi, iterator>::type
2419{
2420 maybe_rehash(1);
2421 element* const p(new_element(std::forward<Args>(args)...));
2422 chronological.list.push_back(*p);
2423 auto const iter(m_cont.insert(*p));
2424 return iterator(iter);
2425}
2426
2427// set, map
2428template <
2429 bool IsMulti,
2430 bool IsMap,
2431 class Key,
2432 class T,
2433 class Clock,
2434 class Hash,
2435 class KeyEqual,
2436 class Allocator>
2437template <bool maybe_multi, class... Args>
2438auto
2440 const_iterator /*hint*/,
2441 Args&&... args) -> typename std::enable_if<!maybe_multi, std::pair<iterator, bool>>::type
2442{
2443 maybe_rehash(1);
2444 // VFALCO NOTE Its unfortunate that we need to
2445 // construct element here
2446 element* const p(new_element(std::forward<Args>(args)...));
2447 typename cont_type::insert_commit_data d;
2448 auto const result(m_cont.insert_check(
2449 extract(p->value),
2450 std::cref(m_config.hash_function()),
2451 std::cref(m_config.key_value_equal()),
2452 d));
2453 if (result.second)
2454 {
2455 auto const iter(m_cont.insert_commit(*p, d));
2456 chronological.list.push_back(*p);
2457 return std::make_pair(iterator(iter), true);
2458 }
2459 delete_element(p);
2460 return std::make_pair(iterator(result.first), false);
2461}
2462
2463template <
2464 bool IsMulti,
2465 bool IsMap,
2466 class Key,
2467 class T,
2468 class Clock,
2469 class Hash,
2470 class KeyEqual,
2471 class Allocator>
2472template <bool is_const, class Iterator>
2480
2481template <
2482 bool IsMulti,
2483 bool IsMap,
2484 class Key,
2485 class T,
2486 class Clock,
2487 class Hash,
2488 class KeyEqual,
2489 class Allocator>
2490template <bool is_const, class Iterator>
2501
2502template <
2503 bool IsMulti,
2504 bool IsMap,
2505 class Key,
2506 class T,
2507 class Clock,
2508 class Hash,
2509 class KeyEqual,
2510 class Allocator>
2511template <class K>
2512auto
2514 K const& k) -> size_type
2515{
2516 auto iter(
2517 m_cont.find(k, std::cref(m_config.hash_function()), std::cref(m_config.key_value_equal())));
2518 if (iter == m_cont.end())
2519 return 0;
2520 size_type n(0);
2521 for (;;)
2522 {
2523 auto p(&*iter++);
2524 bool const done(m_config(*p, extract(iter->value)));
2525 unlink_and_delete_element(p);
2526 ++n;
2527 if (done)
2528 break;
2529 }
2530 return n;
2531}
2532
2533template <
2534 bool IsMulti,
2535 bool IsMap,
2536 class Key,
2537 class T,
2538 class Clock,
2539 class Hash,
2540 class KeyEqual,
2541 class Allocator>
2542void
2544 aged_unordered_container& other) noexcept
2545{
2546 swap_data(other);
2547 std::swap(chronological, other.chronological);
2548 std::swap(m_cont, other.m_cont);
2549}
2550
2551template <
2552 bool IsMulti,
2553 bool IsMap,
2554 class Key,
2555 class T,
2556 class Clock,
2557 class Hash,
2558 class KeyEqual,
2559 class Allocator>
2560template <class K>
2561auto
2563 K const& k) -> size_type
2564{
2565 auto const now(clock().now());
2566 size_type n(0);
2567 auto const range(equal_range(k));
2568 for (auto iter : range)
2569 {
2570 touch(iter, now);
2571 ++n;
2572 }
2573 return n;
2574}
2575
2576template <
2577 bool IsMulti,
2578 bool IsMap,
2579 class Key,
2580 class T,
2581 class Clock,
2582 class Hash,
2583 class KeyEqual,
2584 class Allocator>
2585template <
2586 bool OtherIsMap,
2587 class OtherKey,
2588 class OtherT,
2589 class OtherDuration,
2590 class OtherHash,
2591 class OtherAllocator,
2592 bool maybe_multi>
2596 false,
2597 OtherIsMap,
2598 OtherKey,
2599 OtherT,
2600 OtherDuration,
2601 OtherHash,
2602 KeyEqual,
2603 OtherAllocator> const& other) const
2604{
2605 if (size() != other.size())
2606 return false;
2607 for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter)
2608 {
2609 auto otherIter(other.find(extract(*iter)));
2610 if (otherIter == otherLast)
2611 return false;
2612 }
2613 return true;
2614}
2615
2616template <
2617 bool IsMulti,
2618 bool IsMap,
2619 class Key,
2620 class T,
2621 class Clock,
2622 class Hash,
2623 class KeyEqual,
2624 class Allocator>
2625template <
2626 bool OtherIsMap,
2627 class OtherKey,
2628 class OtherT,
2629 class OtherDuration,
2630 class OtherHash,
2631 class OtherAllocator,
2632 bool maybe_multi>
2636 true,
2637 OtherIsMap,
2638 OtherKey,
2639 OtherT,
2640 OtherDuration,
2641 OtherHash,
2642 KeyEqual,
2643 OtherAllocator> const& other) const
2644{
2645 if (size() != other.size())
2646 return false;
2647 for (auto iter(cbegin()), last(cend()); iter != last;)
2648 {
2649 auto const& k(extract(*iter));
2650 auto const eq(equal_range(k));
2651 auto const oeq(other.equal_range(k));
2652#if BEAST_NO_CXX14_IS_PERMUTATION
2653 if (std::distance(eq.first, eq.second) != std::distance(oeq.first, oeq.second) ||
2654 !std::is_permutation(eq.first, eq.second, oeq.first))
2655 return false;
2656#else
2657 if (!std::is_permutation(eq.first, eq.second, oeq.first, oeq.second))
2658 return false;
2659#endif
2660 iter = eq.second;
2661 }
2662 return true;
2663}
2664
2665//------------------------------------------------------------------------------
2666
2667// map, set
2668template <
2669 bool IsMulti,
2670 bool IsMap,
2671 class Key,
2672 class T,
2673 class Clock,
2674 class Hash,
2675 class KeyEqual,
2676 class Allocator>
2677template <bool maybe_multi>
2678auto
2680 insert_unchecked(value_type const& value) ->
2682{
2683 typename cont_type::insert_commit_data d;
2684 auto const result(m_cont.insert_check(
2685 extract(value),
2686 std::cref(m_config.hash_function()),
2687 std::cref(m_config.key_value_equal()),
2688 d));
2689 if (result.second)
2690 {
2691 element* const p(new_element(value));
2692 auto const iter(m_cont.insert_commit(*p, d));
2693 chronological.list.push_back(*p);
2694 return std::make_pair(iterator(iter), true);
2695 }
2696 return std::make_pair(iterator(result.first), false);
2697}
2698
2699// multimap, multiset
2700template <
2701 bool IsMulti,
2702 bool IsMap,
2703 class Key,
2704 class T,
2705 class Clock,
2706 class Hash,
2707 class KeyEqual,
2708 class Allocator>
2709template <bool maybe_multi>
2710auto
2712 insert_unchecked(value_type const& value) ->
2714{
2715 element* const p(new_element(value));
2716 chronological.list.push_back(*p);
2717 auto const iter(m_cont.insert(*p));
2718 return iterator(iter);
2719}
2720
2721//------------------------------------------------------------------------------
2722
2723} // namespace detail
2724
2725//------------------------------------------------------------------------------
2726
2727template <
2728 bool IsMulti,
2729 bool IsMap,
2730 class Key,
2731 class T,
2732 class Clock,
2733 class Hash,
2734 class KeyEqual,
2735 class Allocator>
2737 beast::detail::
2738 aged_unordered_container<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>>
2740{
2741 explicit is_aged_container() = default;
2742};
2743
2744// Free functions
2745
2746template <
2747 bool IsMulti,
2748 bool IsMap,
2749 class Key,
2750 class T,
2751 class Clock,
2752 class Hash,
2753 class KeyEqual,
2754 class Allocator>
2755void
2758 aged_unordered_container<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>& lhs,
2759 beast::detail::
2760 aged_unordered_container<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>&
2761 rhs) noexcept
2762{
2763 lhs.swap(rhs);
2764}
2765
2767template <
2768 bool IsMulti,
2769 bool IsMap,
2770 class Key,
2771 class T,
2772 class Clock,
2773 class Hash,
2774 class KeyEqual,
2775 class Allocator,
2776 class Rep,
2777 class Period>
2781 aged_unordered_container<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>& c,
2782 std::chrono::duration<Rep, Period> const& age) noexcept
2783{
2784 std::size_t n(0);
2785 auto const expired(c.clock().now() - age);
2786 for (auto iter(c.chronological.cbegin());
2787 iter != c.chronological.cend() && iter.when() <= expired;)
2788 {
2789 iter = c.erase(iter);
2790 ++n;
2791 }
2792 return n;
2793}
2794
2795} // namespace beast
T addressof(T... args)
T allocate(T... args)
T capacity(T... args)
T ceil(T... args)
Abstract interface to a clock.
typename Clock::time_point time_point
typename Clock::duration duration
bool operator()(element const &e, Key const &k) const
bool operator()(Key const &k, element const &e) const
bool operator()(element const &lhs, element const &rhs) 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< true, typename list_type::iterator > const_iterator
beast::detail::aged_container_iterator<!IsMap, typename list_type::iterator > iterator
beast::detail::aged_container_iterator<!IsMap, typename list_type::reverse_iterator > reverse_iterator
config_t(config_t &&other, Allocator const &alloc)
config_t(clock_type &clock_, KeyEqual const &keyEqual)
config_t(clock_type &clock_, KeyEqual const &keyEqual, Allocator const &alloc_)
config_t(clock_type &clock_, Hash const &hash, Allocator const &alloc_)
config_t(clock_type &clock_, Allocator const &alloc_)
config_t(clock_type &clock_, Hash const &hash, KeyEqual const &keyEqual, Allocator const &alloc_)
config_t(config_t const &other, Allocator const &alloc)
config_t(clock_type &clock_, Hash const &hash, KeyEqual const &keyEqual)
Associative container where each element is also indexed by time.
beast::detail::aged_container_iterator< true, typename cont_type::iterator > const_iterator
aged_unordered_container(clock_type &clock, Hash const &hash, KeyEqual const &key_eq)
std::conditional< IsMap, T, void * >::type & at(K const &k)
aged_unordered_container(clock_type &clock, KeyEqual const &key_eq, Allocator const &alloc)
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash)
auto insert(value_type const &value) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
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)
typename std::allocator_traits< Allocator >::const_pointer const_pointer
aged_unordered_container(InputIt first, InputIt last, clock_type &clock, Hash const &hash, KeyEqual const &key_eq)
aged_unordered_container(InputIt first, InputIt last, clock_type &clock, Allocator const &alloc)
static Key const & extract(value_type const &value)
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)
bool would_exceed(size_type additional) const
aged_unordered_container & operator=(aged_unordered_container const &other)
aged_unordered_container(clock_type &clock, KeyEqual const &key_eq)
std::enable_if< maybe_multi, iterator >::type insert(const_iterator, value_type const &value)
const_local_iterator begin(size_type n) const
void insert_unchecked(InputIt first, InputIt last)
aged_unordered_container(aged_unordered_container const &other)
const_local_iterator cend(size_type n) const
typename boost::intrusive::make_list< element, boost::intrusive::constant_time_size< false > >::type list_type
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock, KeyEqual const &key_eq, Allocator const &alloc)
aged_unordered_container(InputIt first, InputIt last, clock_type &clock, Hash const &hash)
const_local_iterator end(size_type n) const
typename std::allocator_traits< Allocator >::pointer pointer
std::enable_if<!maybe_multi, bool >::type operator==(aged_unordered_container< false, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
void insert(std::initializer_list< value_type > init)
std::enable_if<!maybe_multi, iterator >::type insert(const_iterator, value_type const &value)
std::pair< iterator, iterator > equal_range(K const &k)
std::enable_if< maybe_multi, iterator >::type emplace_hint(const_iterator, Args &&... args)
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock)
aged_unordered_container(clock_type &clock, Hash const &hash, Allocator const &alloc)
typename std::allocator_traits< Allocator >::template rebind_alloc< element > BucketAllocator
typename std::conditional< IsMap, std::pair< Key const, T >, Key >::type value_type
auto insert_unchecked(value_type const &value) -> typename std::enable_if< maybe_multi, iterator >::type
const_iterator iterator_to(value_type const &value) const
std::enable_if<!maybe_propagate >::type swap_data(aged_unordered_container &other) noexcept
typename cont_type::bucket_traits bucket_traits
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, KeyEqual const &key_eq, Allocator const &alloc)
auto insert(value_type &&value) -> typename std::enable_if< maybe_multi &&!maybe_map, iterator >::type
beast::detail::aged_container_iterator<!IsMap, typename cont_type::local_iterator > local_iterator
std::pair< const_iterator, const_iterator > equal_range(K const &k) const
void touch(beast::detail::aged_container_iterator< is_const, Iterator > pos)
std::conditional< IsMap, T, void * >::type & operator[](Key const &key)
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock, Allocator const &alloc)
std::enable_if<!maybe_multi, iterator >::type insert(const_iterator, value_type &&value)
auto emplace(Args &&... args) -> typename std::enable_if< maybe_multi, iterator >::type
std::enable_if< maybe_multi, bool >::type operator==(aged_unordered_container< true, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
beast::detail::aged_container_iterator<!IsMap, typename cont_type::iterator > iterator
std::enable_if< maybe_multi, iterator >::type insert(const_iterator, value_type &&value)
aged_unordered_container(InputIt first, InputIt last, clock_type &clock, Hash const &hash, KeyEqual const &key_eq, Allocator const &alloc)
const_local_iterator cbegin(size_type n) const
auto insert_unchecked(value_type const &value) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
typename std::allocator_traits< Allocator >::template rebind_alloc< element > ElementAllocator
aged_unordered_container(aged_unordered_container const &other, Allocator const &alloc)
aged_unordered_container(clock_type &clock, Allocator const &alloc)
auto emplace_hint(const_iterator, Args &&... args) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
void touch(beast::detail::aged_container_iterator< is_const, Iterator > pos, typename clock_type::time_point const &now)
beast::detail::aged_container_iterator< false, Iterator > erase(beast::detail::aged_container_iterator< is_const, Iterator > pos)
void insert(InputIt first, InputIt last, std::input_iterator_tag)
aged_unordered_container & operator=(aged_unordered_container &&other)
std::enable_if< maybe_propagate >::type swap_data(aged_unordered_container &other) noexcept
aged_unordered_container & operator=(std::initializer_list< value_type > init)
aged_unordered_container(InputIt first, InputIt last, clock_type &clock, Hash const &hash, Allocator const &alloc)
bool operator!=(aged_unordered_container< OtherIsMulti, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
void insert(InputIt first, InputIt last, std::random_access_iterator_tag)
typename std::conditional< IsMulti, typename boost::intrusive::make_unordered_multiset< element, boost::intrusive::constant_time_size< true >, boost::intrusive::hash< ValueHash >, boost::intrusive::equal< KeyValueEqual >, boost::intrusive::cache_begin< true > >::type, typename boost::intrusive::make_unordered_set< element, boost::intrusive::constant_time_size< true >, boost::intrusive::hash< ValueHash >, boost::intrusive::equal< KeyValueEqual >, boost::intrusive::cache_begin< true > >::type >::type cont_type
aged_unordered_container(clock_type &clock, Hash const &hash)
aged_unordered_container(clock_type &clock, Hash const &hash, KeyEqual const &key_eq, Allocator const &alloc)
auto emplace(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
void swap(aged_unordered_container &other) noexcept
aged_unordered_container(InputIt first, InputIt last, clock_type &clock)
aged_unordered_container(aged_unordered_container &&other)
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)
auto insert(value_type const &value) -> typename std::enable_if< maybe_multi, iterator >::type
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, KeyEqual const &key_eq)
std::conditional< IsMap, T, void * >::type & operator[](Key &&key)
aged_unordered_container(InputIt first, InputIt last, clock_type &clock, KeyEqual const &key_eq, Allocator const &alloc)
aged_unordered_container(InputIt first, InputIt last, clock_type &clock, KeyEqual const &key_eq)
class beast::detail::aged_unordered_container::chronological_t chronological
beast::detail::aged_container_iterator< true, typename cont_type::local_iterator > const_local_iterator
auto insert(value_type &&value) -> typename std::enable_if<!maybe_multi &&!maybe_map, std::pair< iterator, bool > >::type
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock, KeyEqual const &key_eq)
aged_unordered_container(aged_unordered_container &&other, Allocator const &alloc)
aged_unordered_container(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, Allocator const &alloc)
T clear(T... args)
T construct(T... args)
T deallocate(T... args)
T destroy(T... args)
T distance(T... args)
T forward_as_tuple(T... args)
T get_allocator(T... args)
T is_permutation(T... args)
T is_same_v
T make_pair(T... args)
T max(T... args)
T max_size(T... args)
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)
T resize(T... args)
T size(T... args)
typename aged_unordered_container::value_type value_type
typename aged_unordered_container::time_point time_point
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)