1*51c0b2f7Stbbdev /*
2*51c0b2f7Stbbdev     Copyright (c) 2019-2020 Intel Corporation
3*51c0b2f7Stbbdev 
4*51c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5*51c0b2f7Stbbdev     you may not use this file except in compliance with the License.
6*51c0b2f7Stbbdev     You may obtain a copy of the License at
7*51c0b2f7Stbbdev 
8*51c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
9*51c0b2f7Stbbdev 
10*51c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
11*51c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12*51c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*51c0b2f7Stbbdev     See the License for the specific language governing permissions and
14*51c0b2f7Stbbdev     limitations under the License.
15*51c0b2f7Stbbdev */
16*51c0b2f7Stbbdev 
17*51c0b2f7Stbbdev #ifndef __TBB_test_common_concurrent_ordered_common_H
18*51c0b2f7Stbbdev #define __TBB_test_common_concurrent_ordered_common_H
19*51c0b2f7Stbbdev 
20*51c0b2f7Stbbdev #include "common/concurrent_associative_common.h"
21*51c0b2f7Stbbdev #include "test_comparisons.h"
22*51c0b2f7Stbbdev 
23*51c0b2f7Stbbdev template<typename MyTable>
24*51c0b2f7Stbbdev inline void CheckContainerAllocator(MyTable &table, size_t expected_allocs, size_t expected_frees, bool exact) {
25*51c0b2f7Stbbdev     typename MyTable::allocator_type a = table.get_allocator();
26*51c0b2f7Stbbdev     CheckAllocator<MyTable>(a, expected_allocs, expected_frees, exact);
27*51c0b2f7Stbbdev }
28*51c0b2f7Stbbdev 
29*51c0b2f7Stbbdev template<typename Container>
30*51c0b2f7Stbbdev inline void CheckNoAllocations(Container&) {
31*51c0b2f7Stbbdev     // TODO: enable
32*51c0b2f7Stbbdev     // CheckContainerAllocator(cont, 0, 0, false);
33*51c0b2f7Stbbdev }
34*51c0b2f7Stbbdev 
35*51c0b2f7Stbbdev template <typename Container>
36*51c0b2f7Stbbdev struct OrderChecker {
37*51c0b2f7Stbbdev     typename Container::value_compare& val_comp;
38*51c0b2f7Stbbdev     typename Container::key_compare& key_comp;
39*51c0b2f7Stbbdev 
40*51c0b2f7Stbbdev     OrderChecker(typename Container::value_compare& v_comp, typename Container::key_compare& k_comp)
41*51c0b2f7Stbbdev         : val_comp(v_comp), key_comp(k_comp) {}
42*51c0b2f7Stbbdev 
43*51c0b2f7Stbbdev     bool operator()(const typename Container::value_type& lhs, const typename Container::value_type& rhs) {
44*51c0b2f7Stbbdev         if (AllowMultimapping<Container>::value)
45*51c0b2f7Stbbdev             // We need to use not greater comparator for multicontainer
46*51c0b2f7Stbbdev             return !val_comp(rhs, lhs) && !key_comp(Value<Container>::key(rhs), Value<Container>::key(lhs));
47*51c0b2f7Stbbdev         return val_comp(lhs, rhs) && key_comp(Value<Container>::key(lhs), Value<Container>::key(rhs));
48*51c0b2f7Stbbdev     }
49*51c0b2f7Stbbdev }; // struct OrderChecker
50*51c0b2f7Stbbdev 
51*51c0b2f7Stbbdev template <typename Container>
52*51c0b2f7Stbbdev void check_container_order( const Container& cont ) {
53*51c0b2f7Stbbdev     if (!cont.empty()) {
54*51c0b2f7Stbbdev         typename Container::key_compare key_comp = cont.key_comp();
55*51c0b2f7Stbbdev         typename Container::value_compare value_comp = cont.value_comp();
56*51c0b2f7Stbbdev         OrderChecker<Container> check_order(value_comp, key_comp);
57*51c0b2f7Stbbdev 
58*51c0b2f7Stbbdev         for (auto it = cont.begin(); std::next(it) != cont.end();) {
59*51c0b2f7Stbbdev             auto pr_it = it++;
60*51c0b2f7Stbbdev             REQUIRE_MESSAGE(check_order(*pr_it, *it), "The order of the elements is broken");
61*51c0b2f7Stbbdev         }
62*51c0b2f7Stbbdev     }
63*51c0b2f7Stbbdev }
64*51c0b2f7Stbbdev 
65*51c0b2f7Stbbdev template <typename Container>
66*51c0b2f7Stbbdev void test_ordered_methods() {
67*51c0b2f7Stbbdev     Container cont;
68*51c0b2f7Stbbdev     const Container& ccont = cont;
69*51c0b2f7Stbbdev 
70*51c0b2f7Stbbdev     int r, random_threshold = 10, uncontained_key = random_threshold / 2;
71*51c0b2f7Stbbdev     for (int i = 0; i < 100; ++i) {
72*51c0b2f7Stbbdev         r = std::rand() % random_threshold;
73*51c0b2f7Stbbdev         if (r != uncontained_key) {
74*51c0b2f7Stbbdev             cont.insert(Value<Container>::make(r));
75*51c0b2f7Stbbdev         }
76*51c0b2f7Stbbdev     }
77*51c0b2f7Stbbdev 
78*51c0b2f7Stbbdev     check_container_order(cont);
79*51c0b2f7Stbbdev 
80*51c0b2f7Stbbdev     typename Container::value_compare val_comp = cont.value_comp();
81*51c0b2f7Stbbdev     typename Container::iterator l_bound_check, u_bound_check;
82*51c0b2f7Stbbdev     for (int key = -1; key < random_threshold + 1; ++key) {
83*51c0b2f7Stbbdev         auto eq_range = cont.equal_range(key);
84*51c0b2f7Stbbdev         // Check equal_range content
85*51c0b2f7Stbbdev         for (auto it = eq_range.first; it != eq_range.second; ++it)
86*51c0b2f7Stbbdev             REQUIRE_MESSAGE(*it == Value<Container>::make(key), "equal_range contains wrong value");
87*51c0b2f7Stbbdev 
88*51c0b2f7Stbbdev         // Manual search of upper and lower bounds
89*51c0b2f7Stbbdev         l_bound_check = cont.end();
90*51c0b2f7Stbbdev         u_bound_check = cont.end();
91*51c0b2f7Stbbdev         for (auto it = cont.begin(); it != cont.end(); ++it){
92*51c0b2f7Stbbdev             if (!val_comp(*it, Value<Container>::make(key)) && l_bound_check == cont.end()) {
93*51c0b2f7Stbbdev                 l_bound_check = it;
94*51c0b2f7Stbbdev             }
95*51c0b2f7Stbbdev             if (val_comp(Value<Container>::make(key), *it) && u_bound_check == cont.end()) {
96*51c0b2f7Stbbdev                 u_bound_check = it;
97*51c0b2f7Stbbdev                 break;
98*51c0b2f7Stbbdev             }
99*51c0b2f7Stbbdev         }
100*51c0b2f7Stbbdev 
101*51c0b2f7Stbbdev         typename Container::range_type cont_range = cont.range();
102*51c0b2f7Stbbdev         typename Container::const_range_type ccont_range = ccont.range();
103*51c0b2f7Stbbdev         REQUIRE_MESSAGE(cont_range.size() == ccont_range.size(), "Incorrect ordered container range size");
104*51c0b2f7Stbbdev         REQUIRE_MESSAGE(cont_range.size() == cont.size(), "Incorrect ordered container range size");
105*51c0b2f7Stbbdev 
106*51c0b2f7Stbbdev         typename Container::iterator l_bound = cont.lower_bound(key);
107*51c0b2f7Stbbdev         typename Container::iterator u_bound = cont.upper_bound(key);
108*51c0b2f7Stbbdev 
109*51c0b2f7Stbbdev         REQUIRE_MESSAGE(l_bound == l_bound_check, "lower_bound() returned wrong iterator");
110*51c0b2f7Stbbdev         REQUIRE_MESSAGE(u_bound == u_bound_check, "upper_bound() returned wrong iterator");
111*51c0b2f7Stbbdev 
112*51c0b2f7Stbbdev         using const_iterator = typename Container::const_iterator;
113*51c0b2f7Stbbdev         const_iterator cl_bound = ccont.lower_bound(key);
114*51c0b2f7Stbbdev         const_iterator cu_bound = ccont.upper_bound(key);
115*51c0b2f7Stbbdev 
116*51c0b2f7Stbbdev         REQUIRE_MESSAGE(cl_bound == const_iterator(l_bound), "lower_bound() const returned wrong iterator");
117*51c0b2f7Stbbdev         REQUIRE_MESSAGE(cu_bound == const_iterator(u_bound), "upper_bound() const returned wrong iterator");
118*51c0b2f7Stbbdev 
119*51c0b2f7Stbbdev         REQUIRE((l_bound == eq_range.first && u_bound == eq_range.second));
120*51c0b2f7Stbbdev     }
121*51c0b2f7Stbbdev }
122*51c0b2f7Stbbdev 
123*51c0b2f7Stbbdev template <typename Container, typename CheckElementState = std::false_type>
124*51c0b2f7Stbbdev void test_basic() {
125*51c0b2f7Stbbdev     test_basic_common<Container, CheckElementState>();
126*51c0b2f7Stbbdev     test_ordered_methods<Container>();
127*51c0b2f7Stbbdev }
128*51c0b2f7Stbbdev 
129*51c0b2f7Stbbdev template <typename Container>
130*51c0b2f7Stbbdev void test_concurrent_order() {
131*51c0b2f7Stbbdev     // TODO: MinThread - MaxThread loop
132*51c0b2f7Stbbdev     auto num_threads = utils::get_platform_max_threads();
133*51c0b2f7Stbbdev     Container cont;
134*51c0b2f7Stbbdev     int items = 1000;
135*51c0b2f7Stbbdev     utils::NativeParallelFor(num_threads, [&](std::size_t index) {
136*51c0b2f7Stbbdev         int step = index % 4 + 1;
137*51c0b2f7Stbbdev         bool reverse = (step % 2 == 0);
138*51c0b2f7Stbbdev         if (reverse) {
139*51c0b2f7Stbbdev             for (int i = 0; i < items; i += step) {
140*51c0b2f7Stbbdev                 cont.insert(Value<Container>::make(i));
141*51c0b2f7Stbbdev             }
142*51c0b2f7Stbbdev         } else {
143*51c0b2f7Stbbdev             for (int i = items; i > 0; i -= step) {
144*51c0b2f7Stbbdev                 cont.insert(Value<Container>::make(i));
145*51c0b2f7Stbbdev             }
146*51c0b2f7Stbbdev         }
147*51c0b2f7Stbbdev     });
148*51c0b2f7Stbbdev 
149*51c0b2f7Stbbdev     check_container_order(cont);
150*51c0b2f7Stbbdev }
151*51c0b2f7Stbbdev 
152*51c0b2f7Stbbdev template <typename Container>
153*51c0b2f7Stbbdev void test_concurrent(bool asymptotic = false) {
154*51c0b2f7Stbbdev     test_concurrent_common<Container>(asymptotic);
155*51c0b2f7Stbbdev     test_concurrent_order<Container>();
156*51c0b2f7Stbbdev }
157*51c0b2f7Stbbdev 
158*51c0b2f7Stbbdev struct OrderedMoveTraitsBase {
159*51c0b2f7Stbbdev     static constexpr std::size_t expected_number_of_items_to_allocate_for_steal_move = 584; // TODO: remove allocation of dummy_node
160*51c0b2f7Stbbdev 
161*51c0b2f7Stbbdev     template <typename OrderedType, typename Iterator>
162*51c0b2f7Stbbdev     static OrderedType& construct_container( typename std::aligned_storage<sizeof(OrderedType)>::type& storage,
163*51c0b2f7Stbbdev                                              Iterator begin, Iterator end )
164*51c0b2f7Stbbdev     {
165*51c0b2f7Stbbdev         OrderedType* ptr = reinterpret_cast<OrderedType*>(&storage);
166*51c0b2f7Stbbdev         new (ptr) OrderedType(begin, end);
167*51c0b2f7Stbbdev         return *ptr;
168*51c0b2f7Stbbdev     }
169*51c0b2f7Stbbdev 
170*51c0b2f7Stbbdev     template <typename OrderedType, typename Iterator, typename Allocator>
171*51c0b2f7Stbbdev     static OrderedType& construct_container( typename std::aligned_storage<sizeof(OrderedType)>::type& storage,
172*51c0b2f7Stbbdev                                              Iterator begin, Iterator end, const Allocator& alloc )
173*51c0b2f7Stbbdev     {
174*51c0b2f7Stbbdev         OrderedType* ptr = reinterpret_cast<OrderedType*>(&storage);
175*51c0b2f7Stbbdev         new (ptr) OrderedType(begin, end, typename OrderedType::key_compare(), alloc);
176*51c0b2f7Stbbdev         return *ptr;
177*51c0b2f7Stbbdev     }
178*51c0b2f7Stbbdev 
179*51c0b2f7Stbbdev     template <typename OrderedType, typename Iterator>
180*51c0b2f7Stbbdev     static bool equal( const OrderedType& c, Iterator begin, Iterator end ) {
181*51c0b2f7Stbbdev         bool equal_sizes = std::size_t(std::distance(begin, end)) == c.size();
182*51c0b2f7Stbbdev         if (!equal_sizes) return false;
183*51c0b2f7Stbbdev         for (Iterator it = begin; it != end; ++it) {
184*51c0b2f7Stbbdev             if (!c.contains(Value<OrderedType>::key((*it)))) return false;
185*51c0b2f7Stbbdev         }
186*51c0b2f7Stbbdev         return true;
187*51c0b2f7Stbbdev     }
188*51c0b2f7Stbbdev };
189*51c0b2f7Stbbdev 
190*51c0b2f7Stbbdev namespace std {
191*51c0b2f7Stbbdev template <>
192*51c0b2f7Stbbdev struct less<std::weak_ptr<int>> {
193*51c0b2f7Stbbdev     bool operator()( const std::weak_ptr<int>& lhs, const std::weak_ptr<int>& rhs ) const {
194*51c0b2f7Stbbdev         return *lhs.lock() < *rhs.lock();
195*51c0b2f7Stbbdev     }
196*51c0b2f7Stbbdev };
197*51c0b2f7Stbbdev 
198*51c0b2f7Stbbdev template <>
199*51c0b2f7Stbbdev struct less<const std::weak_ptr<int>> : less<std::weak_ptr<int>> {};
200*51c0b2f7Stbbdev }
201*51c0b2f7Stbbdev 
202*51c0b2f7Stbbdev template <bool DefCtorPresent, typename Table>
203*51c0b2f7Stbbdev void Examine(Table c, const std::list<typename Table::value_type>& lst) {
204*51c0b2f7Stbbdev     CommonExamine<DefCtorPresent>(c, lst);
205*51c0b2f7Stbbdev }
206*51c0b2f7Stbbdev 
207*51c0b2f7Stbbdev template <bool DefCtorPresent, typename Table>
208*51c0b2f7Stbbdev void TypeTester( const std::list<typename Table::value_type>& lst ) {
209*51c0b2f7Stbbdev     REQUIRE_MESSAGE(lst.size() >= 5, "Array should have at least 5 elements");
210*51c0b2f7Stbbdev     REQUIRE_MESSAGE(lst.size() <= 100, "The test has O(n^2) complexity so a big number of elements can lead long execution time");
211*51c0b2f7Stbbdev 
212*51c0b2f7Stbbdev     // Construct an empty table
213*51c0b2f7Stbbdev     Table c1;
214*51c0b2f7Stbbdev     c1.insert(lst.begin(), lst.end());
215*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c1, lst);
216*51c0b2f7Stbbdev 
217*51c0b2f7Stbbdev     typename Table::key_compare compare;
218*51c0b2f7Stbbdev     typename Table::allocator_type allocator;
219*51c0b2f7Stbbdev 
220*51c0b2f7Stbbdev     auto it = lst.begin();
221*51c0b2f7Stbbdev     auto init = {*it++, *it++, *it++};
222*51c0b2f7Stbbdev 
223*51c0b2f7Stbbdev     // Constructor from an std::initializer_list
224*51c0b2f7Stbbdev     Table c2(init);
225*51c0b2f7Stbbdev     c2.insert(it, lst.end());
226*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c2, lst);
227*51c0b2f7Stbbdev 
228*51c0b2f7Stbbdev     // Constructor from an std::initializer_list, default comparator and non-default allocator
229*51c0b2f7Stbbdev     Table c2_alloc(init, allocator);
230*51c0b2f7Stbbdev     c2_alloc.insert(it, lst.end());
231*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c2_alloc, lst);
232*51c0b2f7Stbbdev 
233*51c0b2f7Stbbdev     // Constructor from an std::initializer_list, non-default comparator and allocator
234*51c0b2f7Stbbdev     Table c2_comp_alloc(init, compare, allocator);
235*51c0b2f7Stbbdev     c2_comp_alloc.insert(it, lst.end());
236*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c2_comp_alloc, lst);
237*51c0b2f7Stbbdev 
238*51c0b2f7Stbbdev     // Copying constructor
239*51c0b2f7Stbbdev     Table c3(c1);
240*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c3, lst);
241*51c0b2f7Stbbdev 
242*51c0b2f7Stbbdev     // Copying constructor with the allocator
243*51c0b2f7Stbbdev     Table c3_alloc(c1, allocator);
244*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c3_alloc, lst);
245*51c0b2f7Stbbdev 
246*51c0b2f7Stbbdev     // Constructor with non-default compare
247*51c0b2f7Stbbdev     Table c4(compare);
248*51c0b2f7Stbbdev     c4.insert(lst.begin(), lst.end());
249*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c4, lst);
250*51c0b2f7Stbbdev 
251*51c0b2f7Stbbdev     // Constructor with non-default allocator
252*51c0b2f7Stbbdev     Table c5(allocator);
253*51c0b2f7Stbbdev     c5.insert(lst.begin(), lst.end());
254*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c5, lst);
255*51c0b2f7Stbbdev 
256*51c0b2f7Stbbdev     // Constructor with non-default compare and non-default allocator
257*51c0b2f7Stbbdev     Table c6(compare, allocator);
258*51c0b2f7Stbbdev     c6.insert(lst.begin(), lst.end());
259*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c6, lst);
260*51c0b2f7Stbbdev 
261*51c0b2f7Stbbdev     // Constructor from an iteration range
262*51c0b2f7Stbbdev     Table c7(c1.begin(), c1.end());
263*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c7, lst);
264*51c0b2f7Stbbdev 
265*51c0b2f7Stbbdev     // Constructor from an iteration range, default compare and non-default allocator
266*51c0b2f7Stbbdev     Table c8(c1.begin(), c1.end(), allocator);
267*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c8, lst);
268*51c0b2f7Stbbdev 
269*51c0b2f7Stbbdev     // Constructor from an iteration range, non-default compare and non-default allocator
270*51c0b2f7Stbbdev     Table c9(c1.begin(), c1.end(), compare, allocator);
271*51c0b2f7Stbbdev     Examine<DefCtorPresent>(c9, lst);
272*51c0b2f7Stbbdev }
273*51c0b2f7Stbbdev 
274*51c0b2f7Stbbdev struct TransparentLess {
275*51c0b2f7Stbbdev     template <typename T, typename U>
276*51c0b2f7Stbbdev     auto operator()( T&& lhs, U&& rhs ) const
277*51c0b2f7Stbbdev     -> decltype(std::forward<T>(lhs) < std::forward<U>(rhs)) {
278*51c0b2f7Stbbdev         return lhs < rhs;
279*51c0b2f7Stbbdev     }
280*51c0b2f7Stbbdev 
281*51c0b2f7Stbbdev     using is_transparent = void;
282*51c0b2f7Stbbdev };
283*51c0b2f7Stbbdev 
284*51c0b2f7Stbbdev template <template <typename...> class Container, typename... Args>
285*51c0b2f7Stbbdev void check_heterogeneous_functions_key_int() {
286*51c0b2f7Stbbdev     check_heterogeneous_functions_key_int_impl<Container<Args..., TransparentLess>>();
287*51c0b2f7Stbbdev }
288*51c0b2f7Stbbdev 
289*51c0b2f7Stbbdev template <template <typename...> class Container, typename... Args>
290*51c0b2f7Stbbdev void check_heterogeneous_functions_key_string() {
291*51c0b2f7Stbbdev     check_heterogeneous_functions_key_string_impl<Container<Args..., TransparentLess>>();
292*51c0b2f7Stbbdev }
293*51c0b2f7Stbbdev 
294*51c0b2f7Stbbdev template <typename Container>
295*51c0b2f7Stbbdev void check_heterogeneous_bound_functions() {
296*51c0b2f7Stbbdev     static_assert(std::is_same<typename Container::key_type, int>::value,
297*51c0b2f7Stbbdev                   "incorrect key_type for heterogeneous bounds test");
298*51c0b2f7Stbbdev     // Initialization
299*51c0b2f7Stbbdev     Container c;
300*51c0b2f7Stbbdev     const Container& cc = c;
301*51c0b2f7Stbbdev 
302*51c0b2f7Stbbdev     int size = 10;
303*51c0b2f7Stbbdev     for (int i = 0; i < size; ++i) {
304*51c0b2f7Stbbdev         c.insert(Value<Container>::make(i));
305*51c0b2f7Stbbdev     }
306*51c0b2f7Stbbdev     // Insert first duplicated element for multicontainers
307*51c0b2f7Stbbdev     if (AllowMultimapping<Container>::value) {
308*51c0b2f7Stbbdev         c.insert(Value<Container>::make(0));
309*51c0b2f7Stbbdev     }
310*51c0b2f7Stbbdev 
311*51c0b2f7Stbbdev     // Upper and lower bound testing
312*51c0b2f7Stbbdev     for (int i = 0; i < size; ++i) {
313*51c0b2f7Stbbdev         int_key k(i);
314*51c0b2f7Stbbdev         int key = i;
315*51c0b2f7Stbbdev 
316*51c0b2f7Stbbdev         REQUIRE_MESSAGE(c.lower_bound(k) == c.lower_bound(key), "Incorrect heterogeneous lower_bound return value");
317*51c0b2f7Stbbdev         REQUIRE_MESSAGE(c.upper_bound(k) == c.upper_bound(key), "Incorrect heterogeneous upper_bound return value");
318*51c0b2f7Stbbdev         REQUIRE_MESSAGE(cc.lower_bound(k) == cc.lower_bound(key), "Incorrect const heterogeneous lower_bound return value");
319*51c0b2f7Stbbdev         REQUIRE_MESSAGE(cc.upper_bound(k) == cc.upper_bound(key), "Incorrect const heterogeneous upper_bound return value");
320*51c0b2f7Stbbdev     }
321*51c0b2f7Stbbdev }
322*51c0b2f7Stbbdev 
323*51c0b2f7Stbbdev template <typename Container>
324*51c0b2f7Stbbdev void test_comparisons_basic() {
325*51c0b2f7Stbbdev     using comparisons_testing::testEqualityAndLessComparisons;
326*51c0b2f7Stbbdev     Container c1, c2;
327*51c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(c1, c2);
328*51c0b2f7Stbbdev 
329*51c0b2f7Stbbdev     c1.insert(Value<Container>::make(1));
330*51c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */false, /*ExpectLess = */false>(c1, c2);
331*51c0b2f7Stbbdev 
332*51c0b2f7Stbbdev     c2.insert(Value<Container>::make(1));
333*51c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(c1, c2);
334*51c0b2f7Stbbdev 
335*51c0b2f7Stbbdev     c2.insert(Value<Container>::make(2));
336*51c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */false, /*ExpectLess = */true>(c1, c2);
337*51c0b2f7Stbbdev 
338*51c0b2f7Stbbdev     c1.clear();
339*51c0b2f7Stbbdev     c2.clear();
340*51c0b2f7Stbbdev 
341*51c0b2f7Stbbdev     testEqualityAndLessComparisons</*ExpectEqual = */true, /*ExpectLess = */false>(c1, c2);
342*51c0b2f7Stbbdev }
343*51c0b2f7Stbbdev 
344*51c0b2f7Stbbdev template <typename TwoWayComparableContainerType>
345*51c0b2f7Stbbdev void test_two_way_comparable_container() {
346*51c0b2f7Stbbdev     TwoWayComparableContainerType c1, c2;
347*51c0b2f7Stbbdev     c1.insert(Value<TwoWayComparableContainerType>::make(1));
348*51c0b2f7Stbbdev     c2.insert(Value<TwoWayComparableContainerType>::make(1));
349*51c0b2f7Stbbdev     comparisons_testing::TwoWayComparable::reset();
350*51c0b2f7Stbbdev     REQUIRE_MESSAGE(!(c1 < c2), "Incorrect operator < result");
351*51c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
352*51c0b2f7Stbbdev     REQUIRE_MESSAGE(!(c1 > c2), "Incorrect operator > result");
353*51c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
354*51c0b2f7Stbbdev     REQUIRE_MESSAGE(c1 <= c2, "Incorrect operator <= result");
355*51c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
356*51c0b2f7Stbbdev     REQUIRE_MESSAGE(c1 >= c2, "Incorrect operator >= result");
357*51c0b2f7Stbbdev     comparisons_testing::check_two_way_comparison();
358*51c0b2f7Stbbdev }
359*51c0b2f7Stbbdev 
360*51c0b2f7Stbbdev template <template <typename...> class ContainerType>
361*51c0b2f7Stbbdev void test_map_comparisons() {
362*51c0b2f7Stbbdev     using integral_container = ContainerType<int, int>;
363*51c0b2f7Stbbdev     using two_way_comparable_container = ContainerType<comparisons_testing::TwoWayComparable,
364*51c0b2f7Stbbdev                                                        comparisons_testing::TwoWayComparable>;
365*51c0b2f7Stbbdev     test_comparisons_basic<integral_container>();
366*51c0b2f7Stbbdev     test_comparisons_basic<two_way_comparable_container>();
367*51c0b2f7Stbbdev     test_two_way_comparable_container<two_way_comparable_container>();
368*51c0b2f7Stbbdev }
369*51c0b2f7Stbbdev 
370*51c0b2f7Stbbdev template <template <typename...> class ContainerType>
371*51c0b2f7Stbbdev void test_set_comparisons() {
372*51c0b2f7Stbbdev     using integral_container = ContainerType<int>;
373*51c0b2f7Stbbdev     using two_way_comparable_container = ContainerType<comparisons_testing::TwoWayComparable>;
374*51c0b2f7Stbbdev 
375*51c0b2f7Stbbdev     test_comparisons_basic<integral_container>();
376*51c0b2f7Stbbdev     test_comparisons_basic<two_way_comparable_container>();
377*51c0b2f7Stbbdev     test_two_way_comparable_container<two_way_comparable_container>();
378*51c0b2f7Stbbdev }
379*51c0b2f7Stbbdev 
380*51c0b2f7Stbbdev #endif // __TBB_test_common_concurrent_ordered_common_H
381