xrpld
Loading...
Searching...
No Matches
aged_associative_container_test.cpp
1#include <xrpl/beast/clock/manual_clock.h>
2#include <xrpl/beast/container/aged_map.h>
3#include <xrpl/beast/container/aged_multimap.h>
4#include <xrpl/beast/container/aged_multiset.h>
5#include <xrpl/beast/container/aged_set.h>
6#include <xrpl/beast/container/aged_unordered_map.h>
7#include <xrpl/beast/container/aged_unordered_multimap.h>
8#include <xrpl/beast/container/aged_unordered_multiset.h>
9#include <xrpl/beast/container/aged_unordered_set.h>
10#include <xrpl/beast/container/detail/aged_ordered_container.h>
11#include <xrpl/beast/container/detail/aged_unordered_container.h>
12#include <xrpl/beast/unit_test/suite.h>
13
14#include <algorithm>
15#include <chrono>
16#include <cstddef>
17#include <functional>
18#include <memory>
19#include <stdexcept>
20#include <string>
21#include <type_traits>
22#include <utility>
23#include <vector>
24
25#ifndef BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR
26#ifdef _MSC_VER
27#define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 0
28#else
29#define BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR 1
30#endif
31#endif
32
33#ifndef BEAST_CONTAINER_EXTRACT_NOREF
34#ifdef _MSC_VER
35#define BEAST_CONTAINER_EXTRACT_NOREF 1
36#else
37#define BEAST_CONTAINER_EXTRACT_NOREF 1
38#endif
39#endif
40
41namespace beast {
42
44{
45public:
46 template <class T>
47 struct CompT
48 {
49 CompT() = delete;
50
51 explicit CompT(int)
52 {
53 }
54
55 CompT(CompT const&)
56 {
57 }
58
59 bool
60 operator()(T const& lhs, T const& rhs) const
61 {
62 return less_(lhs, rhs);
63 }
64
65 private:
67 };
68
69 template <class T>
70 class HashT
71 {
72 public:
73 HashT() = delete;
74
75 explicit HashT(int)
76 {
77 }
78
80 operator()(T const& t) const
81 {
82 return hash_(t);
83 }
84
85 private:
87 };
88
89 template <class T>
90 struct EqualT
91 {
92 public:
93 EqualT() = delete;
94
95 explicit EqualT(int)
96 {
97 }
98
99 bool
100 operator()(T const& lhs, T const& rhs) const
101 {
102 return eq_(lhs, rhs);
103 }
104
105 private:
107 };
108
109 template <class T>
110 struct AllocT
111 {
112 using value_type = T;
113
114 // using std::true_type::type = propagate_on_container_swap :;
115
116 template <class U>
117 struct Rebind
118 {
120 };
121
122 explicit AllocT(int)
123 {
124 }
125
126 AllocT(AllocT const&) = default;
127
128 template <class U>
130 {
131 }
132
133 template <class U>
134 bool
135 operator==(AllocT<U> const&) const
136 {
137 return true;
138 }
139
140 template <class U>
141 bool
142 operator!=(AllocT<U> const& o) const
143 {
144 return !(*this == o);
145 }
146
147 T*
148 allocate(std::size_t n, T const* = 0)
149 {
150 return static_cast<T*>(::operator new(n * sizeof(T)));
151 }
152
153 void
155 {
156 ::operator delete(p);
157 }
158
159#if !BEAST_AGED_UNORDERED_NO_ALLOC_DEFAULTCTOR
161 {
162 }
163#else
164 AllocT() = delete;
165#endif
166 };
167
168 //--------------------------------------------------------------------------
169
170 // ordered
171 template <class Base, bool IsUnordered>
172 class MaybeUnordered : public Base
173 {
174 public:
177
178 protected:
179 static std::string
181 {
182 return "";
183 }
184 };
185
186 // unordered
187 template <class Base>
188 class MaybeUnordered<Base, true> : public Base
189 {
190 public:
195
196 protected:
197 static std::string
199 {
200 return "unordered_";
201 }
202 };
203
204 // unique
205 template <class Base, bool IsMulti>
206 class MaybeMulti : public Base
207 {
208 public:
209 protected:
210 static std::string
212 {
213 return "";
214 }
215 };
216
217 // multi
218 template <class Base>
219 class MaybeMulti<Base, true> : public Base
220 {
221 public:
222 protected:
223 static std::string
225 {
226 return "multi";
227 }
228 };
229
230 // set
231 template <class Base, bool IsMap>
232 class MaybeMap : public Base
233 {
234 public:
235 using T = void;
236 using Value = Base::Key;
238
239 static Base::Key const&
240 extract(Value const& value)
241 {
242 return value; // NOLINT(bugprone-return-const-ref-from-parameter)
243 }
244
245 static Values
247 {
248 Values v{
249 "apple",
250 "banana",
251 "cherry",
252 "grape",
253 "orange",
254 };
255 return v;
256 }
257
258 protected:
259 static std::string
261 {
262 return "set";
263 }
264 };
265
266 // map
267 template <class Base>
268 class MaybeMap<Base, true> : public Base
269 {
270 public:
271 using T = int;
274
275 static Base::Key const&
276 extract(Value const& value)
277 {
278 return value.first;
279 }
280
281 static Values
283 {
284 Values v{
285 std::make_pair("apple", 1),
286 std::make_pair("banana", 2),
287 std::make_pair("cherry", 3),
288 std::make_pair("grape", 4),
289 std::make_pair("orange", 5)};
290 return v;
291 }
292
293 protected:
294 static std::string
296 {
297 return "map";
298 }
299 };
300
301 //--------------------------------------------------------------------------
302
303 // ordered
304 template <class Base, bool IsUnordered = Base::is_unordered::value>
305 struct ContType
306 {
307 template <
308 class Compare = std::less<typename Base::Key>,
309 class Allocator = std::allocator<typename Base::Value>>
311 Base::is_multi::value,
312 Base::is_map::value,
313 typename Base::Key,
314 typename Base::T,
315 typename Base::Clock,
316 Compare,
317 Allocator>;
318 };
319
320 // unordered
321 template <class Base>
322 struct ContType<Base, true>
323 {
324 template <
326 class KeyEqual = std::equal_to<typename Base::Key>,
327 class Allocator = std::allocator<typename Base::Value>>
329 Base::is_multi::value,
330 Base::is_map::value,
331 typename Base::Key,
332 typename Base::T,
333 typename Base::Clock,
334 Hash,
335 KeyEqual,
336 Allocator>;
337 };
338
339 //--------------------------------------------------------------------------
340
347
348 template <bool IsUnordered, bool IsMulti, bool IsMap>
350 : MaybeUnordered<MaybeMulti<MaybeMap<TestTraitsBase, IsMap>, IsMulti>, IsUnordered>
351 {
352 private:
353 using Base =
355
356 public:
357 using typename Base::Key;
358
362
365
366 static std::string
368 {
369 return std::string("aged_") + Base::name_ordered_part() + Base::name_multi_part() +
370 Base::name_map_part();
371 }
372 };
373
374 template <bool IsUnordered, bool IsMulti, bool IsMap>
375 struct TestTraits : TestTraitsHelper<IsUnordered, IsMulti, IsMap>,
376 ContType<TestTraitsHelper<IsUnordered, IsMulti, IsMap>>
377 {
378 };
379
380 template <class Cont>
381 static std::string
386
387 template <class Traits>
389 {
390 bool
391 operator()(Traits::Value const& lhs, Traits::Value const& rhs)
392 {
393 return Traits::extract(lhs) == Traits::extract(rhs);
394 }
395 };
396
397 template <class Cont>
399 makeList(Cont const& c)
400 {
401 return std::vector<typename Cont::value_type>(c.begin(), c.end());
402 }
403
404 //--------------------------------------------------------------------------
405
406 template <class Container, class Values>
408 checkMapContents(Container& c, Values const& v);
409
410 template <class Container, class Values>
411 std::enable_if_t<!(Container::is_map::value && !Container::is_multi::value)>
412 checkMapContents(Container, Values const&)
413 {
414 }
415
416 // unordered
417 template <class C, class Values>
419 checkUnorderedContentsRefRef(C&& c, Values const& v);
420
421 template <class C, class Values>
424 {
425 }
426
427 template <class C, class Values>
428 void
429 checkContentsRefRef(C&& c, Values const& v);
430
431 template <class Cont, class Values>
432 void
433 checkContents(Cont& c, Values const& v);
434
435 template <class Cont>
436 void
437 checkContents(Cont& c);
438
439 //--------------------------------------------------------------------------
440
441 // ordered
442 template <bool IsUnordered, bool IsMulti, bool IsMap>
445
446 // unordered
447 template <bool IsUnordered, bool IsMulti, bool IsMap>
450
451 // ordered
452 template <bool IsUnordered, bool IsMulti, bool IsMap>
455
456 // unordered
457 template <bool IsUnordered, bool IsMulti, bool IsMap>
460
461 // ordered
462 template <bool IsUnordered, bool IsMulti, bool IsMap>
465
466 // unordered
467 template <bool IsUnordered, bool IsMulti, bool IsMap>
470
471 //--------------------------------------------------------------------------
472
473 template <bool IsUnordered, bool IsMulti, bool IsMap>
474 void
475 testCopyMove();
476
477 //--------------------------------------------------------------------------
478
479 template <bool IsUnordered, bool IsMulti, bool IsMap>
480 void
481 testIterator();
482
483 // Unordered containers don't have reverse iterators
484 template <bool IsUnordered, bool IsMulti, bool IsMap>
487
488 template <bool IsUnordered, bool IsMulti, bool IsMap>
491 {
492 }
493
494 //--------------------------------------------------------------------------
495
496 template <class Container, class Values>
497 void
498 checkInsertCopy(Container& c, Values const& v);
499
500 template <class Container, class Values>
501 void
502 checkInsertMove(Container& c, Values const& v);
503
504 template <class Container, class Values>
505 void
506 checkInsertHintCopy(Container& c, Values const& v);
507
508 template <class Container, class Values>
509 void
510 checkInsertHintMove(Container& c, Values const& v);
511
512 template <class Container, class Values>
513 void
514 checkEmplace(Container& c, Values const& v);
515
516 template <class Container, class Values>
517 void
518 checkEmplaceHint(Container& c, Values const& v);
519
520 template <bool IsUnordered, bool IsMulti, bool IsMap>
521 void
523
524 //--------------------------------------------------------------------------
525
526 template <bool IsUnordered, bool IsMulti, bool IsMap>
527 void
529
530 //--------------------------------------------------------------------------
531
532 // map, unordered_map
533 template <bool IsUnordered, bool IsMulti, bool IsMap>
536
537 template <bool IsUnordered, bool IsMulti, bool IsMap>
540 {
541 }
542
543 //--------------------------------------------------------------------------
544
545 // Helpers for erase tests
546 template <class Container, class Values>
547 void
548 reverseFillAgedContainer(Container& c, Values const& v);
549
550 template <class Iter>
551 Iter
552 nextToEndIter(Iter const beginIter, Iter const endItr);
553
554 //--------------------------------------------------------------------------
555
556 template <class Container, class Iter>
557 bool
558 doElementErase(Container& c, Iter const beginItr, Iter const endItr);
559
560 template <bool IsUnordered, bool IsMulti, bool IsMap>
561 void
563
564 //--------------------------------------------------------------------------
565
566 template <class Container, class BeginEndSrc>
567 void
568 doRangeErase(Container& c, BeginEndSrc const& beginEndSrc);
569
570 template <bool IsUnordered, bool IsMulti, bool IsMap>
571 void
573
574 //--------------------------------------------------------------------------
575
576 // ordered
577 template <bool IsUnordered, bool IsMulti, bool IsMap>
579 testCompare();
580
581 template <bool IsUnordered, bool IsMulti, bool IsMap>
584 {
585 }
586
587 //--------------------------------------------------------------------------
588
589 // ordered
590 template <bool IsUnordered, bool IsMulti, bool IsMap>
593
594 // unordered
595 template <bool IsUnordered, bool IsMulti, bool IsMap>
598
599 //--------------------------------------------------------------------------
600
601 template <bool IsUnordered, bool IsMulti, bool IsMap>
602 void
604
605 template <bool IsUnordered, bool IsMulti>
606 void
608
609 template <bool IsUnordered>
610 void
612};
613
614//------------------------------------------------------------------------------
615
616// Check contents via at() and operator[]
617// map, unordered_map
618template <class Container, class Values>
621{
622 if (v.empty())
623 {
624 BEAST_EXPECT(c.empty());
625 BEAST_EXPECT(c.size() == 0);
626 return;
627 }
628
629 try
630 {
631 // Make sure no exception is thrown
632 for (auto const& e : v)
633 c.at(e.first);
634 for (auto const& e : v)
635 BEAST_EXPECT(c.operator[](e.first) == e.second);
636 }
637 catch (std::out_of_range const&)
638 {
639 fail("caught exception");
640 }
641}
642
643// unordered
644template <class C, class Values>
647{
648 using Cont = std::remove_reference_t<C>;
649 using Traits =
651 using size_type = Cont::size_type;
652 auto const hash(c.hashFunction());
653 auto const keyEq(c.keyEq());
654 for (size_type i(0); i < c.bucketCount(); ++i)
655 {
656 auto const last(c.end(i));
657 for (auto iter(c.begin(i)); iter != last; ++iter)
658 {
659 auto const match(std::ranges::find_if(v, [iter](Values::value_type const& e) {
660 return Traits::extract(*iter) == Traits::extract(e);
661 }));
662 BEAST_EXPECT(match != v.end());
663 BEAST_EXPECT(keyEq(Traits::extract(*iter), Traits::extract(*match)));
664 BEAST_EXPECT(hash(Traits::extract(*iter)) == hash(Traits::extract(*match)));
665 }
666 }
667}
668
669template <class C, class Values>
670void
672{
673 using Cont = std::remove_reference_t<C>;
674 using size_type = Cont::size_type;
675
676 BEAST_EXPECT(c.size() == v.size());
677 BEAST_EXPECT(size_type(std::distance(c.begin(), c.end())) == v.size());
678 BEAST_EXPECT(size_type(std::distance(c.cbegin(), c.cend())) == v.size());
679 BEAST_EXPECT(
680 size_type(std::distance(c.chronological.begin(), c.chronological.end())) == v.size());
681 BEAST_EXPECT(
682 size_type(std::distance(c.chronological.cbegin(), c.chronological.cend())) == v.size());
683 BEAST_EXPECT(
684 size_type(std::distance(c.chronological.rbegin(), c.chronological.rend())) == v.size());
685 BEAST_EXPECT(
686 size_type(std::distance(c.chronological.crbegin(), c.chronological.crend())) == v.size());
687
689}
690
691template <class Cont, class Values>
692void
694{
696 checkContentsRefRef(const_cast<Cont const&>(c), v);
697 checkMapContents(c, v);
698}
699
700template <class Cont>
701void
703{
704 using Traits =
706 using Values = Traits::Values;
707 checkContents(c, Values());
708}
709
710//------------------------------------------------------------------------------
711//
712// Construction
713//
714//------------------------------------------------------------------------------
715
716// ordered
717template <bool IsUnordered, bool IsMulti, bool IsMap>
720{
722 using Comp = Traits::Comp;
723 using Alloc = Traits::Alloc;
724 using MyComp = Traits::MyComp;
725 using MyAlloc = Traits::MyAlloc;
726 typename Traits::ManualClock clock;
727
728 // testcase (Traits::name() + " empty");
729 testcase("empty");
730
731 {
732 typename Traits::template Cont<Comp, Alloc> c(clock);
733 checkContents(c);
734 }
735
736 {
737 typename Traits::template Cont<MyComp, Alloc> c(clock, MyComp(1));
738 checkContents(c);
739 }
740
741 {
742 typename Traits::template Cont<Comp, MyAlloc> c(clock, MyAlloc(1));
743 checkContents(c);
744 }
745
746 {
747 typename Traits::template Cont<MyComp, MyAlloc> c(clock, MyComp(1), MyAlloc(1));
748 checkContents(c);
749 }
750}
751
752// unordered
753template <bool IsUnordered, bool IsMulti, bool IsMap>
756{
758 using Hash = Traits::Hash;
759 using Equal = Traits::Equal;
760 using Alloc = Traits::Alloc;
761 using MyHash = Traits::MyHash;
762 using MyEqual = Traits::MyEqual;
763 using MyAlloc = Traits::MyAlloc;
764 typename Traits::ManualClock clock;
765
766 // testcase (Traits::name() + " empty");
767 testcase("empty");
768 {
769 typename Traits::template Cont<Hash, Equal, Alloc> c(clock);
770 checkContents(c);
771 }
772
773 {
774 typename Traits::template Cont<MyHash, Equal, Alloc> c(clock, MyHash(1));
775 checkContents(c);
776 }
777
778 {
779 typename Traits::template Cont<Hash, MyEqual, Alloc> c(clock, MyEqual(1));
780 checkContents(c);
781 }
782
783 {
784 typename Traits::template Cont<Hash, Equal, MyAlloc> c(clock, MyAlloc(1));
785 checkContents(c);
786 }
787
788 {
789 typename Traits::template Cont<MyHash, MyEqual, Alloc> c(clock, MyHash(1), MyEqual(1));
790 checkContents(c);
791 }
792
793 {
794 typename Traits::template Cont<MyHash, Equal, MyAlloc> c(clock, MyHash(1), MyAlloc(1));
795 checkContents(c);
796 }
797
798 {
799 typename Traits::template Cont<Hash, MyEqual, MyAlloc> c(clock, MyEqual(1), MyAlloc(1));
800 checkContents(c);
801 }
802
803 {
804 typename Traits::template Cont<MyHash, MyEqual, MyAlloc> c(
805 clock, MyHash(1), MyEqual(1), MyAlloc(1));
806 checkContents(c);
807 }
808}
809
810// ordered
811template <bool IsUnordered, bool IsMulti, bool IsMap>
814{
816 using Comp = Traits::Comp;
817 using Alloc = Traits::Alloc;
818 using MyComp = Traits::MyComp;
819 using MyAlloc = Traits::MyAlloc;
820 typename Traits::ManualClock clock;
821 auto const v(Traits::values());
822
823 // testcase (Traits::name() + " range");
824 testcase("range");
825
826 {
827 typename Traits::template Cont<Comp, Alloc> c(v.begin(), v.end(), clock);
828 checkContents(c, v);
829 }
830
831 {
832 typename Traits::template Cont<MyComp, Alloc> c(v.begin(), v.end(), clock, MyComp(1));
833 checkContents(c, v);
834 }
835
836 {
837 typename Traits::template Cont<Comp, MyAlloc> c(v.begin(), v.end(), clock, MyAlloc(1));
838 checkContents(c, v);
839 }
840
841 {
842 typename Traits::template Cont<MyComp, MyAlloc> c(
843 v.begin(), v.end(), clock, MyComp(1), MyAlloc(1));
844 checkContents(c, v);
845 }
846
847 // swap
848
849 {
850 typename Traits::template Cont<Comp, Alloc> c1(v.begin(), v.end(), clock);
851 typename Traits::template Cont<Comp, Alloc> c2(clock);
852 std::swap(c1, c2);
853 checkContents(c2, v);
854 }
855}
856
857// unordered
858template <bool IsUnordered, bool IsMulti, bool IsMap>
861{
863 using Hash = Traits::Hash;
864 using Equal = Traits::Equal;
865 using Alloc = Traits::Alloc;
866 using MyHash = Traits::MyHash;
867 using MyEqual = Traits::MyEqual;
868 using MyAlloc = Traits::MyAlloc;
869 typename Traits::ManualClock clock;
870 auto const v(Traits::values());
871
872 // testcase (Traits::name() + " range");
873 testcase("range");
874
875 {
876 typename Traits::template Cont<Hash, Equal, Alloc> c(v.begin(), v.end(), clock);
877 checkContents(c, v);
878 }
879
880 {
881 typename Traits::template Cont<MyHash, Equal, Alloc> c(
882 v.begin(), v.end(), clock, MyHash(1));
883 checkContents(c, v);
884 }
885
886 {
887 typename Traits::template Cont<Hash, MyEqual, Alloc> c(
888 v.begin(), v.end(), clock, MyEqual(1));
889 checkContents(c, v);
890 }
891
892 {
893 typename Traits::template Cont<Hash, Equal, MyAlloc> c(
894 v.begin(), v.end(), clock, MyAlloc(1));
895 checkContents(c, v);
896 }
897
898 {
899 typename Traits::template Cont<MyHash, MyEqual, Alloc> c(
900 v.begin(), v.end(), clock, MyHash(1), MyEqual(1));
901 checkContents(c, v);
902 }
903
904 {
905 typename Traits::template Cont<MyHash, Equal, MyAlloc> c(
906 v.begin(), v.end(), clock, MyHash(1), MyAlloc(1));
907 checkContents(c, v);
908 }
909
910 {
911 typename Traits::template Cont<Hash, MyEqual, MyAlloc> c(
912 v.begin(), v.end(), clock, MyEqual(1), MyAlloc(1));
913 checkContents(c, v);
914 }
915
916 {
917 typename Traits::template Cont<MyHash, MyEqual, MyAlloc> c(
918 v.begin(), v.end(), clock, MyHash(1), MyEqual(1), MyAlloc(1));
919 checkContents(c, v);
920 }
921}
922
923// ordered
924template <bool IsUnordered, bool IsMulti, bool IsMap>
927{
929 typename Traits::ManualClock const clock;
930
931 // testcase (Traits::name() + " init-list");
932 testcase("init-list");
933
934 // VFALCO TODO
935
936 pass();
937}
938
939// unordered
940template <bool IsUnordered, bool IsMulti, bool IsMap>
943{
945 typename Traits::ManualClock const clock;
946
947 // testcase (Traits::name() + " init-list");
948 testcase("init-list");
949
950 // VFALCO TODO
951 pass();
952}
953
954//------------------------------------------------------------------------------
955//
956// Copy/Move construction and assign
957//
958//------------------------------------------------------------------------------
959
960template <bool IsUnordered, bool IsMulti, bool IsMap>
961void
963{
965 using Alloc = Traits::Alloc;
966 typename Traits::ManualClock clock;
967 auto const v(Traits::values());
968
969 // testcase (Traits::name() + " copy/move");
970 testcase("copy/move");
971
972 // copy
973
974 {
975 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
976 typename Traits::template Cont<> c2(c);
977 checkContents(c, v);
978 checkContents(c2, v);
979 BEAST_EXPECT(c == c2);
980 unexpected(c != c2);
981 }
982
983 {
984 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
985 typename Traits::template Cont<> c2(c, Alloc());
986 checkContents(c, v);
987 checkContents(c2, v);
988 BEAST_EXPECT(c == c2);
989 unexpected(c != c2);
990 }
991
992 {
993 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
994 typename Traits::template Cont<> c2(clock);
995 c2 = c;
996 checkContents(c, v);
997 checkContents(c2, v);
998 BEAST_EXPECT(c == c2);
999 unexpected(c != c2);
1000 }
1001
1002 // move
1003
1004 {
1005 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
1006 typename Traits::template Cont<> c2(std::move(c));
1007 checkContents(c2, v);
1008 }
1009
1010 {
1011 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
1012 typename Traits::template Cont<> c2(std::move(c), Alloc());
1013 checkContents(c2, v);
1014 }
1015
1016 {
1017 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
1018 typename Traits::template Cont<> c2(clock);
1019 c2 = std::move(c);
1020 checkContents(c2, v);
1021 }
1022}
1023
1024//------------------------------------------------------------------------------
1025//
1026// Iterator construction and assignment
1027//
1028//------------------------------------------------------------------------------
1029
1030template <bool IsUnordered, bool IsMulti, bool IsMap>
1031void
1033{
1035 typename Traits::ManualClock clock;
1036 auto const v(Traits::values());
1037
1038 // testcase (Traits::name() + " iterators");
1039 testcase("iterator");
1040
1041 typename Traits::template Cont<> c{clock};
1042
1043 using iterator = decltype(c.begin());
1044 using const_iterator = decltype(c.cbegin());
1045
1046 // Should be able to construct or assign an iterator from an iterator.
1047 iterator const nnIt0{c.begin()};
1048 iterator const nnIt1{nnIt0};
1049 BEAST_EXPECT(nnIt0 == nnIt1);
1050 iterator nnIt2;
1051 nnIt2 = nnIt1;
1052 BEAST_EXPECT(nnIt1 == nnIt2);
1053
1054 // Should be able to construct or assign a const_iterator from a
1055 // const_iterator.
1056 const_iterator const ccIt0{c.cbegin()};
1057 const_iterator const ccIt1{ccIt0};
1058 BEAST_EXPECT(ccIt0 == ccIt1);
1059 const_iterator ccIt2;
1060 ccIt2 = ccIt1;
1061 BEAST_EXPECT(ccIt1 == ccIt2);
1062
1063 // Comparison between iterator and const_iterator is okay
1064 BEAST_EXPECT(nnIt0 == ccIt0);
1065 BEAST_EXPECT(ccIt1 == nnIt1);
1066
1067 // Should be able to construct a const_iterator from an iterator.
1068 const_iterator const ncIt3{c.begin()};
1069 const_iterator const ncIt4{nnIt0};
1070 BEAST_EXPECT(ncIt3 == ncIt4);
1071 const_iterator ncIt5;
1072 ncIt5 = nnIt2;
1073 BEAST_EXPECT(ncIt5 == ncIt4);
1074
1075 // None of these should compile because they construct or assign to a
1076 // non-const iterator with a const_iterator.
1077
1078 // iterator cnIt_0 {c.cbegin()};
1079
1080 // iterator cnIt_1 {ccIt_0};
1081
1082 // iterator cnIt_2;
1083 // cnIt_2 = ccIt_2;
1084}
1085
1086template <bool IsUnordered, bool IsMulti, bool IsMap>
1089{
1091 typename Traits::ManualClock clock;
1092 auto const v(Traits::values());
1093
1094 // testcase (Traits::name() + " reverse_iterators");
1095 testcase("reverse_iterator");
1096
1097 typename Traits::template Cont<> c{clock};
1098
1099 using iterator = decltype(c.begin());
1100 using reverse_iterator = decltype(c.rbegin());
1101 using const_reverse_iterator = decltype(c.crbegin());
1102
1103 // Naming decoder ring
1104 // constructed from ------+ +----- constructed type
1105 // /\/\ -- character pairs
1106 // xAyBit
1107 // r (reverse) or f (forward)--^-^
1108 // ^-^------ C (const) or N (non-const)
1109
1110 // Should be able to construct or assign a reverse_iterator from a
1111 // reverse_iterator.
1112 reverse_iterator const rNrNit0{c.rbegin()};
1113 reverse_iterator const rNrNit1{rNrNit0};
1114 BEAST_EXPECT(rNrNit0 == rNrNit1);
1115 reverse_iterator xXrNit2;
1116 xXrNit2 = rNrNit1;
1117 BEAST_EXPECT(rNrNit1 == xXrNit2);
1118
1119 // Should be able to construct or assign a const_reverse_iterator from a
1120 // const_reverse_iterator
1121 const_reverse_iterator const rCrCit0{c.crbegin()};
1122 const_reverse_iterator const rCrCit1{rCrCit0};
1123 BEAST_EXPECT(rCrCit0 == rCrCit1);
1124 const_reverse_iterator xXrCit2;
1125 xXrCit2 = rCrCit1;
1126 BEAST_EXPECT(rCrCit1 == xXrCit2);
1127
1128 // Comparison between reverse_iterator and const_reverse_iterator is okay
1129 BEAST_EXPECT(rNrNit0 == rCrCit0);
1130 BEAST_EXPECT(rCrCit1 == rNrNit1);
1131
1132 // Should be able to construct or assign a const_reverse_iterator from a
1133 // reverse_iterator
1134 const_reverse_iterator const rNrCit0{c.rbegin()};
1135 const_reverse_iterator const rNrCit1{rNrNit0};
1136 BEAST_EXPECT(rNrCit0 == rNrCit1);
1137 xXrCit2 = rNrNit1;
1138 BEAST_EXPECT(rNrCit1 == xXrCit2);
1139
1140 // The standard allows these conversions:
1141 // o reverse_iterator is explicitly constructible from iterator.
1142 // o const_reverse_iterator is explicitly constructible from
1143 // const_iterator.
1144 // Should be able to construct or assign reverse_iterators from
1145 // non-reverse iterators.
1146 reverse_iterator const fNrNit0{c.begin()};
1147 const_reverse_iterator const fNrCit0{c.begin()};
1148 BEAST_EXPECT(fNrNit0 == fNrCit0);
1149 const_reverse_iterator const fCrCit0{c.cbegin()};
1150 BEAST_EXPECT(fNrCit0 == fCrCit0);
1151
1152 // None of these should compile because they construct a non-reverse
1153 // iterator from a reverse_iterator.
1154 // iterator rNfNit_0 {c.rbegin()};
1155 // const_iterator rNfCit_0 {c.rbegin()};
1156 // const_iterator rCfCit_0 {c.crbegin()};
1157
1158 // You should not be able to assign an iterator to a reverse_iterator or
1159 // vise-versa. So the following lines should not compile.
1160 iterator const xXfNit0;
1161 // xXfNit_0 = xXrNit_2;
1162 // xXrNit_2 = xXfNit_0;
1163}
1164
1165//------------------------------------------------------------------------------
1166//
1167// Modifiers
1168//
1169//------------------------------------------------------------------------------
1170
1171template <class Container, class Values>
1172void
1174{
1175 for (auto const& e : v)
1176 c.insert(e);
1177 checkContents(c, v);
1178}
1179
1180template <class Container, class Values>
1181void
1183{
1184 Values v2(v);
1185 for (auto& e : v2)
1186 c.insert(std::move(e));
1187 checkContents(c, v);
1188}
1189
1190template <class Container, class Values>
1191void
1193{
1194 for (auto const& e : v)
1195 c.insert(c.cend(), e);
1196 checkContents(c, v);
1197}
1198
1199template <class Container, class Values>
1200void
1202{
1203 Values v2(v);
1204 for (auto& e : v2)
1205 c.insert(c.cend(), std::move(e));
1206 checkContents(c, v);
1207}
1208
1209template <class Container, class Values>
1210void
1212{
1213 for (auto const& e : v)
1214 c.emplace(e);
1215 checkContents(c, v);
1216}
1217
1218template <class Container, class Values>
1219void
1221{
1222 for (auto const& e : v)
1223 c.emplace_hint(c.cend(), e);
1224 checkContents(c, v);
1225}
1226
1227template <bool IsUnordered, bool IsMulti, bool IsMap>
1228void
1230{
1232 typename Traits::ManualClock clock;
1233 auto const v(Traits::values());
1234 auto const l(makeList(v));
1235
1236 // testcase (Traits::name() + " modify");
1237 testcase("modify");
1238
1239 {
1240 typename Traits::template Cont<> c(clock);
1241 checkInsertCopy(c, v);
1242 }
1243
1244 {
1245 typename Traits::template Cont<> c(clock);
1246 checkInsertCopy(c, l);
1247 }
1248
1249 {
1250 typename Traits::template Cont<> c(clock);
1251 checkInsertMove(c, v);
1252 }
1253
1254 {
1255 typename Traits::template Cont<> c(clock);
1256 checkInsertMove(c, l);
1257 }
1258
1259 {
1260 typename Traits::template Cont<> c(clock);
1261 checkInsertHintCopy(c, v);
1262 }
1263
1264 {
1265 typename Traits::template Cont<> c(clock);
1266 checkInsertHintCopy(c, l);
1267 }
1268
1269 {
1270 typename Traits::template Cont<> c(clock);
1271 checkInsertHintMove(c, v);
1272 }
1273
1274 {
1275 typename Traits::template Cont<> c(clock);
1276 checkInsertHintMove(c, l);
1277 }
1278}
1279
1280//------------------------------------------------------------------------------
1281//
1282// Chronological ordering
1283//
1284//------------------------------------------------------------------------------
1285
1286template <bool IsUnordered, bool IsMulti, bool IsMap>
1287void
1289{
1291 typename Traits::ManualClock clock;
1292 auto const v(Traits::values());
1293
1294 // testcase (Traits::name() + " chronological");
1295 testcase("chronological");
1296
1297 typename Traits::template Cont<> c(v.begin(), v.end(), clock);
1298
1299 BEAST_EXPECT(std::ranges::equal(c.chronological, v, EqualValue<Traits>()));
1300
1301 // Test touch() with a non-const iterator.
1302 for (auto iter(v.crbegin()); iter != v.crend(); ++iter)
1303 {
1304 using iterator = decltype(c)::iterator;
1305 iterator const found(c.find(Traits::extract(*iter)));
1306
1307 BEAST_EXPECT(found != c.cend());
1308 if (found == c.cend())
1309 return;
1310 c.touch(found);
1311 }
1312
1313 BEAST_EXPECT(
1314 std::equal(
1315 c.chronological.cbegin(),
1316 c.chronological.cend(),
1317 v.crbegin(),
1318 v.crend(),
1320
1321 // Test touch() with a const_iterator
1322 for (auto iter(v.cbegin()); iter != v.cend(); ++iter)
1323 {
1324 using const_iterator = decltype(c)::const_iterator;
1325 const_iterator const found(c.find(Traits::extract(*iter)));
1326
1327 BEAST_EXPECT(found != c.cend());
1328 if (found == c.cend())
1329 return;
1330 c.touch(found);
1331 }
1332
1333 BEAST_EXPECT(std::ranges::equal(c.chronological, v, EqualValue<Traits>()));
1334
1335 {
1336 // Because touch (reverse_iterator pos) is not allowed, the following
1337 // lines should not compile for any aged_container type.
1338 // c.touch (c.rbegin());
1339 // c.touch (c.crbegin());
1340 }
1341}
1342
1343//------------------------------------------------------------------------------
1344//
1345// Element creation via operator[]
1346//
1347//------------------------------------------------------------------------------
1348
1349// map, unordered_map
1350template <bool IsUnordered, bool IsMulti, bool IsMap>
1353{
1355 typename Traits::ManualClock clock;
1356 auto v(Traits::values());
1357
1358 // testcase (Traits::name() + " array create");
1359 testcase("array create");
1360
1361 {
1362 // Copy construct key
1363 typename Traits::template Cont<> c(clock);
1364 for (auto const& e : v)
1365 c[e.first] = e.second;
1366 checkContents(c, v);
1367 }
1368
1369 {
1370 // Move construct key
1371 typename Traits::template Cont<> c(clock);
1372 for (auto e : v)
1373 c[std::move(e.first)] = e.second;
1374 checkContents(c, v);
1375 }
1376}
1377
1378//------------------------------------------------------------------------------
1379//
1380// Helpers for erase tests
1381//
1382//------------------------------------------------------------------------------
1383
1384template <class Container, class Values>
1385void
1387{
1388 // Just in case the passed in container was not empty.
1389 c.clear();
1390
1391 // c.clock() returns an abstract_clock, so dynamic_cast to ManualClock.
1392 // VFALCO NOTE This is sketchy
1394 ManualClock& clk(dynamic_cast<ManualClock&>(c.clock()));
1395 clk.set(0);
1396
1397 Values rev(values);
1398 std::ranges::sort(rev);
1400 for (auto& v : rev)
1401 {
1402 // Add values in reverse order so they are reversed chronologically.
1403 ++clk;
1404 c.insert(v);
1405 }
1406}
1407
1408// Get one iterator before endIter. We have to use operator++ because you
1409// cannot use operator-- with unordered container iterators.
1410template <class Iter>
1411Iter
1412AgedAssociativeContainerTestBase::nextToEndIter(Iter beginIter, Iter const endIter)
1413{
1414 if (beginIter == endIter)
1415 {
1416 fail("Internal test failure. Cannot advance beginIter");
1417 return beginIter;
1418 }
1419
1420 //
1421 Iter nextToEnd = beginIter;
1422 do
1423 {
1424 nextToEnd = beginIter++;
1425 } while (beginIter != endIter);
1426 return nextToEnd;
1427}
1428
1429// Implementation for the element erase tests
1430//
1431// This test accepts:
1432// o the container from which we will erase elements
1433// o iterators into that container defining the range of the erase
1434//
1435// This implementation does not declare a pass, since it wants to allow
1436// the caller to examine the size of the container and the returned iterator
1437//
1438// Note that this test works on the aged_associative containers because an
1439// erase only invalidates references and iterators to the erased element
1440// (see 23.2.4/13). Therefore the passed-in end iterator stays valid through
1441// the whole test.
1442template <class Container, class Iter>
1443bool
1445 Container& c,
1446 Iter const beginItr,
1447 Iter const endItr)
1448{
1449 auto it(beginItr);
1450 size_t count = c.size();
1451 while (it != endItr)
1452 {
1453 auto expectIt = it;
1454 ++expectIt;
1455 it = c.erase(it);
1456
1457 if (it != expectIt)
1458 {
1459 fail("Unexpected returned iterator from element erase");
1460 return false;
1461 }
1462
1463 --count;
1464 if (count != c.size())
1465 {
1466 fail("Failed to erase element");
1467 return false;
1468 }
1469
1470 if (c.empty())
1471 {
1472 if (it != endItr)
1473 {
1474 fail("Erase of last element didn't produce end");
1475 return false;
1476 }
1477 }
1478 }
1479 return true;
1480}
1481
1482//------------------------------------------------------------------------------
1483//
1484// Erase of individual elements
1485//
1486//------------------------------------------------------------------------------
1487
1488template <bool IsUnordered, bool IsMulti, bool IsMap>
1489void
1491{
1493
1494 // testcase (Traits::name() + " element erase"
1495 testcase("element erase");
1496
1497 // Make and fill the container
1498 typename Traits::ManualClock clock;
1499 typename Traits::template Cont<> c{clock};
1500 reverseFillAgedContainer(c, Traits::values());
1501
1502 {
1503 // Test standard iterators
1504 auto tempContainer(c);
1505 if (!doElementErase(tempContainer, tempContainer.cbegin(), tempContainer.cend()))
1506 return; // Test failed
1507
1508 BEAST_EXPECT(tempContainer.empty());
1509 pass();
1510 }
1511 {
1512 // Test chronological iterators
1513 auto tempContainer(c);
1514 auto& chron(tempContainer.chronological);
1515 if (!doElementErase(tempContainer, chron.begin(), chron.end()))
1516 return; // Test failed
1517
1518 BEAST_EXPECT(tempContainer.empty());
1519 pass();
1520 }
1521 {
1522 // Test standard iterator partial erase
1523 auto tempContainer(c);
1524 BEAST_EXPECT(tempContainer.size() > 2);
1525 if (!doElementErase(
1526 tempContainer,
1527 ++tempContainer.begin(),
1528 nextToEndIter(tempContainer.begin(), tempContainer.end())))
1529 return; // Test failed
1530
1531 BEAST_EXPECT(tempContainer.size() == 2);
1532 pass();
1533 }
1534 {
1535 // Test chronological iterator partial erase
1536 auto tempContainer(c);
1537 BEAST_EXPECT(tempContainer.size() > 2);
1538 auto& chron(tempContainer.chronological);
1539 if (!doElementErase(
1540 tempContainer, ++chron.begin(), nextToEndIter(chron.begin(), chron.end())))
1541 return; // Test failed
1542
1543 BEAST_EXPECT(tempContainer.size() == 2);
1544 pass();
1545 }
1546 {
1547 auto tempContainer(c);
1548 BEAST_EXPECT(tempContainer.size() > 4);
1549 // erase(reverse_iterator) is not allowed. None of the following
1550 // should compile for any aged_container type.
1551 // c.erase (c.rbegin());
1552 // c.erase (c.crbegin());
1553 // c.erase(c.rbegin(), ++c.rbegin());
1554 // c.erase(c.crbegin(), ++c.crbegin());
1555 }
1556}
1557
1558// Implementation for the range erase tests
1559//
1560// This test accepts:
1561//
1562// o A container with more than 2 elements and
1563// o An object to ask for begin() and end() iterators in the passed container
1564//
1565// This peculiar interface allows either the container itself to be passed as
1566// the second argument or the container's "chronological" element. Both
1567// sources of iterators need to be tested on the container.
1568//
1569// The test locates iterators such that a range-based delete leaves the first
1570// and last elements in the container. It then validates that the container
1571// ended up with the expected contents.
1572//
1573template <class Container, class BeginEndSrc>
1574void
1575AgedAssociativeContainerTestBase::doRangeErase(Container& c, BeginEndSrc const& beginEndSrc)
1576{
1577 BEAST_EXPECT(c.size() > 2);
1578 auto itBeginPlusOne(beginEndSrc.begin());
1579 auto const valueFront = *itBeginPlusOne;
1580 ++itBeginPlusOne;
1581
1582 // Get one iterator before end()
1583 auto itBack(nextToEndIter(itBeginPlusOne, beginEndSrc.end()));
1584 auto const valueBack = *itBack;
1585
1586 // Erase all elements but first and last
1587 auto const retIter = c.erase(itBeginPlusOne, itBack);
1588
1589 BEAST_EXPECT(c.size() == 2);
1590 BEAST_EXPECT(valueFront == *(beginEndSrc.begin()));
1591 BEAST_EXPECT(valueBack == *(++beginEndSrc.begin()));
1592 BEAST_EXPECT(retIter == (++beginEndSrc.begin()));
1593}
1594
1595//------------------------------------------------------------------------------
1596//
1597// Erase range of elements
1598//
1599//------------------------------------------------------------------------------
1600
1601template <bool IsUnordered, bool IsMulti, bool IsMap>
1602void
1604{
1606
1607 // testcase (Traits::name() + " element erase"
1608 testcase("range erase");
1609
1610 // Make and fill the container
1611 typename Traits::ManualClock clock;
1612 typename Traits::template Cont<> c{clock};
1613 reverseFillAgedContainer(c, Traits::values());
1614
1615 // Not bothering to test range erase with reverse iterators.
1616 {
1617 auto tempContainer(c);
1618 doRangeErase(tempContainer, tempContainer);
1619 }
1620 {
1621 auto tempContainer(c);
1622 doRangeErase(tempContainer, tempContainer.chronological);
1623 }
1624}
1625
1626//------------------------------------------------------------------------------
1627//
1628// Container-wide comparison
1629//
1630//------------------------------------------------------------------------------
1631
1632// ordered
1633template <bool IsUnordered, bool IsMulti, bool IsMap>
1636{
1638 typename Traits::ManualClock clock;
1639 auto const v(Traits::values());
1640
1641 // testcase (Traits::name() + " array create");
1642 testcase("array create");
1643
1644 typename Traits::template Cont<> const c1(v.begin(), v.end(), clock);
1645
1646 typename Traits::template Cont<> c2(v.begin(), v.end(), clock);
1647 c2.erase(c2.cbegin());
1648
1649 expect(c1 != c2);
1650 unexpected(c1 == c2);
1651 expect(c1 < c2);
1652 expect(c1 <= c2);
1653 unexpected(c1 > c2);
1654 unexpected(c1 >= c2);
1655}
1656
1657//------------------------------------------------------------------------------
1658//
1659// Observers
1660//
1661//------------------------------------------------------------------------------
1662
1663// ordered
1664template <bool IsUnordered, bool IsMulti, bool IsMap>
1667{
1669 typename Traits::ManualClock clock;
1670
1671 // testcase (Traits::name() + " observers");
1672 testcase("observers");
1673
1674 typename Traits::template Cont<> const c(clock);
1675 c.keyComp();
1676 c.valueComp();
1677
1678 pass();
1679}
1680
1681// unordered
1682template <bool IsUnordered, bool IsMulti, bool IsMap>
1685{
1687 typename Traits::ManualClock clock;
1688
1689 // testcase (Traits::name() + " observers");
1690 testcase("observers");
1691
1692 typename Traits::template Cont<> const c(clock);
1693 c.hashFunction();
1694 c.keyEq();
1695
1696 pass();
1697}
1698
1699//------------------------------------------------------------------------------
1700//
1701// Matrix
1702//
1703//------------------------------------------------------------------------------
1704
1705template <bool IsUnordered, bool IsMulti, bool IsMap>
1706void
1723
1724//------------------------------------------------------------------------------
1725
1727{
1728public:
1729 // Compile time checks
1730
1732 using T = int;
1733
1734 static_assert(
1736 "bad alias: aged_set");
1737
1738 static_assert(
1740 "bad alias: aged_multiset");
1741
1742 static_assert(
1744 "bad alias: aged_map");
1745
1746 static_assert(
1748 "bad alias: aged_multimap");
1749
1750 static_assert(
1754 "bad alias: aged_unordered_set");
1755
1756 static_assert(
1760 "bad alias: aged_unordered_multiset");
1761
1762 static_assert(
1766 "bad alias: aged_unordered_map");
1767
1768 static_assert(
1772 "bad alias: aged_unordered_multimap");
1773
1774 void
1779};
1780
1782{
1783public:
1784 void
1785 run() override
1786 {
1788 }
1789};
1790
1792{
1793public:
1794 void
1795 run() override
1796 {
1798 }
1799};
1800
1802{
1803public:
1804 void
1805 run() override
1806 {
1808 }
1809};
1810
1812{
1813public:
1814 void
1815 run() override
1816 {
1818 }
1819};
1820
1822{
1823public:
1824 void
1825 run() override
1826 {
1828 }
1829};
1830
1832{
1833public:
1834 void
1835 run() override
1836 {
1838 }
1839};
1840
1842{
1843public:
1844 void
1845 run() override
1846 {
1848 }
1849};
1850
1859
1860} // namespace beast
void reverseFillAgedContainer(Container &c, Values const &v)
bool doElementErase(Container &c, Iter const beginItr, Iter const endItr)
std::enable_if_t< Container::is_map::value &&!Container::is_multi::value > checkMapContents(Container &c, Values const &v)
std::enable_if_t<!(Container::is_map::value &&!Container::is_multi::value)> checkMapContents(Container, Values const &)
void doRangeErase(Container &c, BeginEndSrc const &beginEndSrc)
std::enable_if_t<!std::remove_reference_t< C >::is_unordered::value > checkUnorderedContentsRefRef(C &&, Values const &)
static std::vector< typename Cont::value_type > makeList(Cont const &c)
std::enable_if_t< std::remove_reference_t< C >::is_unordered::value > checkUnorderedContentsRefRef(C &&c, Values const &v)
Iter nextToEndIter(Iter const beginIter, Iter const endItr)
std::enable_if_t< IsMap &&!IsMulti > testArrayCreate()
Manual clock implementation.
void set(time_point const &when)
Set the current time of the manual clock.
void run() override
Runs the suite.
void run() override
Runs the suite.
Associative container where each element is also indexed by time.
Associative container where each element is also indexed by time.
A testsuite class.
Definition suite.h:50
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:484
void pass()
Record a successful test condition.
Definition suite.h:500
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:223
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:522
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
T distance(T... args)
T equal(T... args)
T find_if(T... args)
T is_same_v
T make_pair(T... args)
detail::AgedOrderedContainer< false, false, Key, void, Clock, Compare, Allocator > aged_set
Definition aged_set.h:16
detail::AgedUnorderedContainer< true, true, Key, T, Clock, Hash, KeyEqual, Allocator > aged_unordered_multimap
detail::AgedUnorderedContainer< false, false, Key, void, Clock, Hash, KeyEqual, Allocator > aged_unordered_set
detail::AgedUnorderedContainer< true, false, Key, void, Clock, Hash, KeyEqual, Allocator > aged_unordered_multiset
detail::AgedOrderedContainer< true, true, Key, T, Clock, Compare, Allocator > aged_multimap
detail::AgedUnorderedContainer< false, true, Key, T, Clock, Hash, KeyEqual, Allocator > aged_unordered_map
detail::AgedOrderedContainer< true, false, Key, void, Clock, Compare, Allocator > aged_multiset
BEAST_DEFINE_TESTSUITE(aged_set, beast, beast)
detail::AgedOrderedContainer< false, true, Key, T, Clock, Compare, Allocator > aged_map
Definition aged_map.h:17
T reverse(T... args)
T sort(T... args)
detail::AgedUnorderedContainer< Base::is_multi::value, Base::is_map::value, typename Base::Key, typename Base::T, typename Base::Clock, Hash, KeyEqual, Allocator > Cont
detail::AgedOrderedContainer< Base::is_multi::value, Base::is_map::value, typename Base::Key, typename Base::T, typename Base::Clock, Compare, Allocator > Cont
bool operator()(Traits::Value const &lhs, Traits::Value const &rhs)
MaybeUnordered< MaybeMulti< MaybeMap< TestTraitsBase, IsMap >, IsMulti >, IsUnordered > Base
T swap(T... args)