151c0b2f7Stbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2019-2021 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev #ifndef __TBB_test_common_concurrent_ordered_common_H
1851c0b2f7Stbbdev #define __TBB_test_common_concurrent_ordered_common_H
1951c0b2f7Stbbdev 
20*b15aabb3Stbbdev #define __TBB_TEST_CPP20_COMPARISONS __TBB_CPP20_COMPARISONS_PRESENT && __TBB_CPP20_CONCEPTS_PRESENT
2151c0b2f7Stbbdev #include "common/concurrent_associative_common.h"
2251c0b2f7Stbbdev #include "test_comparisons.h"
2351c0b2f7Stbbdev 
2451c0b2f7Stbbdev template<typename MyTable>
2551c0b2f7Stbbdev inline void CheckContainerAllocator(MyTable &table, size_t expected_allocs, size_t expected_frees, bool exact) {
2651c0b2f7Stbbdev     typename MyTable::allocator_type a = table.get_allocator();
2751c0b2f7Stbbdev     CheckAllocator<MyTable>(a, expected_allocs, expected_frees, exact);
2851c0b2f7Stbbdev }
2951c0b2f7Stbbdev 
3051c0b2f7Stbbdev template<typename Container>
3151c0b2f7Stbbdev inline void CheckNoAllocations(Container&) {
3251c0b2f7Stbbdev     // TODO: enable
3351c0b2f7Stbbdev     // CheckContainerAllocator(cont, 0, 0, false);
3451c0b2f7Stbbdev }
3551c0b2f7Stbbdev 
3651c0b2f7Stbbdev template <typename Container>
3751c0b2f7Stbbdev struct OrderChecker {
3851c0b2f7Stbbdev     typename Container::value_compare& val_comp;
3951c0b2f7Stbbdev     typename Container::key_compare& key_comp;
4051c0b2f7Stbbdev 
4151c0b2f7Stbbdev     OrderChecker(typename Container::value_compare& v_comp, typename Container::key_compare& k_comp)
4251c0b2f7Stbbdev         : val_comp(v_comp), key_comp(k_comp) {}
4351c0b2f7Stbbdev 
4451c0b2f7Stbbdev     bool operator()(const typename Container::value_type& lhs, const typename Container::value_type& rhs) {
4551c0b2f7Stbbdev         if (AllowMultimapping<Container>::value)
4651c0b2f7Stbbdev             // We need to use not greater comparator for multicontainer
4751c0b2f7Stbbdev             return !val_comp(rhs, lhs) && !key_comp(Value<Container>::key(rhs), Value<Container>::key(lhs));
4851c0b2f7Stbbdev         return val_comp(lhs, rhs) && key_comp(Value<Container>::key(lhs), Value<Container>::key(rhs));
4951c0b2f7Stbbdev     }
5051c0b2f7Stbbdev }; // struct OrderChecker
5151c0b2f7Stbbdev 
5251c0b2f7Stbbdev template <typename Container>
5351c0b2f7Stbbdev void check_container_order( const Container& cont ) {
5451c0b2f7Stbbdev     if (!cont.empty()) {
5551c0b2f7Stbbdev         typename Container::key_compare key_comp = cont.key_comp();
5651c0b2f7Stbbdev         typename Container::value_compare value_comp = cont.value_comp();
5751c0b2f7Stbbdev         OrderChecker<Container> check_order(value_comp, key_comp);
5851c0b2f7Stbbdev 
5951c0b2f7Stbbdev         for (auto it = cont.begin(); std::next(it) != cont.end();) {
6051c0b2f7Stbbdev             auto pr_it = it++;
6151c0b2f7Stbbdev             REQUIRE_MESSAGE(check_order(*pr_it, *it), "The order of the elements is broken");
6251c0b2f7Stbbdev         }
6351c0b2f7Stbbdev     }
6451c0b2f7Stbbdev }
6551c0b2f7Stbbdev 
6651c0b2f7Stbbdev template <typename Container>
6751c0b2f7Stbbdev void test_ordered_methods() {
6851c0b2f7Stbbdev     Container cont;
6951c0b2f7Stbbdev     const Container& ccont = cont;
7051c0b2f7Stbbdev 
7151c0b2f7Stbbdev     int r, random_threshold = 10, uncontained_key = random_threshold / 2;
7251c0b2f7Stbbdev     for (int i = 0; i < 100; ++i) {
7351c0b2f7Stbbdev         r = std::rand() % random_threshold;
7451c0b2f7Stbbdev         if (r != uncontained_key) {
7551c0b2f7Stbbdev             cont.insert(Value<Container>::make(r));
7651c0b2f7Stbbdev         }
7751c0b2f7Stbbdev     }
7851c0b2f7Stbbdev 
7951c0b2f7Stbbdev     check_container_order(cont);
8051c0b2f7Stbbdev 
8151c0b2f7Stbbdev     typename Container::value_compare val_comp = cont.value_comp();
8251c0b2f7Stbbdev     typename Container::iterator l_bound_check, u_bound_check;
8351c0b2f7Stbbdev     for (int key = -1; key < random_threshold + 1; ++key) {
8451c0b2f7Stbbdev         auto eq_range = cont.equal_range(key);
8551c0b2f7Stbbdev         // Check equal_range content
8651c0b2f7Stbbdev         for (auto it = eq_range.first; it != eq_range.second; ++it)
8751c0b2f7Stbbdev             REQUIRE_MESSAGE(*it == Value<Container>::make(key), "equal_range contains wrong value");
8851c0b2f7Stbbdev 
8951c0b2f7Stbbdev         // Manual search of upper and lower bounds
9051c0b2f7Stbbdev         l_bound_check = cont.end();
9151c0b2f7Stbbdev         u_bound_check = cont.end();
9251c0b2f7Stbbdev         for (auto it = cont.begin(); it != cont.end(); ++it){
9351c0b2f7Stbbdev             if (!val_comp(*it, Value<Container>::make(key)) && l_bound_check == cont.end()) {
9451c0b2f7Stbbdev                 l_bound_check = it;
9551c0b2f7Stbbdev             }
9651c0b2f7Stbbdev             if (val_comp(Value<Container>::make(key), *it) && u_bound_check == cont.end()) {
9751c0b2f7Stbbdev                 u_bound_check = it;
9851c0b2f7Stbbdev                 break;
9951c0b2f7Stbbdev             }
10051c0b2f7Stbbdev         }
10151c0b2f7Stbbdev 
10251c0b2f7Stbbdev         typename Container::range_type cont_range = cont.range();
10351c0b2f7Stbbdev         typename Container::const_range_type ccont_range = ccont.range();
10451c0b2f7Stbbdev         REQUIRE_MESSAGE(cont_range.size() == ccont_range.size(), "Incorrect ordered container range size");
10551c0b2f7Stbbdev         REQUIRE_MESSAGE(cont_range.size() == cont.size(), "Incorrect ordered container range size");
10651c0b2f7Stbbdev 
10751c0b2f7Stbbdev         typename Container::iterator l_bound = cont.lower_bound(key);
10851c0b2f7Stbbdev         typename Container::iterator u_bound = cont.upper_bound(key);
10951c0b2f7Stbbdev 
11051c0b2f7Stbbdev         REQUIRE_MESSAGE(l_bound == l_bound_check, "lower_bound() returned wrong iterator");
11151c0b2f7Stbbdev         REQUIRE_MESSAGE(u_bound == u_bound_check, "upper_bound() returned wrong iterator");
11251c0b2f7Stbbdev 
11351c0b2f7Stbbdev         using const_iterator = typename Container::const_iterator;
11451c0b2f7Stbbdev         const_iterator cl_bound = ccont.lower_bound(key);
11551c0b2f7Stbbdev         const_iterator cu_bound = ccont.upper_bound(key);
11651c0b2f7Stbbdev 
11751c0b2f7Stbbdev         REQUIRE_MESSAGE(cl_bound == const_iterator(l_bound), "lower_bound() const returned wrong iterator");
11851c0b2f7Stbbdev         REQUIRE_MESSAGE(cu_bound == const_iterator(u_bound), "upper_bound() const returned wrong iterator");
11951c0b2f7Stbbdev 
12051c0b2f7Stbbdev         REQUIRE((l_bound == eq_range.first && u_bound == eq_range.second));
12151c0b2f7Stbbdev     }
12251c0b2f7Stbbdev }
12351c0b2f7Stbbdev 
12451c0b2f7Stbbdev template <typename Container, typename CheckElementState = std::false_type>
12551c0b2f7Stbbdev void test_basic() {
12651c0b2f7Stbbdev     test_basic_common<Container, CheckElementState>();
12751c0b2f7Stbbdev     test_ordered_methods<Container>();
12851c0b2f7Stbbdev }
12951c0b2f7Stbbdev 
13051c0b2f7Stbbdev template <typename Container>
13151c0b2f7Stbbdev void test_concurrent_order() {
13251c0b2f7Stbbdev     // TODO: MinThread - MaxThread loop
13351c0b2f7Stbbdev     auto num_threads = utils::get_platform_max_threads();
13451c0b2f7Stbbdev     Container cont;
13551c0b2f7Stbbdev     int items = 1000;
13651c0b2f7Stbbdev     utils::NativeParallelFor(num_threads, [&](std::size_t index) {
13751c0b2f7Stbbdev         int step = index % 4 + 1;
13851c0b2f7Stbbdev         bool reverse = (step % 2 == 0);
13951c0b2f7Stbbdev         if (reverse) {
14051c0b2f7Stbbdev             for (int i = 0; i < items; i += step) {
14151c0b2f7Stbbdev                 cont.insert(Value<Container>::make(i));
14251c0b2f7Stbbdev             }
14351c0b2f7Stbbdev         } else {
14451c0b2f7Stbbdev             for (int i = items; i > 0; i -= step) {
14551c0b2f7Stbbdev                 cont.insert(Value<Container>::make(i));
14651c0b2f7Stbbdev             }
14751c0b2f7Stbbdev         }
14851c0b2f7Stbbdev     });
14951c0b2f7Stbbdev 
15051c0b2f7Stbbdev     check_container_order(cont);
15151c0b2f7Stbbdev }
15251c0b2f7Stbbdev 
15351c0b2f7Stbbdev template <typename Container>
15451c0b2f7Stbbdev void test_concurrent(bool asymptotic = false) {
15551c0b2f7Stbbdev     test_concurrent_common<Container>(asymptotic);
15651c0b2f7Stbbdev     test_concurrent_order<Container>();
15751c0b2f7Stbbdev }
15851c0b2f7Stbbdev 
15951c0b2f7Stbbdev struct OrderedMoveTraitsBase {
16051c0b2f7Stbbdev     static constexpr std::size_t expected_number_of_items_to_allocate_for_steal_move = 584; // TODO: remove allocation of dummy_node
16151c0b2f7Stbbdev 
16251c0b2f7Stbbdev     template <typename OrderedType, typename Iterator>
16351c0b2f7Stbbdev     static OrderedType& construct_container( typename std::aligned_storage<sizeof(OrderedType)>::type& storage,
16451c0b2f7Stbbdev                                              Iterator begin, Iterator end )
16551c0b2f7Stbbdev     {
16651c0b2f7Stbbdev         OrderedType* ptr = reinterpret_cast<OrderedType*>(&storage);
16751c0b2f7Stbbdev         new (ptr) OrderedType(begin, end);
16851c0b2f7Stbbdev         return *ptr;
16951c0b2f7Stbbdev     }
17051c0b2f7Stbbdev 
17151c0b2f7Stbbdev     template <typename OrderedType, typename Iterator, typename Allocator>
17251c0b2f7Stbbdev     static OrderedType& construct_container( typename std::aligned_storage<sizeof(OrderedType)>::type& storage,
17351c0b2f7Stbbdev                                              Iterator begin, Iterator end, const Allocator& alloc )
17451c0b2f7Stbbdev     {
17551c0b2f7Stbbdev         OrderedType* ptr = reinterpret_cast<OrderedType*>(&storage);
17651c0b2f7Stbbdev         new (ptr) OrderedType(begin, end, typename OrderedType::key_compare(), alloc);
17751c0b2f7Stbbdev         return *ptr;
17851c0b2f7Stbbdev     }
17951c0b2f7Stbbdev 
18051c0b2f7Stbbdev     template <typename OrderedType, typename Iterator>
18151c0b2f7Stbbdev     static bool equal( const OrderedType& c, Iterator begin, Iterator end ) {
18251c0b2f7Stbbdev         bool equal_sizes = std::size_t(std::distance(begin, end)) == c.size();
18351c0b2f7Stbbdev         if (!equal_sizes) return false;
18451c0b2f7Stbbdev         for (Iterator it = begin; it != end; ++it) {
18551c0b2f7Stbbdev             if (!c.contains(Value<OrderedType>::key((*it)))) return false;
18651c0b2f7Stbbdev         }
18751c0b2f7Stbbdev         return true;
18851c0b2f7Stbbdev     }
18951c0b2f7Stbbdev };
19051c0b2f7Stbbdev 
19151c0b2f7Stbbdev namespace std {
19251c0b2f7Stbbdev template <>
19351c0b2f7Stbbdev struct less<std::weak_ptr<int>> {
19451c0b2f7Stbbdev     bool operator()( const std::weak_ptr<int>& lhs, const std::weak_ptr<int>& rhs ) const {
19551c0b2f7Stbbdev         return *lhs.lock() < *rhs.lock();
19651c0b2f7Stbbdev     }
19751c0b2f7Stbbdev };
19851c0b2f7Stbbdev 
19951c0b2f7Stbbdev template <>
20051c0b2f7Stbbdev struct less<const std::weak_ptr<int>> : less<std::weak_ptr<int>> {};
20151c0b2f7Stbbdev }
20251c0b2f7Stbbdev 
20351c0b2f7Stbbdev template <bool DefCtorPresent, typename Table>
20451c0b2f7Stbbdev void Examine(Table c, const std::list<typename Table::value_type>& lst) {
20551c0b2f7Stbbdev     CommonExamine<DefCtorPresent>(c, lst);
20651c0b2f7Stbbdev }
20751c0b2f7Stbbdev 
20851c0b2f7Stbbdev template <bool DefCtorPresent, typename Table>
20951c0b2f7Stbbdev void TypeTester( const std::list<typename Table::value_type>& lst ) {
21051c0b2f7Stbbdev     REQUIRE_MESSAGE(lst.size() >= 5, "Array should have at least 5 elements");
21151c0b2f7Stbbdev     REQUIRE_MESSAGE(lst.size() <= 100, "The test has O(n^2) complexity so a big number of elements can lead long execution time");
21251c0b2f7Stbbdev 
21351c0b2f7Stbbdev     // Construct an empty table
21451c0b2f7Stbbdev     Table c1;
21551c0b2f7Stbbdev     c1.insert(lst.begin(), lst.end());
21651c0b2f7Stbbdev     Examine<DefCtorPresent>(c1, lst);
21751c0b2f7Stbbdev 
21851c0b2f7Stbbdev     typename Table::key_compare compare;
21951c0b2f7Stbbdev     typename Table::allocator_type allocator;
22051c0b2f7Stbbdev 
22151c0b2f7Stbbdev     auto it = lst.begin();
22251c0b2f7Stbbdev     auto init = {*it++, *it++, *it++};
22351c0b2f7Stbbdev 
22451c0b2f7Stbbdev     // Constructor from an std::initializer_list
22551c0b2f7Stbbdev     Table c2(init);
22651c0b2f7Stbbdev     c2.insert(it, lst.end());
22751c0b2f7Stbbdev     Examine<DefCtorPresent>(c2, lst);
22851c0b2f7Stbbdev 
22951c0b2f7Stbbdev     // Constructor from an std::initializer_list, default comparator and non-default allocator
23051c0b2f7Stbbdev     Table c2_alloc(init, allocator);
23151c0b2f7Stbbdev     c2_alloc.insert(it, lst.end());
23251c0b2f7Stbbdev     Examine<DefCtorPresent>(c2_alloc, lst);
23351c0b2f7Stbbdev 
23451c0b2f7Stbbdev     // Constructor from an std::initializer_list, non-default comparator and allocator
23551c0b2f7Stbbdev     Table c2_comp_alloc(init, compare, allocator);
23651c0b2f7Stbbdev     c2_comp_alloc.insert(it, lst.end());
23751c0b2f7Stbbdev     Examine<DefCtorPresent>(c2_comp_alloc, lst);
23851c0b2f7Stbbdev 
23951c0b2f7Stbbdev     // Copying constructor
24051c0b2f7Stbbdev     Table c3(c1);
24151c0b2f7Stbbdev     Examine<DefCtorPresent>(c3, lst);
24251c0b2f7Stbbdev 
24351c0b2f7Stbbdev     // Copying constructor with the allocator
24451c0b2f7Stbbdev     Table c3_alloc(c1, allocator);
24551c0b2f7Stbbdev     Examine<DefCtorPresent>(c3_alloc, lst);
24651c0b2f7Stbbdev 
24751c0b2f7Stbbdev     // Constructor with non-default compare
24851c0b2f7Stbbdev     Table c4(compare);
24951c0b2f7Stbbdev     c4.insert(lst.begin(), lst.end());
25051c0b2f7Stbbdev     Examine<DefCtorPresent>(c4, lst);
25151c0b2f7Stbbdev 
25251c0b2f7Stbbdev     // Constructor with non-default allocator
25351c0b2f7Stbbdev     Table c5(allocator);
25451c0b2f7Stbbdev     c5.insert(lst.begin(), lst.end());
25551c0b2f7Stbbdev     Examine<DefCtorPresent>(c5, lst);
25651c0b2f7Stbbdev 
25751c0b2f7Stbbdev     // Constructor with non-default compare and non-default allocator
25851c0b2f7Stbbdev     Table c6(compare, allocator);
25951c0b2f7Stbbdev     c6.insert(lst.begin(), lst.end());
26051c0b2f7Stbbdev     Examine<DefCtorPresent>(c6, lst);
26151c0b2f7Stbbdev 
26251c0b2f7Stbbdev     // Constructor from an iteration range
26351c0b2f7Stbbdev     Table c7(c1.begin(), c1.end());
26451c0b2f7Stbbdev     Examine<DefCtorPresent>(c7, lst);
26551c0b2f7Stbbdev 
26651c0b2f7Stbbdev     // Constructor from an iteration range, default compare and non-default allocator
26751c0b2f7Stbbdev     Table c8(c1.begin(), c1.end(), allocator);
26851c0b2f7Stbbdev     Examine<DefCtorPresent>(c8, lst);
26951c0b2f7Stbbdev 
27051c0b2f7Stbbdev     // Constructor from an iteration range, non-default compare and non-default allocator
27151c0b2f7Stbbdev     Table c9(c1.begin(), c1.end(), compare, allocator);
27251c0b2f7Stbbdev     Examine<DefCtorPresent>(c9, lst);
27351c0b2f7Stbbdev }
27451c0b2f7Stbbdev 
27551c0b2f7Stbbdev struct TransparentLess {
27651c0b2f7Stbbdev     template <typename T, typename U>
27751c0b2f7Stbbdev     auto operator()( T&& lhs, U&& rhs ) const
27851c0b2f7Stbbdev     -> decltype(std::forward<T>(lhs) < std::forward<U>(rhs)) {
27951c0b2f7Stbbdev         return lhs < rhs;
28051c0b2f7Stbbdev     }
28151c0b2f7Stbbdev 
28251c0b2f7Stbbdev     using is_transparent = void;
28351c0b2f7Stbbdev };
28451c0b2f7Stbbdev 
28551c0b2f7Stbbdev template <template <typename...> class Container, typename... Args>
28651c0b2f7Stbbdev void check_heterogeneous_functions_key_int() {
28751c0b2f7Stbbdev     check_heterogeneous_functions_key_int_impl<Container<Args..., TransparentLess>>();
28851c0b2f7Stbbdev }
28951c0b2f7Stbbdev 
29051c0b2f7Stbbdev template <template <typename...> class Container, typename... Args>
29151c0b2f7Stbbdev void check_heterogeneous_functions_key_string() {
29251c0b2f7Stbbdev     check_heterogeneous_functions_key_string_impl<Container<Args..., TransparentLess>>();
29351c0b2f7Stbbdev }
29451c0b2f7Stbbdev 
29551c0b2f7Stbbdev template <typename Container>
29651c0b2f7Stbbdev void check_heterogeneous_bound_functions() {
29751c0b2f7Stbbdev     static_assert(std::is_same<typename Container::key_type, int>::value,
29851c0b2f7Stbbdev                   "incorrect key_type for heterogeneous bounds test");
29951c0b2f7Stbbdev     // Initialization
30051c0b2f7Stbbdev     Container c;
30151c0b2f7Stbbdev     const Container& cc = c;
30251c0b2f7Stbbdev 
30351c0b2f7Stbbdev     int size = 10;
30451c0b2f7Stbbdev     for (int i = 0; i < size; ++i) {
30551c0b2f7Stbbdev         c.insert(Value<Container>::make(i));
30651c0b2f7Stbbdev     }
30751c0b2f7Stbbdev     // Insert first duplicated element for multicontainers
30851c0b2f7Stbbdev     if (AllowMultimapping<Container>::value) {
30951c0b2f7Stbbdev         c.insert(Value<Container>::make(0));
31051c0b2f7Stbbdev     }
31151c0b2f7Stbbdev 
31251c0b2f7Stbbdev     // Upper and lower bound testing
31351c0b2f7Stbbdev     for (int i = 0; i < size; ++i) {
31451c0b2f7Stbbdev         int_key k(i);
31551c0b2f7Stbbdev         int key = i;
31651c0b2f7Stbbdev 
31751c0b2f7Stbbdev         REQUIRE_MESSAGE(c.lower_bound(k) == c.lower_bound(key), "Incorrect heterogeneous lower_bound return value");
31851c0b2f7Stbbdev         REQUIRE_MESSAGE(c.upper_bound(k) == c.upper_bound(key), "Incorrect heterogeneous upper_bound return value");
31951c0b2f7Stbbdev         REQUIRE_MESSAGE(cc.lower_bound(k) == cc.lower_bound(key), "Incorrect const heterogeneous lower_bound return value");
32051c0b2f7Stbbdev         REQUIRE_MESSAGE(cc.upper_bound(k) == cc.upper_bound(key), "Incorrect const heterogeneous upper_bound return value");
32151c0b2f7Stbbdev     }
32251c0b2f7Stbbdev }
32351c0b2f7Stbbdev 
32451c0b2f7Stbbdev template <typename Container>
32551c0b2f7Stbbdev void test_comparisons_basic() {
32651c0b2f7Stbbdev     using comparisons_testing::testEqualityAndLessComparisons;
32751c0b2f7Stbbdev     Container c1, c2;
32851c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(c1, c2);
32951c0b2f7Stbbdev 
33051c0b2f7Stbbdev     c1.insert(Value<Container>::make(1));
33151c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */false, /*ExpectLess = */false>(c1, c2);
33251c0b2f7Stbbdev 
33351c0b2f7Stbbdev     c2.insert(Value<Container>::make(1));
33451c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(c1, c2);
33551c0b2f7Stbbdev 
33651c0b2f7Stbbdev     c2.insert(Value<Container>::make(2));
33751c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */false, /*ExpectLess = */true>(c1, c2);
33851c0b2f7Stbbdev 
33951c0b2f7Stbbdev     c1.clear();
34051c0b2f7Stbbdev     c2.clear();
34151c0b2f7Stbbdev 
34251c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(c1, c2);
34351c0b2f7Stbbdev }
34451c0b2f7Stbbdev 
34551c0b2f7Stbbdev template <typename TwoWayComparableContainerType>
34651c0b2f7Stbbdev void test_two_way_comparable_container() {
34751c0b2f7Stbbdev     TwoWayComparableContainerType c1, c2;
34851c0b2f7Stbbdev     c1.insert(Value<TwoWayComparableContainerType>::make(1));
34951c0b2f7Stbbdev     c2.insert(Value<TwoWayComparableContainerType>::make(1));
35051c0b2f7Stbbdev     comparisons_testing::TwoWayComparable::reset();
35151c0b2f7Stbbdev     REQUIRE_MESSAGE(!(c1 < c2), "Incorrect operator < result");
35251c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
35351c0b2f7Stbbdev     REQUIRE_MESSAGE(!(c1 > c2), "Incorrect operator > result");
35451c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
35551c0b2f7Stbbdev     REQUIRE_MESSAGE(c1 <= c2, "Incorrect operator <= result");
35651c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
35751c0b2f7Stbbdev     REQUIRE_MESSAGE(c1 >= c2, "Incorrect operator >= result");
35851c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
35951c0b2f7Stbbdev }
36051c0b2f7Stbbdev 
361*b15aabb3Stbbdev #if __TBB_TEST_CPP20_COMPARISONS
362*b15aabb3Stbbdev template <typename ThreeWayComparableContainerType>
363*b15aabb3Stbbdev void test_three_way_comparable_container() {
364*b15aabb3Stbbdev     ThreeWayComparableContainerType c1, c2;
365*b15aabb3Stbbdev     c1.insert(Value<ThreeWayComparableContainerType>::make(1));
366*b15aabb3Stbbdev     c2.insert(Value<ThreeWayComparableContainerType>::make(1));
367*b15aabb3Stbbdev     comparisons_testing::ThreeWayComparable::reset();
368*b15aabb3Stbbdev     REQUIRE_MESSAGE(!(c1 <=> c2 < 0), "Incorrect operator<=> result");
369*b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
370*b15aabb3Stbbdev 
371*b15aabb3Stbbdev     REQUIRE_MESSAGE(!(c1 < c2), "Incorrect operator< result");
372*b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
373*b15aabb3Stbbdev 
374*b15aabb3Stbbdev     REQUIRE_MESSAGE(!(c1 > c2), "Incorrect operator> result");
375*b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
376*b15aabb3Stbbdev 
377*b15aabb3Stbbdev     REQUIRE_MESSAGE(c1 <= c2, "Incorrect operator>= result");
378*b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
379*b15aabb3Stbbdev 
380*b15aabb3Stbbdev     REQUIRE_MESSAGE(c1 >= c2, "Incorrect operator>= result");
381*b15aabb3Stbbdev     comparisons_testing::check_three_way_comparison();
382*b15aabb3Stbbdev }
383*b15aabb3Stbbdev #endif
384*b15aabb3Stbbdev 
38551c0b2f7Stbbdev template <template <typename...> class ContainerType>
38651c0b2f7Stbbdev void test_map_comparisons() {
38751c0b2f7Stbbdev     using integral_container = ContainerType<int, int>;
38851c0b2f7Stbbdev     using two_way_comparable_container = ContainerType<comparisons_testing::TwoWayComparable,
38951c0b2f7Stbbdev                                                        comparisons_testing::TwoWayComparable>;
39051c0b2f7Stbbdev     test_comparisons_basic<integral_container>();
39151c0b2f7Stbbdev     test_comparisons_basic<two_way_comparable_container>();
39251c0b2f7Stbbdev     test_two_way_comparable_container<two_way_comparable_container>();
393*b15aabb3Stbbdev 
394*b15aabb3Stbbdev #if __TBB_TEST_CPP20_COMPARISONS
395*b15aabb3Stbbdev     using two_way_less_only_container = ContainerType<comparisons_testing::LessComparableOnly,
396*b15aabb3Stbbdev                                                       comparisons_testing::LessComparableOnly>;
397*b15aabb3Stbbdev 
398*b15aabb3Stbbdev     using three_way_only_container = ContainerType<comparisons_testing::ThreeWayComparableOnly,
399*b15aabb3Stbbdev                                                    comparisons_testing::ThreeWayComparableOnly>;
400*b15aabb3Stbbdev 
401*b15aabb3Stbbdev     using three_way_comparable_container = ContainerType<comparisons_testing::ThreeWayComparable,
402*b15aabb3Stbbdev                                                          comparisons_testing::ThreeWayComparable>;
403*b15aabb3Stbbdev 
404*b15aabb3Stbbdev     test_comparisons_basic<two_way_less_only_container>();
405*b15aabb3Stbbdev     test_comparisons_basic<three_way_only_container>();
406*b15aabb3Stbbdev     test_comparisons_basic<three_way_comparable_container>();
407*b15aabb3Stbbdev     test_three_way_comparable_container<three_way_comparable_container>();
408*b15aabb3Stbbdev #endif // __TBB_TEST_CPP20_COMPARISONS
40951c0b2f7Stbbdev }
41051c0b2f7Stbbdev 
41151c0b2f7Stbbdev template <template <typename...> class ContainerType>
41251c0b2f7Stbbdev void test_set_comparisons() {
41351c0b2f7Stbbdev     using integral_container = ContainerType<int>;
41451c0b2f7Stbbdev     using two_way_comparable_container = ContainerType<comparisons_testing::TwoWayComparable>;
41551c0b2f7Stbbdev 
41651c0b2f7Stbbdev     test_comparisons_basic<integral_container>();
41751c0b2f7Stbbdev     test_comparisons_basic<two_way_comparable_container>();
41851c0b2f7Stbbdev     test_two_way_comparable_container<two_way_comparable_container>();
419*b15aabb3Stbbdev 
420*b15aabb3Stbbdev #if __TBB_TEST_CPP20_COMPARISONS
421*b15aabb3Stbbdev     using two_way_less_only_container = ContainerType<comparisons_testing::LessComparableOnly>;
422*b15aabb3Stbbdev     using three_way_only_container = ContainerType<comparisons_testing::ThreeWayComparableOnly>;
423*b15aabb3Stbbdev     using three_way_comparable_container = ContainerType<comparisons_testing::ThreeWayComparable>;
424*b15aabb3Stbbdev 
425*b15aabb3Stbbdev     test_comparisons_basic<two_way_less_only_container>();
426*b15aabb3Stbbdev     test_comparisons_basic<three_way_only_container>();
427*b15aabb3Stbbdev     test_comparisons_basic<three_way_comparable_container>();
428*b15aabb3Stbbdev     test_three_way_comparable_container<three_way_comparable_container>();
429*b15aabb3Stbbdev #endif // __TBB_TEST_CPP20_COMPARISONS
43051c0b2f7Stbbdev }
43151c0b2f7Stbbdev 
43251c0b2f7Stbbdev #endif // __TBB_test_common_concurrent_ordered_common_H
433