xrpld
Loading...
Searching...
No Matches
aged_unordered_container.h
1#pragma once
2
3#include <xrpl/beast/clock/abstract_clock.h>
4#include <xrpl/beast/container/aged_container.h>
5#include <xrpl/beast/container/detail/aged_associative_container.h>
6#include <xrpl/beast/container/detail/aged_container_iterator.h>
7#include <xrpl/beast/container/detail/empty_base_optimization.h>
8
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 = std::allocator<std::conditional_t<IsMap, std::pair<Key const, T>, Key>>>
67{
68public:
72 using key_type = Key;
73 using mapped_type = T;
77
78 // Introspection (for unit tests)
82
83private:
84 static Key const&
85 extract(value_type const& value)
86 {
88 }
89
90 // VFALCO TODO hoist to remove template argument dependencies
91 struct Element : boost::intrusive::unordered_set_base_hook<
92 boost::intrusive::link_mode<boost::intrusive::normal_link>>,
93 boost::intrusive::list_base_hook<
94 boost::intrusive::link_mode<boost::intrusive::normal_link>>
95 {
96 // Stash types here so the iterator doesn't
97 // need to see the container declaration.
105
107 {
108 }
109
111 {
112 }
113
114 template <
115 class... Args,
117 Element(time_point const& when, Args&&... args)
118 : value(std::forward<Args>(args)...), when(when)
119 {
120 }
121
124 };
125
126 // VFALCO TODO hoist to remove template argument dependencies
127 class ValueHash : public Hash
128 {
129 public:
131 using result_type = size_t;
132
133 ValueHash() = default;
134
135 ValueHash(Hash const& h) : Hash(h)
136 {
137 }
138
140 operator()(Element const& e) const
141 {
142 return Hash::operator()(extract(e.value));
143 }
144
145 Hash&
147 {
148 return *this;
149 }
150
151 [[nodiscard]] Hash const&
153 {
154 return *this;
155 }
156 };
157
158 // Compares value_type against element, used in find/insert_check
159 // VFALCO TODO hoist to remove template argument dependencies
160 class KeyValueEqual : public KeyEqual
161 {
162 public:
165 using result_type = bool;
166
167 KeyValueEqual() = default;
168
169 KeyValueEqual(KeyEqual const& keyEqual) : KeyEqual(keyEqual)
170 {
171 }
172
173 bool
174 operator()(Key const& k, Element const& e) const
175 {
176 return KeyEqual::operator()(k, extract(e.value));
177 }
178
179 bool
180 operator()(Element const& e, Key const& k) const
181 {
182 return KeyEqual::operator()(extract(e.value), k);
183 }
184
185 bool
186 operator()(Element const& lhs, Element const& rhs) const
187 {
188 return KeyEqual::operator()(extract(lhs.value), extract(rhs.value));
189 }
190
191 KeyEqual&
193 {
194 return *this;
195 }
196
197 [[nodiscard]] KeyEqual const&
198 keyEq() const
199 {
200 return *this;
201 }
202 };
203
204 using list_type =
205 boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
206
208 IsMulti,
209 typename boost::intrusive::make_unordered_multiset<
210 Element,
211 boost::intrusive::constant_time_size<true>,
212 boost::intrusive::hash<ValueHash>,
213 boost::intrusive::equal<KeyValueEqual>,
214 boost::intrusive::cache_begin<true>>::type,
215 typename boost::intrusive::make_unordered_set<
216 Element,
217 boost::intrusive::constant_time_size<true>,
218 boost::intrusive::hash<ValueHash>,
219 boost::intrusive::equal<KeyValueEqual>,
220 boost::intrusive::cache_begin<true>>::type>;
221
222 using bucket_type = cont_type::bucket_type;
223 using bucket_traits = cont_type::bucket_traits;
224
226
228
230
232
233 class ConfigT : private ValueHash,
234 private KeyValueEqual,
235 private beast::detail::EmptyBaseOptimization<ElementAllocator>
236 {
237 public:
239 {
240 }
241
242 ConfigT(clock_type& clock, Hash const& hash) : ValueHash(hash), clock(clock)
243 {
244 }
245
246 ConfigT(clock_type& clock, KeyEqual const& keyEqual) : KeyValueEqual(keyEqual), clock(clock)
247 {
248 }
249
254
255 ConfigT(clock_type& clock, Hash const& hash, KeyEqual const& keyEqual)
256 : ValueHash(hash), KeyValueEqual(keyEqual), clock(clock)
257 {
258 }
259
260 ConfigT(clock_type& clock, Hash const& hash, Allocator const& alloc)
261 : ValueHash(hash)
263 , clock(clock)
264 {
265 }
266
267 ConfigT(clock_type& clock, KeyEqual const& keyEqual, Allocator const& alloc)
268 : KeyValueEqual(keyEqual)
270 , clock(clock)
271 {
272 }
273
276 Hash const& hash,
277 KeyEqual const& keyEqual,
278 Allocator const& alloc)
279 : ValueHash(hash)
280 , KeyValueEqual(keyEqual)
282 , clock(clock)
283 {
284 }
285
286 ConfigT(ConfigT const& other)
287 : ValueHash(other.hashFunction())
288 , KeyValueEqual(other.keyEq())
290 ElementAllocatorTraits::select_on_container_copy_construction(other.alloc()))
291 , clock(other.clock)
292 {
293 }
294
295 ConfigT(ConfigT const& other, Allocator const& alloc)
296 : ValueHash(other.hashFunction())
297 , KeyValueEqual(other.keyEq())
299 , clock(other.clock)
300 {
301 }
302
304 : ValueHash(std::move(other.hashFunction()))
305 , KeyValueEqual(std::move(other.keyEq()))
307 , clock(other.clock)
308 {
309 }
310
312 ConfigT&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
313 Allocator const& alloc)
314 : ValueHash(std::move(other.hashFunction()))
315 , KeyValueEqual(std::move(other.keyEq()))
317 , clock(other.clock)
318 {
319 }
320
321 ConfigT&
322 operator=(ConfigT const& other)
323 {
324 hashFunction() = other.hashFunction();
325 keyEq() = other.keyEq();
326 alloc() = other.alloc();
327 clock = other.clock;
328 return *this;
329 }
330
331 ConfigT&
333 {
334 hashFunction() = std::move(other.hashFunction());
335 keyEq() = std::move(other.keyEq());
336 alloc() = std::move(other.alloc());
337 clock = other.clock;
338 return *this;
339 }
340
341 ValueHash&
343 {
344 return *this;
345 }
346
347 [[nodiscard]] ValueHash const&
348 valueHash() const
349 {
350 return *this;
351 }
352
353 Hash&
355 {
357 }
358
359 [[nodiscard]] Hash const&
361 {
363 }
364
367 {
368 return *this;
369 }
370
371 [[nodiscard]] KeyValueEqual const&
373 {
374 return *this;
375 }
376
377 KeyEqual&
379 {
380 return keyValueEqual().keyEq();
381 }
382
383 [[nodiscard]] KeyEqual const&
384 keyEq() const
385 {
386 return keyValueEqual().keyEq();
387 }
388
394
395 [[nodiscard]] ElementAllocator const&
400
402 };
403
405 {
406 public:
409 typename std::allocator_traits<Allocator>::template rebind_alloc<bucket_type>>;
410
412 {
413 vec_.resize(cont_type::suggested_upper_bucket_count(0));
414 }
415
416 Buckets(Allocator const& alloc) : maxLoadFactor_(1.f), vec_(alloc)
417 {
418 vec_.resize(cont_type::suggested_upper_bucket_count(0));
419 }
420
421 operator bucket_traits()
422 {
423 return bucket_traits(&vec_[0], vec_.size());
424 }
425
426 void
428 {
429 vec_.clear();
430 }
431
432 [[nodiscard]] size_type
434 {
435 return vec_.max_size();
436 }
437
438 float&
440 {
441 return maxLoadFactor_;
442 }
443
444 [[nodiscard]] float const&
446 {
447 return maxLoadFactor_;
448 }
449
450 // count is the number of buckets
451 template <class Container>
452 void
453 rehash(size_type count, Container& c)
454 {
455 size_type const size(vec_.size());
456 if (count == size)
457 return;
458 if (count > vec_.capacity())
459 {
460 // Need two vectors otherwise we
461 // will destroy non-empty buckets.
462 vec_type vec(vec_.get_allocator());
463 std::swap(vec_, vec);
464 vec_.resize(count);
465 c.rehash(bucket_traits(&vec_[0], vec_.size()));
466 return;
467 }
468 // Rehash in place.
469 if (count > size)
470 {
471 // This should not reallocate since
472 // we checked capacity earlier.
473 vec_.resize(count);
474 c.rehash(bucket_traits(&vec_[0], count));
475 return;
476 }
477 // Resize must happen after rehash otherwise
478 // we might destroy non-empty buckets.
479 c.rehash(bucket_traits(&vec_[0], count));
480 vec_.resize(count);
481 }
482
483 // Resize the buckets to accommodate at least n items.
484 template <class Container>
485 void
486 resize(size_type n, Container& c)
487 {
488 size_type const suggested(cont_type::suggested_upper_bucket_count(n));
489 rehash(suggested, c);
490 }
491
492 private:
495 };
496
497 template <class... Args>
498 Element*
499 newElement(Args&&... args)
500 {
501 struct Deleter
502 {
504 Deleter(ElementAllocator& a) : a(a)
505 {
506 }
507
508 void
509 operator()(Element* p)
510 {
512 }
513 };
514
516 ElementAllocatorTraits::allocate(config_.alloc(), 1), Deleter(config_.alloc()));
518 config_.alloc(), p.get(), clock().now(), std::forward<Args>(args)...);
519 return p.release();
520 }
521
522 void
523 deleteElement(Element const* p)
524 {
526 ElementAllocatorTraits::deallocate(config_.alloc(), const_cast<Element*>(p), 1);
527 }
528
529 void
530 unlinkAndDeleteElement(Element const* p)
531 {
532 chronological.list_.erase(chronological.list_.iterator_to(*p));
533 cont_.erase(cont_.iterator_to(*p));
534 deleteElement(p);
535 }
536
537public:
538 using hasher = Hash;
539 using key_equal = KeyEqual;
540 using allocator_type = Allocator;
545
546 // A set iterator (IsMap==false) is always const
547 // because the elements of a set are immutable.
550
555
556 //--------------------------------------------------------------------------
557 //
558 // Chronological ordered iterators
559 //
560 // "Memberspace"
561 // http://accu.org/index.php/journals/1527
562 //
563 //--------------------------------------------------------------------------
564
566 {
567 public:
568 // A set iterator (IsMap==false) is always const
569 // because the elements of a set are immutable.
577
580 {
581 return iterator(list_.begin());
582 }
583
585 begin() const
586 {
587 return const_iterator(list_.begin());
588 }
589
591 cbegin() const
592 {
593 return const_iterator(list_.begin());
594 }
595
598 {
599 return iterator(list_.end());
600 }
601
603 end() const
604 {
605 return const_iterator(list_.end());
606 }
607
609 cend() const
610 {
611 return const_iterator(list_.end());
612 }
613
616 {
617 return reverse_iterator(list_.rbegin());
618 }
619
621 rbegin() const
622 {
623 return const_reverse_iterator(list_.rbegin());
624 }
625
627 crbegin() const
628 {
629 return const_reverse_iterator(list_.rbegin());
630 }
631
634 {
635 return reverse_iterator(list_.rend());
636 }
637
639 rend() const
640 {
641 return const_reverse_iterator(list_.rend());
642 }
643
645 crend() const
646 {
647 return const_reverse_iterator(list_.rend());
648 }
649
652 {
653 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
654 return list_.iterator_to(*reinterpret_cast<Element*>(
655 reinterpret_cast<uint8_t*>(&value) -
656 ((std::size_t)std::addressof(((Element*)0)->member))));
657 }
658
660 iteratorTo(value_type const& value) const
661 {
662 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
663 return list_.iterator_to(*reinterpret_cast<Element const*>(
664 reinterpret_cast<uint8_t const*>(&value) -
665 ((std::size_t)std::addressof(((Element*)0)->member))));
666 }
667
670 ChronologicalT() = default;
671
672 private:
676
677 //--------------------------------------------------------------------------
678 //
679 // Construction
680 //
681 //--------------------------------------------------------------------------
682
684
686
688
690
691 AgedUnorderedContainer(clock_type& clock, Allocator const& alloc);
692
693 AgedUnorderedContainer(clock_type& clock, Hash const& hash, KeyEqual const& keyEq);
694
695 AgedUnorderedContainer(clock_type& clock, Hash const& hash, Allocator const& alloc);
696
697 AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq, Allocator const& alloc);
698
701 Hash const& hash,
702 KeyEqual const& keyEq,
703 Allocator const& alloc);
704
705 template <class InputIt>
706 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock);
707
708 template <class InputIt>
709 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Hash const& hash);
710
711 template <class InputIt>
712 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, KeyEqual const& keyEq);
713
714 template <class InputIt>
715 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc);
716
717 template <class InputIt>
719 InputIt first,
720 InputIt last,
722 Hash const& hash,
723 KeyEqual const& keyEq);
724
725 template <class InputIt>
727 InputIt first,
728 InputIt last,
730 Hash const& hash,
731 Allocator const& alloc);
732
733 template <class InputIt>
735 InputIt first,
736 InputIt last,
738 KeyEqual const& keyEq,
739 Allocator const& alloc);
740
741 template <class InputIt>
743 InputIt first,
744 InputIt last,
746 Hash const& hash,
747 KeyEqual const& keyEq,
748 Allocator const& alloc);
749
751
752 AgedUnorderedContainer(AgedUnorderedContainer const& other, Allocator const& alloc);
753
755
757 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
759 Allocator const& alloc);
760
762
766 Hash const& hash);
767
771 KeyEqual const& keyEq);
772
776 Allocator const& alloc);
777
781 Hash const& hash,
782 KeyEqual const& keyEq);
783
787 Hash const& hash,
788 Allocator const& alloc);
789
793 KeyEqual const& keyEq,
794 Allocator const& alloc);
795
799 Hash const& hash,
800 KeyEqual const& keyEq,
801 Allocator const& alloc);
802
804
807
810
813
816 {
817 return config_.alloc();
818 }
819
822 {
823 return config_.clock;
824 }
825
826 clock_type const&
827 clock() const
828 {
829 return config_.clock;
830 }
831
832 //--------------------------------------------------------------------------
833 //
834 // Element access (maps)
835 //
836 //--------------------------------------------------------------------------
837
838 template <
839 class K,
840 bool MaybeMulti = IsMulti,
841 bool MaybeMap = IsMap,
844 at(K const& k);
845
846 template <
847 class K,
848 bool MaybeMulti = IsMulti,
849 bool MaybeMap = IsMap,
852 at(K const& k) const;
853
854 template <
855 bool MaybeMulti = IsMulti,
856 bool MaybeMap = IsMap,
859 operator[](Key const& key);
860
861 template <
862 bool MaybeMulti = IsMulti,
863 bool MaybeMap = IsMap,
866 operator[](Key&& key);
867
868 //--------------------------------------------------------------------------
869 //
870 // Iterators
871 //
872 //--------------------------------------------------------------------------
873
876 {
877 return iterator(cont_.begin());
878 }
879
881 begin() const
882 {
883 return const_iterator(cont_.begin());
884 }
885
887 cbegin() const
888 {
889 return const_iterator(cont_.begin());
890 }
891
894 {
895 return iterator(cont_.end());
896 }
897
899 end() const
900 {
901 return const_iterator(cont_.end());
902 }
903
905 cend() const
906 {
907 return const_iterator(cont_.end());
908 }
909
912 {
913 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
914 return cont_.iterator_to(*reinterpret_cast<Element*>(
915 reinterpret_cast<uint8_t*>(&value) -
916 ((std::size_t)std::addressof(((Element*)0)->member))));
917 }
918
920 iteratorTo(value_type const& value) const
921 {
922 static_assert(std::is_standard_layout_v<Element>, "must be standard layout");
923 return cont_.iterator_to(*reinterpret_cast<Element const*>(
924 reinterpret_cast<uint8_t const*>(&value) -
925 ((std::size_t)std::addressof(((Element*)0)->member))));
926 }
927
928 //--------------------------------------------------------------------------
929 //
930 // Capacity
931 //
932 //--------------------------------------------------------------------------
933
934 bool
935 empty() const noexcept
936 {
937 return cont_.empty();
938 }
939
941 size() const noexcept
942 {
943 return cont_.size();
944 }
945
947 maxSize() const noexcept
948 {
949 return config_.max_size();
950 }
951
952 //--------------------------------------------------------------------------
953 //
954 // Modifiers
955 //
956 //--------------------------------------------------------------------------
957
958 void
960
961 // map, set
962 template <bool MaybeMulti = IsMulti>
963 auto
965
966 // multimap, multiset
967 template <bool MaybeMulti = IsMulti>
968 auto
970
971 // map, set
972 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
973 auto
976
977 // multimap, multiset
978 template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
979 auto
981
982 // map, set
983 template <bool MaybeMulti = IsMulti>
985 insert(const_iterator /*hint*/, value_type const& value)
986 {
987 // Hint is ignored but we provide the interface so
988 // callers may use ordered and unordered interchangeably.
989 return insert(value).first;
990 }
991
992 // multimap, multiset
993 template <bool MaybeMulti = IsMulti>
995 insert(const_iterator /*hint*/, value_type const& value)
996 {
997 // VFALCO TODO The hint could be used to let
998 // the client order equal ranges
999 return insert(value);
1000 }
1001
1002 // map, set
1003 template <bool MaybeMulti = IsMulti>
1006 {
1007 // Hint is ignored but we provide the interface so
1008 // callers may use ordered and unordered interchangeably.
1009 return insert(std::move(value)).first;
1010 }
1011
1012 // multimap, multiset
1013 template <bool MaybeMulti = IsMulti>
1016 {
1017 // VFALCO TODO The hint could be used to let
1018 // the client order equal ranges
1019 return insert(std::move(value));
1020 }
1021
1022 // map, multimap
1023 template <class P, bool MaybeMap = IsMap>
1027 insert(P&& value)
1028 {
1029 return emplace(std::forward<P>(value));
1030 }
1031
1032 // map, multimap
1033 template <class P, bool MaybeMap = IsMap>
1037 insert(const_iterator hint, P&& value)
1038 {
1039 return emplaceHint(hint, std::forward<P>(value));
1040 }
1041
1042 template <class InputIt>
1043 void
1044 insert(InputIt first, InputIt last)
1045 {
1047 }
1048
1049 void
1051 {
1052 insert(init.begin(), init.end());
1053 }
1054
1055 // set, map
1056 template <bool MaybeMulti = IsMulti, class... Args>
1057 auto
1059
1060 // multiset, multimap
1061 template <bool MaybeMulti = IsMulti, class... Args>
1062 auto
1064
1065 // set, map
1066 template <bool MaybeMulti = IsMulti, class... Args>
1067 auto
1068 emplaceHint(const_iterator /*hint*/, Args&&... args)
1070
1071 // multiset, multimap
1072 template <bool MaybeMulti = IsMulti, class... Args>
1074 emplaceHint(const_iterator /*hint*/, Args&&... args)
1075 {
1076 // VFALCO TODO The hint could be used for multi, to let
1077 // the client order equal ranges
1078 return emplace<MaybeMulti>(std::forward<Args>(args)...);
1079 }
1080
1081 template <bool IsConst, class Iterator>
1084
1085 template <bool IsConst, class Iterator>
1090
1091 template <class K>
1092 auto
1093 erase(K const& k) -> size_type;
1094
1095 void
1097
1098 template <bool IsConst, class Iterator>
1099 void
1104
1105 template <class K>
1106 auto
1107 touch(K const& k) -> size_type;
1108
1109 //--------------------------------------------------------------------------
1110 //
1111 // Lookup
1112 //
1113 //--------------------------------------------------------------------------
1114
1115 // VFALCO TODO Respect is_transparent (c++14)
1116 template <class K>
1117 size_type
1118 count(K const& k) const
1119 {
1120 return cont_.count(
1121 k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()));
1122 }
1123
1124 // VFALCO TODO Respect is_transparent (c++14)
1125 template <class K>
1126 iterator
1127 find(K const& k)
1128 {
1129 return iterator(
1130 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1131 }
1132
1133 // VFALCO TODO Respect is_transparent (c++14)
1134 template <class K>
1136 find(K const& k) const
1137 {
1138 return const_iterator(
1139 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1140 }
1141
1142 // VFALCO TODO Respect is_transparent (c++14)
1143 template <class K>
1145 equalRange(K const& k)
1146 {
1147 auto const r(cont_.equal_range(
1148 k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1149 return std::make_pair(iterator(r.first), iterator(r.second));
1150 }
1151
1152 // VFALCO TODO Respect is_transparent (c++14)
1153 template <class K>
1155 equalRange(K const& k) const
1156 {
1157 auto const r(cont_.equal_range(
1158 k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
1159 return std::make_pair(const_iterator(r.first), const_iterator(r.second));
1160 }
1161
1162 //--------------------------------------------------------------------------
1163 //
1164 // Bucket interface
1165 //
1166 //--------------------------------------------------------------------------
1167
1170 {
1171 return local_iterator(cont_.begin(n));
1172 }
1173
1176 {
1177 return const_local_iterator(cont_.begin(n));
1178 }
1179
1182 {
1183 return const_local_iterator(cont_.begin(n));
1184 }
1185
1188 {
1189 return local_iterator(cont_.end(n));
1190 }
1191
1194 {
1195 return const_local_iterator(cont_.end(n));
1196 }
1197
1200 {
1201 return const_local_iterator(cont_.end(n));
1202 }
1203
1204 size_type
1206 {
1207 return cont_.bucket_count();
1208 }
1209
1210 size_type
1212 {
1213 return buck_.maxBucketCount();
1214 }
1215
1216 size_type
1218 {
1219 return cont_.bucket_size(n);
1220 }
1221
1222 size_type
1223 bucket(Key const& k) const
1224 {
1225 XRPL_ASSERT(
1226 bucketCount() != 0,
1227 "beast::detail::AgedUnorderedContainer::bucket : nonzero bucket "
1228 "count");
1229 return cont_.bucket(k, std::cref(config_.hashFunction()));
1230 }
1231
1232 //--------------------------------------------------------------------------
1233 //
1234 // Hash policy
1235 //
1236 //--------------------------------------------------------------------------
1237
1238 float
1240 {
1241 return size() / static_cast<float>(cont_.bucket_count());
1242 }
1243
1244 float
1246 {
1247 return buck_.maxLoadFactor();
1248 }
1249
1250 void
1252 {
1253 buck_.maxLoadFactor() = std::max(ml, buck_.maxLoadFactor());
1254 }
1255
1256 void
1258 {
1260 buck_.rehash(count, cont_);
1261 }
1262
1263 void
1268
1269 //--------------------------------------------------------------------------
1270 //
1271 // Observers
1272 //
1273 //--------------------------------------------------------------------------
1274
1275 hasher const&
1277 {
1278 return config_.hashFunction();
1279 }
1280
1281 key_equal const&
1282 keyEq() const
1283 {
1284 return config_.keyEq();
1285 }
1286
1287 //--------------------------------------------------------------------------
1288 //
1289 // Comparison
1290 //
1291 //--------------------------------------------------------------------------
1292
1293 // This differs from the standard in that the comparison
1294 // is only done on the key portion of the value type, ignoring
1295 // the mapped type.
1296 //
1297 template <
1298 bool OtherIsMap,
1299 class OtherKey,
1300 class OtherT,
1301 class OtherDuration,
1302 class OtherHash,
1303 class OtherAllocator,
1304 bool MaybeMulti = IsMulti>
1307 false,
1308 OtherIsMap,
1309 OtherKey,
1310 OtherT,
1311 OtherDuration,
1312 OtherHash,
1313 KeyEqual,
1314 OtherAllocator> const& other) const;
1315
1316 template <
1317 bool OtherIsMap,
1318 class OtherKey,
1319 class OtherT,
1320 class OtherDuration,
1321 class OtherHash,
1322 class OtherAllocator,
1323 bool MaybeMulti = IsMulti>
1326 true,
1327 OtherIsMap,
1328 OtherKey,
1329 OtherT,
1330 OtherDuration,
1331 OtherHash,
1332 KeyEqual,
1333 OtherAllocator> const& other) const;
1334
1335 template <
1336 bool OtherIsMulti,
1337 bool OtherIsMap,
1338 class OtherKey,
1339 class OtherT,
1340 class OtherDuration,
1341 class OtherHash,
1342 class OtherAllocator>
1343 bool
1345 OtherIsMulti,
1346 OtherIsMap,
1347 OtherKey,
1348 OtherT,
1349 OtherDuration,
1350 OtherHash,
1351 KeyEqual,
1352 OtherAllocator> const& other) const
1353 {
1354 return !(this->operator==(other));
1355 }
1356
1357private:
1358 bool
1359 wouldExceed(size_type additional) const
1360 {
1361 return size() + additional > bucketCount() * maxLoadFactor();
1362 }
1363
1364 void
1366 {
1367 if (wouldExceed(additional))
1368 buck_.resize(size() + additional, cont_);
1369 XRPL_ASSERT(
1371 "beast::detail::AgedUnorderedContainer::maybeRehash : maximum "
1372 "load factor");
1373 }
1374
1375 // map, set
1376 template <bool MaybeMulti = IsMulti>
1377 auto
1380
1381 // multimap, multiset
1382 template <bool MaybeMulti = IsMulti>
1383 auto
1385
1386 template <class InputIt>
1387 void
1388 insertUnchecked(InputIt first, InputIt last)
1389 {
1390 for (; first != last; ++first)
1391 insertUnchecked(*first);
1392 }
1393
1394 template <class InputIt>
1395 void
1396 insert(InputIt first, InputIt last, std::input_iterator_tag)
1397 {
1398 for (; first != last; ++first)
1399 insert(*first);
1400 }
1401
1402 template <class InputIt>
1403 void
1404 insert(InputIt first, InputIt last, std::random_access_iterator_tag)
1405 {
1406 auto const n(std::distance(first, last));
1407 maybeRehash(n);
1408 insertUnchecked(first, last);
1409 }
1410
1411 template <bool IsConst, class Iterator>
1412 void
1415 clock_type::time_point const& now)
1416 {
1417 auto& e(*pos.iterator());
1418 e.when = now;
1419 chronological.list_.erase(chronological.list_.iterator_to(e));
1420 chronological.list_.push_back(e);
1421 }
1422
1423 template <
1427 {
1428 std::swap(config_.hashFunction(), other.config_.hashFunction());
1429 std::swap(config_.keyEq(), other.config_.keyEq());
1430 std::swap(config_.alloc(), other.config_.alloc());
1431 std::swap(config_.clock, other.config_.clock);
1432 }
1433
1434 template <
1438 {
1439 std::swap(config_.hashFunction(), other.config_.hashFunction());
1440 std::swap(config_.keyEq(), other.config_.keyEq());
1441 std::swap(config_.clock, other.config_.clock);
1442 }
1443
1444private:
1445 ConfigT config_;
1446 Buckets buck_;
1448};
1449
1450//------------------------------------------------------------------------------
1451
1452template <
1453 bool IsMulti,
1454 bool IsMap,
1455 class Key,
1456 class T,
1457 class Clock,
1458 class Hash,
1459 class KeyEqual,
1460 class Allocator>
1467
1468template <
1469 bool IsMulti,
1470 bool IsMap,
1471 class Key,
1472 class T,
1473 class Clock,
1474 class Hash,
1475 class KeyEqual,
1476 class Allocator>
1478 AgedUnorderedContainer(clock_type& clock, Hash const& hash)
1479 : config_(clock, hash)
1480 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1481{
1482}
1483
1484template <
1485 bool IsMulti,
1486 bool IsMap,
1487 class Key,
1488 class T,
1489 class Clock,
1490 class Hash,
1491 class KeyEqual,
1492 class Allocator>
1499
1500template <
1501 bool IsMulti,
1502 bool IsMap,
1503 class Key,
1504 class T,
1505 class Clock,
1506 class Hash,
1507 class KeyEqual,
1508 class Allocator>
1510 AgedUnorderedContainer(clock_type& clock, Allocator const& alloc)
1511 : config_(clock, alloc)
1512 , buck_(alloc)
1513 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1514{
1515}
1516
1517template <
1518 bool IsMulti,
1519 bool IsMap,
1520 class Key,
1521 class T,
1522 class Clock,
1523 class Hash,
1524 class KeyEqual,
1525 class Allocator>
1527 AgedUnorderedContainer(clock_type& clock, Hash const& hash, KeyEqual const& keyEq)
1528 : config_(clock, hash, keyEq)
1529 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1530{
1531}
1532
1533template <
1534 bool IsMulti,
1535 bool IsMap,
1536 class Key,
1537 class T,
1538 class Clock,
1539 class Hash,
1540 class KeyEqual,
1541 class Allocator>
1543 AgedUnorderedContainer(clock_type& clock, Hash const& hash, Allocator const& alloc)
1544 : config_(clock, hash, alloc)
1545 , buck_(alloc)
1546 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1547{
1548}
1549
1550template <
1551 bool IsMulti,
1552 bool IsMap,
1553 class Key,
1554 class T,
1555 class Clock,
1556 class Hash,
1557 class KeyEqual,
1558 class Allocator>
1560 AgedUnorderedContainer(clock_type& clock, KeyEqual const& keyEq, Allocator const& alloc)
1561 : config_(clock, keyEq, alloc)
1562 , buck_(alloc)
1563 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1564{
1565}
1566
1567template <
1568 bool IsMulti,
1569 bool IsMap,
1570 class Key,
1571 class T,
1572 class Clock,
1573 class Hash,
1574 class KeyEqual,
1575 class Allocator>
1579 Hash const& hash,
1580 KeyEqual const& keyEq,
1581 Allocator const& alloc)
1582 : config_(clock, hash, keyEq, alloc)
1583 , buck_(alloc)
1584 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1585{
1586}
1587
1588template <
1589 bool IsMulti,
1590 bool IsMap,
1591 class Key,
1592 class T,
1593 class Clock,
1594 class Hash,
1595 class KeyEqual,
1596 class Allocator>
1597template <class InputIt>
1599 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock)
1600 : config_(clock)
1601 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1602{
1603 insert(first, last);
1604}
1605
1606template <
1607 bool IsMulti,
1608 bool IsMap,
1609 class Key,
1610 class T,
1611 class Clock,
1612 class Hash,
1613 class KeyEqual,
1614 class Allocator>
1615template <class InputIt>
1617 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Hash const& hash)
1618 : config_(clock, hash)
1619 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1620{
1621 insert(first, last);
1622}
1623
1624template <
1625 bool IsMulti,
1626 bool IsMap,
1627 class Key,
1628 class T,
1629 class Clock,
1630 class Hash,
1631 class KeyEqual,
1632 class Allocator>
1633template <class InputIt>
1635 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, KeyEqual const& keyEq)
1636 : config_(clock, keyEq)
1637 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1638{
1639 insert(first, last);
1640}
1641
1642template <
1643 bool IsMulti,
1644 bool IsMap,
1645 class Key,
1646 class T,
1647 class Clock,
1648 class Hash,
1649 class KeyEqual,
1650 class Allocator>
1651template <class InputIt>
1653 AgedUnorderedContainer(InputIt first, InputIt last, clock_type& clock, Allocator const& alloc)
1654 : config_(clock, alloc)
1655 , buck_(alloc)
1656 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1657{
1658 insert(first, last);
1659}
1660
1661template <
1662 bool IsMulti,
1663 bool IsMap,
1664 class Key,
1665 class T,
1666 class Clock,
1667 class Hash,
1668 class KeyEqual,
1669 class Allocator>
1670template <class InputIt>
1673 InputIt first,
1674 InputIt last,
1676 Hash const& hash,
1677 KeyEqual const& keyEq)
1678 : config_(clock, hash, keyEq)
1679 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1680{
1681 insert(first, last);
1682}
1683
1684template <
1685 bool IsMulti,
1686 bool IsMap,
1687 class Key,
1688 class T,
1689 class Clock,
1690 class Hash,
1691 class KeyEqual,
1692 class Allocator>
1693template <class InputIt>
1696 InputIt first,
1697 InputIt last,
1699 Hash const& hash,
1700 Allocator const& alloc)
1701 : config_(clock, hash, alloc)
1702 , buck_(alloc)
1703 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1704{
1705 insert(first, last);
1706}
1707
1708template <
1709 bool IsMulti,
1710 bool IsMap,
1711 class Key,
1712 class T,
1713 class Clock,
1714 class Hash,
1715 class KeyEqual,
1716 class Allocator>
1717template <class InputIt>
1720 InputIt first,
1721 InputIt last,
1723 KeyEqual const& keyEq,
1724 Allocator const& alloc)
1725 : config_(clock, keyEq, alloc)
1726 , buck_(alloc)
1727 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1728{
1729 insert(first, last);
1730}
1731
1732template <
1733 bool IsMulti,
1734 bool IsMap,
1735 class Key,
1736 class T,
1737 class Clock,
1738 class Hash,
1739 class KeyEqual,
1740 class Allocator>
1741template <class InputIt>
1744 InputIt first,
1745 InputIt last,
1747 Hash const& hash,
1748 KeyEqual const& keyEq,
1749 Allocator const& alloc)
1750 : config_(clock, hash, keyEq, alloc)
1751 , buck_(alloc)
1752 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
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>
1768 : config_(other.config_)
1769 , buck_(config_.alloc())
1770 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1771{
1772 insert(other.cbegin(), other.cend());
1773}
1774
1775template <
1776 bool IsMulti,
1777 bool IsMap,
1778 class Key,
1779 class T,
1780 class Clock,
1781 class Hash,
1782 class KeyEqual,
1783 class Allocator>
1785 AgedUnorderedContainer(AgedUnorderedContainer const& other, Allocator const& alloc)
1786 : config_(other.config_, alloc)
1787 , buck_(alloc)
1788 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1789{
1790 insert(other.cbegin(), other.cend());
1791}
1792
1793template <
1794 bool IsMulti,
1795 bool IsMap,
1796 class Key,
1797 class T,
1798 class Clock,
1799 class Hash,
1800 class KeyEqual,
1801 class Allocator>
1804 : config_(std::move(other.config_))
1805 , buck_(std::move(other.buck_))
1806 , cont_(std::move(other.cont_))
1807{
1808 chronological.list_ = std::move(other.chronological.list_);
1809}
1810
1811template <
1812 bool IsMulti,
1813 bool IsMap,
1814 class Key,
1815 class T,
1816 class Clock,
1817 class Hash,
1818 class KeyEqual,
1819 class Allocator>
1822 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
1823 AgedUnorderedContainer&& other,
1824 Allocator const& alloc)
1825 : config_(std::move(other.config_), alloc)
1826 , buck_(alloc)
1827 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1828{
1829 insert(other.cbegin(), other.cend());
1830 other.clear();
1831}
1832
1833template <
1834 bool IsMulti,
1835 bool IsMap,
1836 class Key,
1837 class T,
1838 class Clock,
1839 class Hash,
1840 class KeyEqual,
1841 class Allocator>
1849
1850template <
1851 bool IsMulti,
1852 bool IsMap,
1853 class Key,
1854 class T,
1855 class Clock,
1856 class Hash,
1857 class KeyEqual,
1858 class Allocator>
1863 Hash const& hash)
1864 : config_(clock, hash)
1865 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1866{
1867 insert(init.begin(), init.end());
1868}
1869
1870template <
1871 bool IsMulti,
1872 bool IsMap,
1873 class Key,
1874 class T,
1875 class Clock,
1876 class Hash,
1877 class KeyEqual,
1878 class Allocator>
1883 KeyEqual const& keyEq)
1884 : config_(clock, keyEq)
1885 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1886{
1887 insert(init.begin(), init.end());
1888}
1889
1890template <
1891 bool IsMulti,
1892 bool IsMap,
1893 class Key,
1894 class T,
1895 class Clock,
1896 class Hash,
1897 class KeyEqual,
1898 class Allocator>
1903 Allocator const& alloc)
1904 : config_(clock, alloc)
1905 , buck_(alloc)
1906 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1907{
1908 insert(init.begin(), init.end());
1909}
1910
1911template <
1912 bool IsMulti,
1913 bool IsMap,
1914 class Key,
1915 class T,
1916 class Clock,
1917 class Hash,
1918 class KeyEqual,
1919 class Allocator>
1924 Hash const& hash,
1925 KeyEqual const& keyEq)
1926 : config_(clock, hash, keyEq)
1927 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1928{
1929 insert(init.begin(), init.end());
1930}
1931
1932template <
1933 bool IsMulti,
1934 bool IsMap,
1935 class Key,
1936 class T,
1937 class Clock,
1938 class Hash,
1939 class KeyEqual,
1940 class Allocator>
1945 Hash const& hash,
1946 Allocator const& alloc)
1947 : config_(clock, hash, alloc)
1948 , buck_(alloc)
1949 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1950{
1951 insert(init.begin(), init.end());
1952}
1953
1954template <
1955 bool IsMulti,
1956 bool IsMap,
1957 class Key,
1958 class T,
1959 class Clock,
1960 class Hash,
1961 class KeyEqual,
1962 class Allocator>
1967 KeyEqual const& keyEq,
1968 Allocator const& alloc)
1969 : config_(clock, keyEq, alloc)
1970 , buck_(alloc)
1971 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1972{
1973 insert(init.begin(), init.end());
1974}
1975
1976template <
1977 bool IsMulti,
1978 bool IsMap,
1979 class Key,
1980 class T,
1981 class Clock,
1982 class Hash,
1983 class KeyEqual,
1984 class Allocator>
1989 Hash const& hash,
1990 KeyEqual const& keyEq,
1991 Allocator const& alloc)
1992 : config_(clock, hash, keyEq, alloc)
1993 , buck_(alloc)
1994 , cont_(buck_, std::cref(config_.valueHash()), std::cref(config_.keyValueEqual()))
1995{
1996 insert(init.begin(), init.end());
1997}
1998
1999template <
2000 bool IsMulti,
2001 bool IsMap,
2002 class Key,
2003 class T,
2004 class Clock,
2005 class Hash,
2006 class KeyEqual,
2007 class Allocator>
2013
2014template <
2015 bool IsMulti,
2016 bool IsMap,
2017 class Key,
2018 class T,
2019 class Clock,
2020 class Hash,
2021 class KeyEqual,
2022 class Allocator>
2023auto
2026{
2027 if (this != &other)
2028 {
2029 size_type const n(other.size());
2030 clear();
2031 config_ = other.config_;
2032 buck_ = Buckets(config_.alloc());
2033 maybeRehash(n);
2034 insertUnchecked(other.begin(), other.end());
2035 }
2036 return *this;
2037}
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 size_type const n(other.size());
2053 clear();
2054 config_ = std::move(other.config_);
2055 buck_ = Buckets(config_.alloc());
2056 maybeRehash(n);
2057 insertUnchecked(other.begin(), other.end());
2058 other.clear();
2059 return *this;
2060}
2061
2062template <
2063 bool IsMulti,
2064 bool IsMap,
2065 class Key,
2066 class T,
2067 class Clock,
2068 class Hash,
2069 class KeyEqual,
2070 class Allocator>
2071auto
2079
2080//------------------------------------------------------------------------------
2081
2082template <
2083 bool IsMulti,
2084 bool IsMap,
2085 class Key,
2086 class T,
2087 class Clock,
2088 class Hash,
2089 class KeyEqual,
2090 class Allocator>
2091template <class K, bool MaybeMulti, bool MaybeMap, class>
2094{
2095 auto const iter(
2096 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
2097 if (iter == cont_.end())
2098 throw std::out_of_range("key not found");
2099 return iter->value.second;
2100}
2101
2102template <
2103 bool IsMulti,
2104 bool IsMap,
2105 class Key,
2106 class T,
2107 class Clock,
2108 class Hash,
2109 class KeyEqual,
2110 class Allocator>
2111template <class K, bool MaybeMulti, bool MaybeMap, class>
2114 K const& k) const
2115{
2116 auto const iter(
2117 cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
2118 if (iter == cont_.end())
2119 throw std::out_of_range("key not found");
2120 return iter->value.second;
2121}
2122
2123template <
2124 bool IsMulti,
2125 bool IsMap,
2126 class Key,
2127 class T,
2128 class Clock,
2129 class Hash,
2130 class KeyEqual,
2131 class Allocator>
2132template <bool MaybeMulti, bool MaybeMap, class>
2135 Key const& key)
2136{
2137 maybeRehash(1);
2138 typename cont_type::insert_commit_data d;
2139 auto const result(cont_.insert_check(
2140 key, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2141 if (result.second)
2142 {
2143 Element* const p(newElement(
2145 cont_.insert_commit(*p, d);
2146 chronological.list_.push_back(*p);
2147 return p->value.second;
2148 }
2149 return result.first->value.second;
2150}
2151
2152template <
2153 bool IsMulti,
2154 bool IsMap,
2155 class Key,
2156 class T,
2157 class Clock,
2158 class Hash,
2159 class KeyEqual,
2160 class Allocator>
2161template <bool MaybeMulti, bool MaybeMap, class>
2164 Key&& key)
2165{
2166 maybeRehash(1);
2167 typename cont_type::insert_commit_data d;
2168 auto const result(cont_.insert_check(
2169 key, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2170 if (result.second)
2171 {
2172 Element* const p(newElement(
2174 std::forward_as_tuple(std::move(key)),
2176 cont_.insert_commit(*p, d);
2177 chronological.list_.push_back(*p);
2178 return p->value.second;
2179 }
2180 return result.first->value.second;
2181}
2182
2183//------------------------------------------------------------------------------
2184
2185template <
2186 bool IsMulti,
2187 bool IsMap,
2188 class Key,
2189 class T,
2190 class Clock,
2191 class Hash,
2192 class KeyEqual,
2193 class Allocator>
2194void
2196{
2197 for (auto iter(chronological.list_.begin()); iter != chronological.list_.end();)
2198 unlinkAndDeleteElement(&*iter++);
2199 chronological.list_.clear();
2200 cont_.clear();
2201 buck_.clear();
2202}
2203
2204// map, set
2205template <
2206 bool IsMulti,
2207 bool IsMap,
2208 class Key,
2209 class T,
2210 class Clock,
2211 class Hash,
2212 class KeyEqual,
2213 class Allocator>
2214template <bool MaybeMulti>
2215auto
2218{
2219 maybeRehash(1);
2220 typename cont_type::insert_commit_data d;
2221 auto const result(cont_.insert_check(
2222 extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2223 if (result.second)
2224 {
2225 Element* const p(newElement(value));
2226 auto const iter(cont_.insert_commit(*p, d));
2227 chronological.list_.push_back(*p);
2228 return std::make_pair(iterator(iter), true);
2229 }
2230 return std::make_pair(iterator(result.first), false);
2231}
2232
2233// multimap, multiset
2234template <
2235 bool IsMulti,
2236 bool IsMap,
2237 class Key,
2238 class T,
2239 class Clock,
2240 class Hash,
2241 class KeyEqual,
2242 class Allocator>
2243template <bool MaybeMulti>
2244auto
2247{
2248 maybeRehash(1);
2249 Element* const p(newElement(value));
2250 chronological.list_.push_back(*p);
2251 auto const iter(cont_.insert(*p));
2252 return iterator(iter);
2253}
2254
2255// map, set
2256template <
2257 bool IsMulti,
2258 bool IsMap,
2259 class Key,
2260 class T,
2261 class Clock,
2262 class Hash,
2263 class KeyEqual,
2264 class Allocator>
2265template <bool MaybeMulti, bool MaybeMap>
2266auto
2269{
2270 maybeRehash(1);
2271 typename cont_type::insert_commit_data d;
2272 auto const result(cont_.insert_check(
2273 extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2274 if (result.second)
2275 {
2276 Element* const p(newElement(std::move(value)));
2277 auto const iter(cont_.insert_commit(*p, d));
2278 chronological.list_.push_back(*p);
2279 return std::make_pair(iterator(iter), true);
2280 }
2281 return std::make_pair(iterator(result.first), false);
2282}
2283
2284// multimap, multiset
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 MaybeMulti, bool MaybeMap>
2295auto
2298{
2299 maybeRehash(1);
2300 Element* const p(newElement(std::move(value)));
2301 chronological.list_.push_back(*p);
2302 auto const iter(cont_.insert(*p));
2303 return iterator(iter);
2304}
2305
2306#if 1 // Use insert() instead of insert_check() insert_commit()
2307// set, map
2308template <
2309 bool IsMulti,
2310 bool IsMap,
2311 class Key,
2312 class T,
2313 class Clock,
2314 class Hash,
2315 class KeyEqual,
2316 class Allocator>
2317template <bool MaybeMulti, class... Args>
2318auto
2321{
2322 maybeRehash(1);
2323 // VFALCO NOTE Its unfortunate that we need to
2324 // construct element here
2325 Element* const p(newElement(std::forward<Args>(args)...));
2326 auto const result(cont_.insert(*p));
2327 if (result.second)
2328 {
2329 chronological.list_.push_back(*p);
2330 return std::make_pair(iterator(result.first), true);
2331 }
2332 deleteElement(p);
2333 return std::make_pair(iterator(result.first), false);
2334}
2335#else // As original, use insert_check() / insert_commit () pair.
2336// set, map
2337template <
2338 bool IsMulti,
2339 bool IsMap,
2340 class Key,
2341 class T,
2342 class Clock,
2343 class Hash,
2344 class KeyEqual,
2345 class Allocator>
2346template <bool maybe_multi, class... Args>
2347auto
2350{
2351 maybe_rehash(1);
2352 // VFALCO NOTE Its unfortunate that we need to
2353 // construct element here
2354 element* const p(new_element(std::forward<Args>(args)...));
2355 typename cont_type::insert_commit_data d;
2356 auto const result(m_cont.insert_check(
2357 extract(p->value),
2358 std::cref(m_config.hashFunction()),
2359 std::cref(m_config.keyValueEqual()),
2360 d));
2361 if (result.second)
2362 {
2363 auto const iter(m_cont.insert_commit(*p, d));
2364 chronological.list.push_back(*p);
2365 return std::make_pair(iterator(iter), true);
2366 }
2367 delete_element(p);
2368 return std::make_pair(iterator(result.first), false);
2369}
2370#endif // 0
2371
2372// multiset, multimap
2373template <
2374 bool IsMulti,
2375 bool IsMap,
2376 class Key,
2377 class T,
2378 class Clock,
2379 class Hash,
2380 class KeyEqual,
2381 class Allocator>
2382template <bool MaybeMulti, class... Args>
2383auto
2386{
2387 maybeRehash(1);
2388 Element* const p(newElement(std::forward<Args>(args)...));
2389 chronological.list_.push_back(*p);
2390 auto const iter(cont_.insert(*p));
2391 return iterator(iter);
2392}
2393
2394// set, map
2395template <
2396 bool IsMulti,
2397 bool IsMap,
2398 class Key,
2399 class T,
2400 class Clock,
2401 class Hash,
2402 class KeyEqual,
2403 class Allocator>
2404template <bool MaybeMulti, class... Args>
2405auto
2407 const_iterator /*hint*/,
2409{
2410 maybeRehash(1);
2411 // VFALCO NOTE Its unfortunate that we need to
2412 // construct element here
2413 Element* const p(newElement(std::forward<Args>(args)...));
2414 typename cont_type::insert_commit_data d;
2415 auto const result(cont_.insert_check(
2416 extract(p->value),
2417 std::cref(config_.hashFunction()),
2418 std::cref(config_.keyValueEqual()),
2419 d));
2420 if (result.second)
2421 {
2422 auto const iter(cont_.insert_commit(*p, d));
2423 chronological.list_.push_back(*p);
2424 return std::make_pair(iterator(iter), true);
2425 }
2426 deleteElement(p);
2427 return std::make_pair(iterator(result.first), false);
2428}
2429
2430template <
2431 bool IsMulti,
2432 bool IsMap,
2433 class Key,
2434 class T,
2435 class Clock,
2436 class Hash,
2437 class KeyEqual,
2438 class Allocator>
2439template <bool IsConst, class Iterator>
2447
2448template <
2449 bool IsMulti,
2450 bool IsMap,
2451 class Key,
2452 class T,
2453 class Clock,
2454 class Hash,
2455 class KeyEqual,
2456 class Allocator>
2457template <bool IsConst, class Iterator>
2468
2469template <
2470 bool IsMulti,
2471 bool IsMap,
2472 class Key,
2473 class T,
2474 class Clock,
2475 class Hash,
2476 class KeyEqual,
2477 class Allocator>
2478template <class K>
2479auto
2481 -> size_type
2482{
2483 auto iter(cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
2484 if (iter == cont_.end())
2485 return 0;
2486 size_type n(0);
2487 for (;;)
2488 {
2489 auto p(&*iter++);
2490 bool const done(config_(*p, extract(iter->value)));
2492 ++n;
2493 if (done)
2494 break;
2495 }
2496 return n;
2497}
2498
2499template <
2500 bool IsMulti,
2501 bool IsMap,
2502 class Key,
2503 class T,
2504 class Clock,
2505 class Hash,
2506 class KeyEqual,
2507 class Allocator>
2508void
2516
2517template <
2518 bool IsMulti,
2519 bool IsMap,
2520 class Key,
2521 class T,
2522 class Clock,
2523 class Hash,
2524 class KeyEqual,
2525 class Allocator>
2526template <class K>
2527auto
2529 -> size_type
2530{
2531 auto const now(clock().now());
2532 size_type n(0);
2533 auto const range(equal_range(k));
2534 for (auto iter : range)
2535 {
2536 touch(iter, now);
2537 ++n;
2538 }
2539 return n;
2540}
2541
2542template <
2543 bool IsMulti,
2544 bool IsMap,
2545 class Key,
2546 class T,
2547 class Clock,
2548 class Hash,
2549 class KeyEqual,
2550 class Allocator>
2551template <
2552 bool OtherIsMap,
2553 class OtherKey,
2554 class OtherT,
2555 class OtherDuration,
2556 class OtherHash,
2557 class OtherAllocator,
2558 bool MaybeMulti>
2562 false,
2563 OtherIsMap,
2564 OtherKey,
2565 OtherT,
2566 OtherDuration,
2567 OtherHash,
2568 KeyEqual,
2569 OtherAllocator> const& other) const
2570{
2571 if (size() != other.size())
2572 return false;
2573 for (auto iter(cbegin()), last(cend()), otherLast(other.cend()); iter != last; ++iter)
2574 {
2575 auto otherIter(other.find(extract(*iter)));
2576 if (otherIter == otherLast)
2577 return false;
2578 }
2579 return true;
2580}
2581
2582template <
2583 bool IsMulti,
2584 bool IsMap,
2585 class Key,
2586 class T,
2587 class Clock,
2588 class Hash,
2589 class KeyEqual,
2590 class Allocator>
2591template <
2592 bool OtherIsMap,
2593 class OtherKey,
2594 class OtherT,
2595 class OtherDuration,
2596 class OtherHash,
2597 class OtherAllocator,
2598 bool MaybeMulti>
2602 true,
2603 OtherIsMap,
2604 OtherKey,
2605 OtherT,
2606 OtherDuration,
2607 OtherHash,
2608 KeyEqual,
2609 OtherAllocator> const& other) const
2610{
2611 if (size() != other.size())
2612 return false;
2613 for (auto iter(cbegin()), last(cend()); iter != last;)
2614 {
2615 auto const& k(extract(*iter));
2616 auto const eq(equalRange(k));
2617 auto const oeq(other.equalRange(k));
2618#if BEAST_NO_CXX14_IS_PERMUTATION
2619 if (std::distance(eq.first, eq.second) != std::distance(oeq.first, oeq.second) ||
2620 !std::is_permutation(eq.first, eq.second, oeq.first))
2621 return false;
2622#else
2623 if (!std::is_permutation(eq.first, eq.second, oeq.first, oeq.second))
2624 return false;
2625#endif
2626 iter = eq.second;
2627 }
2628 return true;
2629}
2630
2631//------------------------------------------------------------------------------
2632
2633// map, set
2634template <
2635 bool IsMulti,
2636 bool IsMap,
2637 class Key,
2638 class T,
2639 class Clock,
2640 class Hash,
2641 class KeyEqual,
2642 class Allocator>
2643template <bool MaybeMulti>
2644auto
2647{
2648 typename cont_type::insert_commit_data d;
2649 auto const result(cont_.insert_check(
2650 extract(value), std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual()), d));
2651 if (result.second)
2652 {
2653 Element* const p(newElement(value));
2654 auto const iter(cont_.insert_commit(*p, d));
2655 chronological.list_.push_back(*p);
2656 return std::make_pair(iterator(iter), true);
2657 }
2658 return std::make_pair(iterator(result.first), false);
2659}
2660
2661// multimap, multiset
2662template <
2663 bool IsMulti,
2664 bool IsMap,
2665 class Key,
2666 class T,
2667 class Clock,
2668 class Hash,
2669 class KeyEqual,
2670 class Allocator>
2671template <bool MaybeMulti>
2672auto
2675{
2676 Element* const p(newElement(value));
2677 chronological.list_.push_back(*p);
2678 auto const iter(cont_.insert(*p));
2679 return iterator(iter);
2680}
2681
2682//------------------------------------------------------------------------------
2683
2684} // namespace detail
2685
2686//------------------------------------------------------------------------------
2687
2688template <
2689 bool IsMulti,
2690 bool IsMap,
2691 class Key,
2692 class T,
2693 class Clock,
2694 class Hash,
2695 class KeyEqual,
2696 class Allocator>
2698 beast::detail::AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>>
2700{
2701 explicit IsAgedContainer() = default;
2702};
2703
2704// Free functions
2705
2706template <
2707 bool IsMulti,
2708 bool IsMap,
2709 class Key,
2710 class T,
2711 class Clock,
2712 class Hash,
2713 class KeyEqual,
2714 class Allocator>
2715void
2724
2726template <
2727 bool IsMulti,
2728 bool IsMap,
2729 class Key,
2730 class T,
2731 class Clock,
2732 class Hash,
2733 class KeyEqual,
2734 class Allocator,
2735 class Rep,
2736 class Period>
2740 c,
2741 std::chrono::duration<Rep, Period> const& age) noexcept
2742{
2743 std::size_t n(0);
2744 auto const expired(c.clock().now() - age);
2745 for (auto iter(c.chronological.cbegin());
2746 iter != c.chronological.cend() && iter.when() <= expired;)
2747 {
2748 iter = c.erase(iter);
2749 ++n;
2750 }
2751 return n;
2752}
2753
2754} // namespace beast
T addressof(T... args)
T ceil(T... args)
Abstract interface to a clock.
Clock::duration duration
Clock::time_point time_point
std::vector< bucket_type, typename std::allocator_traits< Allocator >::template rebind_alloc< bucket_type > > vec_type
beast::detail::AgedContainerIterator<!IsMap, typename list_type::reverse_iterator > reverse_iterator
beast::detail::AgedContainerIterator< true, typename list_type::iterator > const_iterator
const_iterator iteratorTo(value_type const &value) const
beast::detail::AgedContainerIterator<!IsMap, typename list_type::iterator > iterator
beast::detail::AgedContainerIterator< true, typename list_type::reverse_iterator > const_reverse_iterator
ConfigT(clock_type &clock, Allocator const &alloc)
ConfigT(clock_type &clock, Hash const &hash, KeyEqual const &keyEqual, Allocator const &alloc)
ConfigT(ConfigT const &other, Allocator const &alloc)
ConfigT(clock_type &clock, KeyEqual const &keyEqual)
ConfigT(ConfigT &&other, Allocator const &alloc)
ConfigT(clock_type &clock, Hash const &hash, Allocator const &alloc)
ConfigT(clock_type &clock, Hash const &hash, KeyEqual const &keyEqual)
ConfigT(clock_type &clock, KeyEqual const &keyEqual, Allocator const &alloc)
bool operator()(Element const &lhs, Element const &rhs) const
bool operator()(Key const &k, Element const &e) const
bool operator()(Element const &e, Key const &k) const
Associative container where each element is also indexed by time.
auto insert(value_type &&value) -> std::enable_if_t<!MaybeMulti &&!MaybeMap, std::pair< iterator, bool > >
auto insertUnchecked(value_type const &value) -> std::enable_if_t<!MaybeMulti, std::pair< iterator, bool > >
std::enable_if_t< MaybeMap &&std::is_constructible_v< value_type, P && >, std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > > insert(const_iterator hint, P &&value)
void touch(beast::detail::AgedContainerIterator< IsConst, Iterator > pos, clock_type::time_point const &now)
std::enable_if_t<!MaybePropagate > swapData(AgedUnorderedContainer &other) noexcept
AgedUnorderedContainer & operator=(AgedUnorderedContainer const &other)
auto insert(value_type const &value) -> std::enable_if_t< MaybeMulti, iterator >
std::enable_if_t< MaybeMulti, iterator > insert(const_iterator, value_type &&value)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Allocator const &alloc)
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > first, beast::detail::AgedContainerIterator< IsConst, Iterator > last)
auto insert(value_type &&value) -> std::enable_if_t< MaybeMulti &&!MaybeMap, iterator >
AgedUnorderedContainer(clock_type &clock, Hash const &hash, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash, Allocator const &alloc)
std::enable_if_t<!MaybeMulti, bool > operator==(AgedUnorderedContainer< false, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
beast::detail::AgedContainerIterator< true, typename cont_type::iterator > const_iterator
std::allocator_traits< Allocator >::template rebind_alloc< Element > BucketAllocator
std::conditional< IsMap, T, void * >::type const & at(K const &k) const
std::enable_if_t< MaybeMap &&std::is_constructible_v< value_type, P && >, std::conditional_t< IsMulti, iterator, std::pair< iterator, bool > > > insert(P &&value)
auto insert(value_type const &value) -> std::enable_if_t<!MaybeMulti, std::pair< iterator, bool > >
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, Allocator const &alloc)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, KeyEqual const &keyEq)
auto emplaceHint(const_iterator, Args &&... args) -> std::enable_if_t<!MaybeMulti, std::pair< iterator, bool > >
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash, KeyEqual const &keyEq)
std::enable_if_t<!MaybeMulti, iterator > insert(const_iterator, value_type const &value)
std::enable_if_t<!MaybeMulti, iterator > insert(const_iterator, value_type &&value)
boost::intrusive::make_list< Element, boost::intrusive::constant_time_size< false > >::type list_type
std::conditional_t< IsMulti, typename boost::intrusive::make_unordered_multiset< Element, boost::intrusive::constant_time_size< true >, boost::intrusive::hash< ValueHash >, boost::intrusive::equal< KeyValueEqual >, boost::intrusive::cache_begin< true > >::type, typename boost::intrusive::make_unordered_set< Element, boost::intrusive::constant_time_size< true >, boost::intrusive::hash< ValueHash >, boost::intrusive::equal< KeyValueEqual >, boost::intrusive::cache_begin< true > >::type > cont_type
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, KeyEqual const &keyEq)
AgedUnorderedContainer(clock_type &clock, KeyEqual const &keyEq, Allocator const &alloc)
bool operator!=(AgedUnorderedContainer< OtherIsMulti, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
AgedUnorderedContainer(clock_type &clock, Hash const &hash, Allocator const &alloc)
std::enable_if_t< MaybeMulti, bool > operator==(AgedUnorderedContainer< true, OtherIsMap, OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual, OtherAllocator > const &other) const
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::local_iterator > local_iterator
beast::detail::AgedContainerIterator< true, typename cont_type::local_iterator > const_local_iterator
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash)
std::enable_if_t< MaybeMulti, iterator > emplaceHint(const_iterator, Args &&... args)
AgedUnorderedContainer & operator=(std::initializer_list< value_type > init)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock)
std::enable_if_t< MaybeMulti, iterator > insert(const_iterator, value_type const &value)
std::allocator_traits< Allocator >::template rebind_alloc< Element > ElementAllocator
auto insertUnchecked(value_type const &value) -> std::enable_if_t< MaybeMulti, iterator >
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash, KeyEqual const &keyEq, Allocator const &alloc)
AgedUnorderedContainer(AgedUnorderedContainer const &other, Allocator const &alloc)
auto emplace(Args &&... args) -> std::enable_if_t<!MaybeMulti, std::pair< iterator, bool > >
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Hash const &hash)
std::enable_if_t< MaybePropagate > swapData(AgedUnorderedContainer &other) noexcept
AgedUnorderedContainer(clock_type &clock, Hash const &hash, KeyEqual const &keyEq)
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, KeyEqual const &keyEq, Allocator const &alloc)
beast::detail::AgedContainerIterator<!IsMap, typename cont_type::iterator > iterator
auto emplace(Args &&... args) -> std::enable_if_t< MaybeMulti, iterator >
AgedUnorderedContainer(std::initializer_list< value_type > init, clock_type &clock, Hash const &hash, KeyEqual const &keyEq)
AgedUnorderedContainer(InputIt first, InputIt last, clock_type &clock, Allocator const &alloc)
beast::detail::AgedContainerIterator< false, Iterator > erase(beast::detail::AgedContainerIterator< IsConst, Iterator > pos)
T distance(T... args)
T forward_as_tuple(T... args)
T forward(T... args)
T is_constructible_v
T is_permutation(T... args)
T is_standard_layout_v
T make_pair(T... args)
T max(T... args)
std::enable_if_t< IsAgedContainer< AgedContainer >::value, std::size_t > expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
void swap(beast::detail::AgedOrderedContainer< IsMulti, IsMap, Key, T, Clock, Compare, Allocator > &lhs, beast::detail::AgedOrderedContainer< IsMulti, IsMap, Key, T, Clock, Compare, Allocator > &rhs) noexcept
STL namespace.
T piecewise_construct
T cref(T... args)
T release(T... args)
Element(time_point const &when, value_type const &value)
Element(time_point const &when, value_type &&value)
Element(time_point const &when, Args &&... args)
T swap(T... args)