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