xref: /oneTBB/test/tbb/test_parallel_sort.cpp (revision 4eec89fe)
151c0b2f7Stbbdev /*
2b15aabb3Stbbdev     Copyright (c) 2005-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 #include "common/test.h"
1851c0b2f7Stbbdev #include "common/utils_concurrency_limit.h"
1951c0b2f7Stbbdev #include "common/cpu_usertime.h"
20478de5b1Stbbdev #include "common/concepts_common.h"
21478de5b1Stbbdev #include "common/iterator.h"
2251c0b2f7Stbbdev 
2351c0b2f7Stbbdev #include "tbb/parallel_sort.h"
2451c0b2f7Stbbdev #include "tbb/concurrent_vector.h"
2551c0b2f7Stbbdev #include "tbb/global_control.h"
2651c0b2f7Stbbdev 
2751c0b2f7Stbbdev #include <math.h>
2851c0b2f7Stbbdev #include <vector>
2951c0b2f7Stbbdev #include <functional>
3051c0b2f7Stbbdev #include <string>
3151c0b2f7Stbbdev #include <cstring>
3251c0b2f7Stbbdev #include <cstddef>
3351c0b2f7Stbbdev #include <cstdio>
34b95bbc9cSIvan Kochin #include <iterator>
35b95bbc9cSIvan Kochin #include <type_traits>
3651c0b2f7Stbbdev 
3751c0b2f7Stbbdev //! \file test_parallel_sort.cpp
3851c0b2f7Stbbdev //! \brief Test for [algorithms.parallel_sort]
3951c0b2f7Stbbdev 
4051c0b2f7Stbbdev /** Has tightly controlled interface so that we can verify
4151c0b2f7Stbbdev     that parallel_sort uses only the required interface. */
4251c0b2f7Stbbdev class Minimal {
4351c0b2f7Stbbdev     int val;
4451c0b2f7Stbbdev public:
4551c0b2f7Stbbdev     void set_val(int i) { val = i; }
4651c0b2f7Stbbdev     static bool Less (const Minimal &a, const Minimal &b) {
4751c0b2f7Stbbdev         return (a.val < b.val);
4851c0b2f7Stbbdev     }
49b95bbc9cSIvan Kochin     static bool AreEqual( const Minimal &a, const Minimal &b) {
5051c0b2f7Stbbdev        return a.val == b.val;
5151c0b2f7Stbbdev     }
5251c0b2f7Stbbdev };
5351c0b2f7Stbbdev 
5451c0b2f7Stbbdev //! Defines a comparison function object for Minimal
5551c0b2f7Stbbdev class MinimalLessCompare {
5651c0b2f7Stbbdev public:
5751c0b2f7Stbbdev     bool operator() (const Minimal &a, const Minimal &b) const {
5851c0b2f7Stbbdev         return Minimal::Less(a,b);
5951c0b2f7Stbbdev     }
6051c0b2f7Stbbdev };
6151c0b2f7Stbbdev 
62b95bbc9cSIvan Kochin template<typename Value>
63b95bbc9cSIvan Kochin bool compare(const Value& lhs, const Value& rhs) {
64b95bbc9cSIvan Kochin     return lhs == rhs;
65b95bbc9cSIvan Kochin }
66b95bbc9cSIvan Kochin 
67b95bbc9cSIvan Kochin bool compare(const Minimal& lhs, const Minimal& rhs) {
68b95bbc9cSIvan Kochin     return Minimal::AreEqual(lhs, rhs);
69b95bbc9cSIvan Kochin }
70b95bbc9cSIvan Kochin 
7151c0b2f7Stbbdev template<typename Range>
72b95bbc9cSIvan Kochin void validate(Range test_range, Range sorted_range) {
73b95bbc9cSIvan Kochin     using value_type = typename std::iterator_traits<decltype(std::begin(test_range))>::value_type;
74b95bbc9cSIvan Kochin     REQUIRE(
75b95bbc9cSIvan Kochin         std::equal(std::begin(test_range), std::end(test_range), std::begin(sorted_range),
76b95bbc9cSIvan Kochin             [](const value_type& tested, const value_type& reference) {
77b95bbc9cSIvan Kochin                 return compare(tested, reference);
7851c0b2f7Stbbdev             }
79b95bbc9cSIvan Kochin         )
80b95bbc9cSIvan Kochin     );
8151c0b2f7Stbbdev }
8251c0b2f7Stbbdev 
8351c0b2f7Stbbdev //! The default initialization routine.
8451c0b2f7Stbbdev /*! This routine assumes that you can assign to the elements from a float.
8551c0b2f7Stbbdev     It assumes that iter and sorted_list have already been allocated. It fills
8651c0b2f7Stbbdev     them according to the current data set (tracked by a local static variable).
8751c0b2f7Stbbdev     Returns true if a valid test has been setup, or false if there is no test to
8851c0b2f7Stbbdev     perform.
8951c0b2f7Stbbdev */
9051c0b2f7Stbbdev template <typename RefType, typename ValueType>
9151c0b2f7Stbbdev void set(RefType& ref, ValueType new_value) {
9251c0b2f7Stbbdev     ref = static_cast<RefType>(new_value);
9351c0b2f7Stbbdev }
9451c0b2f7Stbbdev 
9551c0b2f7Stbbdev template <typename ValueType>
9651c0b2f7Stbbdev void set(Minimal& minimal_ref, ValueType new_value) {
9751c0b2f7Stbbdev     minimal_ref.set_val(static_cast<int>(new_value));
9851c0b2f7Stbbdev }
9951c0b2f7Stbbdev 
100b95bbc9cSIvan Kochin template <typename KeyType>
101b95bbc9cSIvan Kochin void set(std::string& string_ref, KeyType key) {
102b95bbc9cSIvan Kochin     static char buffer[20];
103b95bbc9cSIvan Kochin #if _MSC_VER && __STDC_SECURE_LIB__>=200411
104b95bbc9cSIvan Kochin     sprintf_s(buffer, sizeof(buffer), "%f", static_cast<float>(key));
105b95bbc9cSIvan Kochin #else
106b95bbc9cSIvan Kochin     sprintf(buffer, "%f", static_cast<float>(key));
107b95bbc9cSIvan Kochin #endif
108b95bbc9cSIvan Kochin     string_ref = buffer;
109b95bbc9cSIvan Kochin }
110b95bbc9cSIvan Kochin 
111b95bbc9cSIvan Kochin 
11251c0b2f7Stbbdev template <typename RandomAccessIterator, typename Compare>
11351c0b2f7Stbbdev bool fill_ranges(RandomAccessIterator test_range_begin, RandomAccessIterator sorted_range_begin,
11451c0b2f7Stbbdev     std::size_t size, const Compare &compare) {
11551c0b2f7Stbbdev 
11651c0b2f7Stbbdev     static char test_case = 0;
11751c0b2f7Stbbdev     const char num_cases = 3;
11851c0b2f7Stbbdev 
11951c0b2f7Stbbdev     if (test_case < num_cases) {
12051c0b2f7Stbbdev         // switch on the current test case, filling the test_list and sorted_list appropriately
12151c0b2f7Stbbdev         switch(test_case) {
12251c0b2f7Stbbdev             case 0:
12351c0b2f7Stbbdev                 /* use sin to generate the values */
12451c0b2f7Stbbdev                 for (std::size_t i = 0; i < size; i++) {
12551c0b2f7Stbbdev                     set(test_range_begin[i], sin(float(i)));
12651c0b2f7Stbbdev                     set(sorted_range_begin[i], sin(float(i)));
12751c0b2f7Stbbdev                 }
12851c0b2f7Stbbdev                 break;
12951c0b2f7Stbbdev             case 1:
13051c0b2f7Stbbdev                 /* presorted list */
13151c0b2f7Stbbdev                 for (std::size_t i = 0; i < size; i++) {
13251c0b2f7Stbbdev                     set(test_range_begin[i], i);
13351c0b2f7Stbbdev                     set(sorted_range_begin[i], i);
13451c0b2f7Stbbdev                 }
13551c0b2f7Stbbdev                 break;
13651c0b2f7Stbbdev             case 2:
13751c0b2f7Stbbdev                 /* reverse-sorted list */
13851c0b2f7Stbbdev                 for (std::size_t i = 0; i < size; i++) {
13951c0b2f7Stbbdev                     set(test_range_begin[i], size - i);
14051c0b2f7Stbbdev                     set(sorted_range_begin[i], size - i);
14151c0b2f7Stbbdev                 }
14251c0b2f7Stbbdev                 break;
14351c0b2f7Stbbdev         }
14451c0b2f7Stbbdev 
14551c0b2f7Stbbdev         // pre-sort sorted_range for later validity testing
14651c0b2f7Stbbdev         std::sort(sorted_range_begin, sorted_range_begin + size, compare);
14751c0b2f7Stbbdev         test_case++;
14851c0b2f7Stbbdev         return true;
14951c0b2f7Stbbdev     }
15051c0b2f7Stbbdev     test_case = 0;
15151c0b2f7Stbbdev     return false;
15251c0b2f7Stbbdev }
15351c0b2f7Stbbdev 
15451c0b2f7Stbbdev //! The default test routine.
15551c0b2f7Stbbdev /*! Tests all data set sizes from 0 to N, all grainsizes from 0 to G=10, and selects from
15651c0b2f7Stbbdev     all possible interfaces to parallel_sort depending on whether a scratch space and
15751c0b2f7Stbbdev     compare have been provided.
15851c0b2f7Stbbdev */
159b95bbc9cSIvan Kochin template<typename ContainerType, std::size_t Size>
16051c0b2f7Stbbdev struct parallel_sort_test {
16151c0b2f7Stbbdev     static void run() {
162b95bbc9cSIvan Kochin         std::less<typename ContainerType::value_type> default_comp;
163b95bbc9cSIvan Kochin         ContainerType range(Size);
164b95bbc9cSIvan Kochin         ContainerType sorted_range(Size);
16551c0b2f7Stbbdev 
166b95bbc9cSIvan Kochin         while (fill_ranges(std::begin(range), std::begin(sorted_range), Size, default_comp)) {
167b95bbc9cSIvan Kochin             tbb::parallel_sort(range);
168b95bbc9cSIvan Kochin             validate(range, sorted_range);
16951c0b2f7Stbbdev         }
17051c0b2f7Stbbdev     }
17151c0b2f7Stbbdev 
17251c0b2f7Stbbdev     template<typename Comparator>
17351c0b2f7Stbbdev     static void run(Comparator& comp) {
174b95bbc9cSIvan Kochin         ContainerType range(Size);
175b95bbc9cSIvan Kochin         ContainerType sorted_range(Size);
17651c0b2f7Stbbdev 
177b95bbc9cSIvan Kochin         while (fill_ranges(std::begin(range), std::begin(sorted_range), Size, comp)) {
178b95bbc9cSIvan Kochin             tbb::parallel_sort(range, comp);
179b95bbc9cSIvan Kochin             validate(range, sorted_range);
18051c0b2f7Stbbdev         }
18151c0b2f7Stbbdev     }
18251c0b2f7Stbbdev };
18351c0b2f7Stbbdev 
184b95bbc9cSIvan Kochin template<typename ContainerType, typename Comparator>
18551c0b2f7Stbbdev void parallel_sort_test_suite() {
18651c0b2f7Stbbdev     Comparator comp;
18751c0b2f7Stbbdev     for (auto concurrency_level : utils::concurrency_range()) {
18851c0b2f7Stbbdev         tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level);
189b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/0    >::run(comp);
190b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/1    >::run(comp);
191b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/10   >::run(comp);
192b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/9999 >::run(comp);
193b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/50000>::run(comp);
19451c0b2f7Stbbdev     }
19551c0b2f7Stbbdev }
19651c0b2f7Stbbdev 
197b95bbc9cSIvan Kochin template<typename ContainerType>
19851c0b2f7Stbbdev void parallel_sort_test_suite() {
19951c0b2f7Stbbdev     for (auto concurrency_level : utils::concurrency_range()) {
20051c0b2f7Stbbdev         tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level);
201b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/0    >::run();
202b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/1    >::run();
203b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/10   >::run();
204b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/9999 >::run();
205b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/50000>::run();
20651c0b2f7Stbbdev     }
20751c0b2f7Stbbdev }
20851c0b2f7Stbbdev 
209478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
210478de5b1Stbbdev template <typename RandomAccessIterator>
211478de5b1Stbbdev concept can_call_parallel_sort_with_iterator = requires( RandomAccessIterator it ) {
212478de5b1Stbbdev     tbb::parallel_sort(it, it);
213478de5b1Stbbdev };
214478de5b1Stbbdev 
215478de5b1Stbbdev template <typename RandomAccessIterator, typename Compare>
216478de5b1Stbbdev concept can_call_parallel_sort_with_iterator_and_compare = requires( RandomAccessIterator it, const Compare& compare ) {
217478de5b1Stbbdev     tbb::parallel_sort(it, it, compare);
218478de5b1Stbbdev };
219478de5b1Stbbdev 
220478de5b1Stbbdev template <typename CBS>
221478de5b1Stbbdev concept can_call_parallel_sort_with_cbs = requires( CBS& cbs ) {
222478de5b1Stbbdev     tbb::parallel_sort(cbs);
223478de5b1Stbbdev };
224478de5b1Stbbdev 
225478de5b1Stbbdev template <typename CBS, typename Compare>
226478de5b1Stbbdev concept can_call_parallel_sort_with_cbs_and_compare = requires( CBS& cbs, const Compare& compare ) {
227478de5b1Stbbdev     tbb::parallel_sort(cbs, compare);
228478de5b1Stbbdev };
229478de5b1Stbbdev 
230478de5b1Stbbdev template <typename T>
231478de5b1Stbbdev using CorrectCompare = test_concepts::compare::Correct<T>;
232478de5b1Stbbdev 
233478de5b1Stbbdev void test_psort_iterator_constraints() {
234*4eec89feSIvan Kochin     using namespace test_concepts::parallel_sort_value;
235*4eec89feSIvan Kochin 
236478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator<utils::RandomIterator<int>>);
237478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator<typename std::vector<int>::iterator>);
238478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator<utils::ForwardIterator<int>>);
239478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator<utils::InputIterator<int>>);
240*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_iterator<utils::RandomIterator<NonMovableValue>>);
241*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_iterator<utils::RandomIterator<NonMoveAssignableValue>>);
242*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_iterator<utils::RandomIterator<NonComparableValue>>);
243*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_iterator<test_concepts::ConstantIT<int>>);
244478de5b1Stbbdev 
245478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator_and_compare<utils::RandomIterator<int>, CorrectCompare<int>>);
246478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator_and_compare<typename std::vector<int>::iterator, CorrectCompare<int>>);
247478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<utils::ForwardIterator<int>, CorrectCompare<int>>);
248478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<utils::InputIterator<int>, CorrectCompare<int>>);
249*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_iterator_and_compare<utils::RandomIterator<NonMovableValue>, CorrectCompare<NonMovableValue>>);
250*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_iterator_and_compare<utils::RandomIterator<NonMoveAssignableValue>, CorrectCompare<NonMoveAssignableValue>>);
251*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_iterator_and_compare<test_concepts::ConstantIT<int>, CorrectCompare<const int>>);
252478de5b1Stbbdev }
253478de5b1Stbbdev 
254478de5b1Stbbdev void test_psort_compare_constraints() {
255478de5b1Stbbdev     using namespace test_concepts::compare;
256*4eec89feSIvan Kochin 
257478de5b1Stbbdev     using CorrectCBS = test_concepts::container_based_sequence::Correct;
258*4eec89feSIvan Kochin     using CorrectIterator = CorrectCBS::iterator;
259478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, Correct<int>>);
260478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, NoOperatorRoundBrackets<int>>);
261478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, WrongFirstInputOperatorRoundBrackets<int>>);
262478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, WrongSecondInputOperatorRoundBrackets<int>>);
263478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, WrongReturnOperatorRoundBrackets<int>>);
264478de5b1Stbbdev 
265478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, Correct<int>>);
266478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, NoOperatorRoundBrackets<int>>);
267478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, WrongFirstInputOperatorRoundBrackets<int>>);
268478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, WrongSecondInputOperatorRoundBrackets<int>>);
269478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, WrongReturnOperatorRoundBrackets<int>>);
270478de5b1Stbbdev }
271478de5b1Stbbdev 
272478de5b1Stbbdev void test_psort_cbs_constraints() {
273478de5b1Stbbdev     using namespace test_concepts::container_based_sequence;
274*4eec89feSIvan Kochin     using namespace test_concepts::parallel_sort_value;
275*4eec89feSIvan Kochin 
276478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_cbs<Correct>);
277478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs<NoBegin>);
278478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs<NoEnd>);
279478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs<ForwardIteratorCBS>);
280*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_cbs<ConstantCBS>);
281478de5b1Stbbdev 
282*4eec89feSIvan Kochin     static_assert(can_call_parallel_sort_with_cbs<CustomValueCBS<CorrectValue>>);
283*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_cbs<CustomValueCBS<NonMovableValue>>);
284*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_cbs<CustomValueCBS<NonMoveAssignableValue>>);
285*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_cbs<CustomValueCBS<NonComparableValue>>);\
286*4eec89feSIvan Kochin 
287*4eec89feSIvan Kochin     using CorrectCompare = test_concepts::compare::Correct<int>;
288*4eec89feSIvan Kochin     using NonMovableCompare = test_concepts::compare::Correct<NonMovableValue>;
289*4eec89feSIvan Kochin     using NonMoveAssignableCompare = test_concepts::compare::Correct<NonMoveAssignableValue>;
290478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_cbs_and_compare<Correct, CorrectCompare>);
291478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<NoBegin, CorrectCompare>);
292478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<NoEnd, CorrectCompare>);
293478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<ForwardIteratorCBS, CorrectCompare>);
294*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_cbs_and_compare<ConstantCBS, CorrectCompare>);
295*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CustomValueCBS<NonMovableValue>, NonMovableCompare>);
296*4eec89feSIvan Kochin     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CustomValueCBS<NonMoveAssignableValue>, NonMoveAssignableCompare>);
297478de5b1Stbbdev }
298478de5b1Stbbdev 
299478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
300478de5b1Stbbdev 
301b95bbc9cSIvan Kochin template<typename T>
302b95bbc9cSIvan Kochin struct minimal_span {
303b95bbc9cSIvan Kochin     minimal_span(T* input_data, std::size_t input_size)
304b95bbc9cSIvan Kochin      : data{input_data}
305b95bbc9cSIvan Kochin      , size{input_size}
306b95bbc9cSIvan Kochin     {}
307b95bbc9cSIvan Kochin 
308b95bbc9cSIvan Kochin     T* begin() const {
309b95bbc9cSIvan Kochin         return data;
310b95bbc9cSIvan Kochin     }
311b95bbc9cSIvan Kochin     T* end() const {
312b95bbc9cSIvan Kochin         return data + size;
313b95bbc9cSIvan Kochin     }
314b95bbc9cSIvan Kochin private:
315b95bbc9cSIvan Kochin     T* data;
316b95bbc9cSIvan Kochin     std::size_t size;
317b95bbc9cSIvan Kochin };
318b95bbc9cSIvan Kochin 
31951c0b2f7Stbbdev //! Minimal array sorting test (less comparator)
32051c0b2f7Stbbdev //! \brief \ref error_guessing
32151c0b2f7Stbbdev TEST_CASE("Minimal array sorting test (less comparator)") {
322b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<Minimal>, MinimalLessCompare>();
32351c0b2f7Stbbdev }
32451c0b2f7Stbbdev 
32551c0b2f7Stbbdev //! Float array sorting test (default comparator)
32651c0b2f7Stbbdev //! \brief \ref error_guessing
32751c0b2f7Stbbdev TEST_CASE("Float array sorting test (default comparator)") {
328b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<float>>();
32951c0b2f7Stbbdev }
33051c0b2f7Stbbdev 
33151c0b2f7Stbbdev //! tbb::concurrent_vector<float> sorting test (less comparator)
33251c0b2f7Stbbdev //! \brief \ref error_guessing
33351c0b2f7Stbbdev TEST_CASE("tbb::concurrent_vector<float> sorting test (less comparator)") {
33451c0b2f7Stbbdev     parallel_sort_test_suite<tbb::concurrent_vector<float>, std::less<float>>();
33551c0b2f7Stbbdev }
33651c0b2f7Stbbdev 
33751c0b2f7Stbbdev //! tbb::concurrent_vector<float> sorting test (default comparator)
33851c0b2f7Stbbdev //! \brief \ref error_guessing
33951c0b2f7Stbbdev TEST_CASE("tbb::concurrent_vector<float> sorting test (default comparator)") {
34051c0b2f7Stbbdev     parallel_sort_test_suite<tbb::concurrent_vector<float>>();
34151c0b2f7Stbbdev }
34251c0b2f7Stbbdev 
34351c0b2f7Stbbdev //! Array of strings sorting test (less comparator)
34451c0b2f7Stbbdev //! \brief \ref error_guessing
34551c0b2f7Stbbdev TEST_CASE("Array of strings sorting test (less comparator)") {
346b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<std::string>, std::less<std::string>>();
34751c0b2f7Stbbdev }
34851c0b2f7Stbbdev 
34951c0b2f7Stbbdev //! Array of strings sorting test (default comparator)
35051c0b2f7Stbbdev //! \brief \ref error_guessing
35151c0b2f7Stbbdev TEST_CASE("Array of strings sorting test (default comparator)") {
352b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<std::string>>();
35351c0b2f7Stbbdev }
35451c0b2f7Stbbdev 
35551c0b2f7Stbbdev //! tbb::concurrent_vector<Minimal> sorting test (less comparator)
35651c0b2f7Stbbdev //! \brief \ref error_guessing
35751c0b2f7Stbbdev TEST_CASE("tbb::concurrent_vector<Minimal> sorting test (less comparator)") {
35851c0b2f7Stbbdev     parallel_sort_test_suite<tbb::concurrent_vector<Minimal>, MinimalLessCompare>();
35951c0b2f7Stbbdev }
36051c0b2f7Stbbdev 
361b95bbc9cSIvan Kochin constexpr std::size_t array_size = 10000;
362b95bbc9cSIvan Kochin 
363b95bbc9cSIvan Kochin template<typename SortFunctor>
364b95bbc9cSIvan Kochin void sort_array_test(const SortFunctor& sort_functor) {
365b95bbc9cSIvan Kochin     int test_array[array_size];
366b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size; ++i)
367b95bbc9cSIvan Kochin         test_array[i] = rand() % array_size;
368b95bbc9cSIvan Kochin 
369b95bbc9cSIvan Kochin     sort_functor(test_array);
370b95bbc9cSIvan Kochin 
371b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size - 1; ++i)
372b95bbc9cSIvan Kochin         REQUIRE_MESSAGE(test_array[i] <= test_array[i + 1], "Testing data not sorted");
373b95bbc9cSIvan Kochin }
37451c0b2f7Stbbdev 
37551c0b2f7Stbbdev //! Array sorting test (default comparator)
37651c0b2f7Stbbdev //! \brief \ref error_guessing
37751c0b2f7Stbbdev TEST_CASE("Array sorting test (default comparator)") {
37851c0b2f7Stbbdev     for ( auto concurrency_level : utils::concurrency_range() ) {
37951c0b2f7Stbbdev         tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level);
380b95bbc9cSIvan Kochin         sort_array_test([](int (&array)[array_size]) {
381b95bbc9cSIvan Kochin             tbb::parallel_sort(array);
382b95bbc9cSIvan Kochin         });
38351c0b2f7Stbbdev     }
38451c0b2f7Stbbdev }
38551c0b2f7Stbbdev 
386b95bbc9cSIvan Kochin //! Test array sorting via rvalue span (default comparator)
387b95bbc9cSIvan Kochin //! \brief \ref error_guessing
388b95bbc9cSIvan Kochin TEST_CASE("Test array sorting via rvalue span (default comparator)") {
389b95bbc9cSIvan Kochin     sort_array_test([](int (&array)[array_size]) {
390b95bbc9cSIvan Kochin         tbb::parallel_sort(minimal_span<int>{array, array_size});
391b95bbc9cSIvan Kochin     });
392b95bbc9cSIvan Kochin }
393b95bbc9cSIvan Kochin 
394b95bbc9cSIvan Kochin //! Test array sorting via const span (default comparator)
395b95bbc9cSIvan Kochin //! \brief \ref error_guessing
396b95bbc9cSIvan Kochin TEST_CASE("Test array sorting via const span (default comparator)") {
397b95bbc9cSIvan Kochin     sort_array_test([](int (&array)[array_size]) {
398b95bbc9cSIvan Kochin         const minimal_span<int> span(array, array_size);
399b95bbc9cSIvan Kochin         tbb::parallel_sort(span);
400b95bbc9cSIvan Kochin     });
401b95bbc9cSIvan Kochin }
402b95bbc9cSIvan Kochin 
403b95bbc9cSIvan Kochin //! Test rvalue container with stateful comparator
404b95bbc9cSIvan Kochin //! \brief \ref error_guessing
405b95bbc9cSIvan Kochin TEST_CASE("Test rvalue container with stateful comparator") {
406b95bbc9cSIvan Kochin     // Create sorted range
407b95bbc9cSIvan Kochin     std::vector<std::size_t> test_vector(array_size);
408b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size; ++i)
409b95bbc9cSIvan Kochin         test_vector[i] = i;
410b95bbc9cSIvan Kochin 
411b95bbc9cSIvan Kochin     std::atomic<std::size_t> count{0};
412b95bbc9cSIvan Kochin     tbb::parallel_sort(std::move(test_vector), [&](std::size_t lhs, std::size_t rhs) {
413b95bbc9cSIvan Kochin         ++count;
414b95bbc9cSIvan Kochin         return lhs < rhs;
415b95bbc9cSIvan Kochin     });
416b95bbc9cSIvan Kochin 
417b95bbc9cSIvan Kochin     // The comparator should be called at least (size - 1) times to check that the array is sorted
418b95bbc9cSIvan Kochin     REQUIRE_MESSAGE(count >= array_size - 1, "Incorrect comparator calls count");
419b95bbc9cSIvan Kochin }
420b95bbc9cSIvan Kochin 
42151c0b2f7Stbbdev //! Testing workers going to sleep
42251c0b2f7Stbbdev //! \brief \ref resource_usage
42351c0b2f7Stbbdev TEST_CASE("That all workers sleep when no work") {
424b95bbc9cSIvan Kochin     int test_array[array_size];
425b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size; ++i)
426b95bbc9cSIvan Kochin         test_array[i] = rand() % array_size;
42751c0b2f7Stbbdev 
42851c0b2f7Stbbdev     tbb::parallel_sort(test_array);
42951c0b2f7Stbbdev     TestCPUUserTime(utils::get_platform_max_threads());
43051c0b2f7Stbbdev }
431478de5b1Stbbdev 
432478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
433478de5b1Stbbdev //! \brief \ref error_guessing
434478de5b1Stbbdev TEST_CASE("parallel_sort constraints") {
435478de5b1Stbbdev     test_psort_iterator_constraints();
436478de5b1Stbbdev     test_psort_compare_constraints();
437478de5b1Stbbdev     test_psort_cbs_constraints();
438478de5b1Stbbdev }
439478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
440