xref: /oneTBB/test/tbb/test_parallel_sort.cpp (revision b95bbc9c)
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>
34*b95bbc9cSIvan Kochin #include <iterator>
35*b95bbc9cSIvan 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     }
49*b95bbc9cSIvan 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 
62*b95bbc9cSIvan Kochin template<typename Value>
63*b95bbc9cSIvan Kochin bool compare(const Value& lhs, const Value& rhs) {
64*b95bbc9cSIvan Kochin     return lhs == rhs;
65*b95bbc9cSIvan Kochin }
66*b95bbc9cSIvan Kochin 
67*b95bbc9cSIvan Kochin bool compare(const Minimal& lhs, const Minimal& rhs) {
68*b95bbc9cSIvan Kochin     return Minimal::AreEqual(lhs, rhs);
69*b95bbc9cSIvan Kochin }
70*b95bbc9cSIvan Kochin 
7151c0b2f7Stbbdev template<typename Range>
72*b95bbc9cSIvan Kochin void validate(Range test_range, Range sorted_range) {
73*b95bbc9cSIvan Kochin     using value_type = typename std::iterator_traits<decltype(std::begin(test_range))>::value_type;
74*b95bbc9cSIvan Kochin     REQUIRE(
75*b95bbc9cSIvan Kochin         std::equal(std::begin(test_range), std::end(test_range), std::begin(sorted_range),
76*b95bbc9cSIvan Kochin             [](const value_type& tested, const value_type& reference) {
77*b95bbc9cSIvan Kochin                 return compare(tested, reference);
7851c0b2f7Stbbdev             }
79*b95bbc9cSIvan Kochin         )
80*b95bbc9cSIvan 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 
100*b95bbc9cSIvan Kochin template <typename KeyType>
101*b95bbc9cSIvan Kochin void set(std::string& string_ref, KeyType key) {
102*b95bbc9cSIvan Kochin     static char buffer[20];
103*b95bbc9cSIvan Kochin #if _MSC_VER && __STDC_SECURE_LIB__>=200411
104*b95bbc9cSIvan Kochin     sprintf_s(buffer, sizeof(buffer), "%f", static_cast<float>(key));
105*b95bbc9cSIvan Kochin #else
106*b95bbc9cSIvan Kochin     sprintf(buffer, "%f", static_cast<float>(key));
107*b95bbc9cSIvan Kochin #endif
108*b95bbc9cSIvan Kochin     string_ref = buffer;
109*b95bbc9cSIvan Kochin }
110*b95bbc9cSIvan Kochin 
111*b95bbc9cSIvan 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 */
159*b95bbc9cSIvan Kochin template<typename ContainerType, std::size_t Size>
16051c0b2f7Stbbdev struct parallel_sort_test {
16151c0b2f7Stbbdev     static void run() {
162*b95bbc9cSIvan Kochin         std::less<typename ContainerType::value_type> default_comp;
163*b95bbc9cSIvan Kochin         ContainerType range(Size);
164*b95bbc9cSIvan Kochin         ContainerType sorted_range(Size);
16551c0b2f7Stbbdev 
166*b95bbc9cSIvan Kochin         while (fill_ranges(std::begin(range), std::begin(sorted_range), Size, default_comp)) {
167*b95bbc9cSIvan Kochin             tbb::parallel_sort(range);
168*b95bbc9cSIvan Kochin             validate(range, sorted_range);
16951c0b2f7Stbbdev         }
17051c0b2f7Stbbdev     }
17151c0b2f7Stbbdev 
17251c0b2f7Stbbdev     template<typename Comparator>
17351c0b2f7Stbbdev     static void run(Comparator& comp) {
174*b95bbc9cSIvan Kochin         ContainerType range(Size);
175*b95bbc9cSIvan Kochin         ContainerType sorted_range(Size);
17651c0b2f7Stbbdev 
177*b95bbc9cSIvan Kochin         while (fill_ranges(std::begin(range), std::begin(sorted_range), Size, comp)) {
178*b95bbc9cSIvan Kochin             tbb::parallel_sort(range, comp);
179*b95bbc9cSIvan Kochin             validate(range, sorted_range);
18051c0b2f7Stbbdev         }
18151c0b2f7Stbbdev     }
18251c0b2f7Stbbdev };
18351c0b2f7Stbbdev 
184*b95bbc9cSIvan 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);
189*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/0    >::run(comp);
190*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/1    >::run(comp);
191*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/10   >::run(comp);
192*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/9999 >::run(comp);
193*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/50000>::run(comp);
19451c0b2f7Stbbdev     }
19551c0b2f7Stbbdev }
19651c0b2f7Stbbdev 
197*b95bbc9cSIvan 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);
201*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/0    >::run();
202*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/1    >::run();
203*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/10   >::run();
204*b95bbc9cSIvan Kochin         parallel_sort_test<ContainerType, /*Size*/9999 >::run();
205*b95bbc9cSIvan 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() {
234478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator<utils::RandomIterator<int>>);
235478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator<typename std::vector<int>::iterator>);
236478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator<utils::ForwardIterator<int>>);
237478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator<utils::InputIterator<int>>);
238478de5b1Stbbdev 
239478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator_and_compare<utils::RandomIterator<int>, CorrectCompare<int>>);
240478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator_and_compare<typename std::vector<int>::iterator, CorrectCompare<int>>);
241478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<utils::ForwardIterator<int>, CorrectCompare<int>>);
242478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<utils::InputIterator<int>, CorrectCompare<int>>);
243478de5b1Stbbdev }
244478de5b1Stbbdev 
245478de5b1Stbbdev void test_psort_compare_constraints() {
246478de5b1Stbbdev     using namespace test_concepts::compare;
247478de5b1Stbbdev     using CorrectIterator = test_concepts::container_based_sequence::iterator;
248478de5b1Stbbdev     using CorrectCBS = test_concepts::container_based_sequence::Correct;
249478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, Correct<int>>);
250478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, NoOperatorRoundBrackets<int>>);
251478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, WrongFirstInputOperatorRoundBrackets<int>>);
252478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, WrongSecondInputOperatorRoundBrackets<int>>);
253478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_iterator_and_compare<CorrectIterator, WrongReturnOperatorRoundBrackets<int>>);
254478de5b1Stbbdev 
255478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, Correct<int>>);
256478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, NoOperatorRoundBrackets<int>>);
257478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, WrongFirstInputOperatorRoundBrackets<int>>);
258478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, WrongSecondInputOperatorRoundBrackets<int>>);
259478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<CorrectCBS, WrongReturnOperatorRoundBrackets<int>>);
260478de5b1Stbbdev }
261478de5b1Stbbdev 
262478de5b1Stbbdev void test_psort_cbs_constraints() {
263478de5b1Stbbdev     using namespace test_concepts::container_based_sequence;
264478de5b1Stbbdev     using CorrectCompare = test_concepts::compare::Correct<int>;
265478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_cbs<Correct>);
266478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs<NoBegin>);
267478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs<NoEnd>);
268478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs<ForwardIteratorCBS>);
269478de5b1Stbbdev 
270478de5b1Stbbdev     static_assert(can_call_parallel_sort_with_cbs_and_compare<Correct, CorrectCompare>);
271478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<NoBegin, CorrectCompare>);
272478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<NoEnd, CorrectCompare>);
273478de5b1Stbbdev     static_assert(!can_call_parallel_sort_with_cbs_and_compare<ForwardIteratorCBS, CorrectCompare>);
274478de5b1Stbbdev }
275478de5b1Stbbdev 
276478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
277478de5b1Stbbdev 
278*b95bbc9cSIvan Kochin template<typename T>
279*b95bbc9cSIvan Kochin struct minimal_span {
280*b95bbc9cSIvan Kochin     minimal_span(T* input_data, std::size_t input_size)
281*b95bbc9cSIvan Kochin      : data{input_data}
282*b95bbc9cSIvan Kochin      , size{input_size}
283*b95bbc9cSIvan Kochin     {}
284*b95bbc9cSIvan Kochin 
285*b95bbc9cSIvan Kochin     T* begin() const {
286*b95bbc9cSIvan Kochin         return data;
287*b95bbc9cSIvan Kochin     }
288*b95bbc9cSIvan Kochin     T* end() const {
289*b95bbc9cSIvan Kochin         return data + size;
290*b95bbc9cSIvan Kochin     }
291*b95bbc9cSIvan Kochin private:
292*b95bbc9cSIvan Kochin     T* data;
293*b95bbc9cSIvan Kochin     std::size_t size;
294*b95bbc9cSIvan Kochin };
295*b95bbc9cSIvan Kochin 
29651c0b2f7Stbbdev //! Minimal array sorting test (less comparator)
29751c0b2f7Stbbdev //! \brief \ref error_guessing
29851c0b2f7Stbbdev TEST_CASE("Minimal array sorting test (less comparator)") {
299*b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<Minimal>, MinimalLessCompare>();
30051c0b2f7Stbbdev }
30151c0b2f7Stbbdev 
30251c0b2f7Stbbdev //! Float array sorting test (default comparator)
30351c0b2f7Stbbdev //! \brief \ref error_guessing
30451c0b2f7Stbbdev TEST_CASE("Float array sorting test (default comparator)") {
305*b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<float>>();
30651c0b2f7Stbbdev }
30751c0b2f7Stbbdev 
30851c0b2f7Stbbdev //! tbb::concurrent_vector<float> sorting test (less comparator)
30951c0b2f7Stbbdev //! \brief \ref error_guessing
31051c0b2f7Stbbdev TEST_CASE("tbb::concurrent_vector<float> sorting test (less comparator)") {
31151c0b2f7Stbbdev     parallel_sort_test_suite<tbb::concurrent_vector<float>, std::less<float>>();
31251c0b2f7Stbbdev }
31351c0b2f7Stbbdev 
31451c0b2f7Stbbdev //! tbb::concurrent_vector<float> sorting test (default comparator)
31551c0b2f7Stbbdev //! \brief \ref error_guessing
31651c0b2f7Stbbdev TEST_CASE("tbb::concurrent_vector<float> sorting test (default comparator)") {
31751c0b2f7Stbbdev     parallel_sort_test_suite<tbb::concurrent_vector<float>>();
31851c0b2f7Stbbdev }
31951c0b2f7Stbbdev 
32051c0b2f7Stbbdev //! Array of strings sorting test (less comparator)
32151c0b2f7Stbbdev //! \brief \ref error_guessing
32251c0b2f7Stbbdev TEST_CASE("Array of strings sorting test (less comparator)") {
323*b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<std::string>, std::less<std::string>>();
32451c0b2f7Stbbdev }
32551c0b2f7Stbbdev 
32651c0b2f7Stbbdev //! Array of strings sorting test (default comparator)
32751c0b2f7Stbbdev //! \brief \ref error_guessing
32851c0b2f7Stbbdev TEST_CASE("Array of strings sorting test (default comparator)") {
329*b95bbc9cSIvan Kochin     parallel_sort_test_suite<std::vector<std::string>>();
33051c0b2f7Stbbdev }
33151c0b2f7Stbbdev 
33251c0b2f7Stbbdev //! tbb::concurrent_vector<Minimal> sorting test (less comparator)
33351c0b2f7Stbbdev //! \brief \ref error_guessing
33451c0b2f7Stbbdev TEST_CASE("tbb::concurrent_vector<Minimal> sorting test (less comparator)") {
33551c0b2f7Stbbdev     parallel_sort_test_suite<tbb::concurrent_vector<Minimal>, MinimalLessCompare>();
33651c0b2f7Stbbdev }
33751c0b2f7Stbbdev 
338*b95bbc9cSIvan Kochin constexpr std::size_t array_size = 10000;
339*b95bbc9cSIvan Kochin 
340*b95bbc9cSIvan Kochin template<typename SortFunctor>
341*b95bbc9cSIvan Kochin void sort_array_test(const SortFunctor& sort_functor) {
342*b95bbc9cSIvan Kochin     int test_array[array_size];
343*b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size; ++i)
344*b95bbc9cSIvan Kochin         test_array[i] = rand() % array_size;
345*b95bbc9cSIvan Kochin 
346*b95bbc9cSIvan Kochin     sort_functor(test_array);
347*b95bbc9cSIvan Kochin 
348*b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size - 1; ++i)
349*b95bbc9cSIvan Kochin         REQUIRE_MESSAGE(test_array[i] <= test_array[i + 1], "Testing data not sorted");
350*b95bbc9cSIvan Kochin }
35151c0b2f7Stbbdev 
35251c0b2f7Stbbdev //! Array sorting test (default comparator)
35351c0b2f7Stbbdev //! \brief \ref error_guessing
35451c0b2f7Stbbdev TEST_CASE("Array sorting test (default comparator)") {
35551c0b2f7Stbbdev     for ( auto concurrency_level : utils::concurrency_range() ) {
35651c0b2f7Stbbdev         tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_level);
357*b95bbc9cSIvan Kochin         sort_array_test([](int (&array)[array_size]) {
358*b95bbc9cSIvan Kochin             tbb::parallel_sort(array);
359*b95bbc9cSIvan Kochin         });
36051c0b2f7Stbbdev     }
36151c0b2f7Stbbdev }
36251c0b2f7Stbbdev 
363*b95bbc9cSIvan Kochin //! Test array sorting via rvalue span (default comparator)
364*b95bbc9cSIvan Kochin //! \brief \ref error_guessing
365*b95bbc9cSIvan Kochin TEST_CASE("Test array sorting via rvalue span (default comparator)") {
366*b95bbc9cSIvan Kochin     sort_array_test([](int (&array)[array_size]) {
367*b95bbc9cSIvan Kochin         tbb::parallel_sort(minimal_span<int>{array, array_size});
368*b95bbc9cSIvan Kochin     });
369*b95bbc9cSIvan Kochin }
370*b95bbc9cSIvan Kochin 
371*b95bbc9cSIvan Kochin //! Test array sorting via const span (default comparator)
372*b95bbc9cSIvan Kochin //! \brief \ref error_guessing
373*b95bbc9cSIvan Kochin TEST_CASE("Test array sorting via const span (default comparator)") {
374*b95bbc9cSIvan Kochin     sort_array_test([](int (&array)[array_size]) {
375*b95bbc9cSIvan Kochin         const minimal_span<int> span(array, array_size);
376*b95bbc9cSIvan Kochin         tbb::parallel_sort(span);
377*b95bbc9cSIvan Kochin     });
378*b95bbc9cSIvan Kochin }
379*b95bbc9cSIvan Kochin 
380*b95bbc9cSIvan Kochin //! Test rvalue container with stateful comparator
381*b95bbc9cSIvan Kochin //! \brief \ref error_guessing
382*b95bbc9cSIvan Kochin TEST_CASE("Test rvalue container with stateful comparator") {
383*b95bbc9cSIvan Kochin     // Create sorted range
384*b95bbc9cSIvan Kochin     std::vector<std::size_t> test_vector(array_size);
385*b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size; ++i)
386*b95bbc9cSIvan Kochin         test_vector[i] = i;
387*b95bbc9cSIvan Kochin 
388*b95bbc9cSIvan Kochin     std::atomic<std::size_t> count{0};
389*b95bbc9cSIvan Kochin     tbb::parallel_sort(std::move(test_vector), [&](std::size_t lhs, std::size_t rhs) {
390*b95bbc9cSIvan Kochin         ++count;
391*b95bbc9cSIvan Kochin         return lhs < rhs;
392*b95bbc9cSIvan Kochin     });
393*b95bbc9cSIvan Kochin 
394*b95bbc9cSIvan Kochin     // The comparator should be called at least (size - 1) times to check that the array is sorted
395*b95bbc9cSIvan Kochin     REQUIRE_MESSAGE(count >= array_size - 1, "Incorrect comparator calls count");
396*b95bbc9cSIvan Kochin }
397*b95bbc9cSIvan Kochin 
39851c0b2f7Stbbdev //! Testing workers going to sleep
39951c0b2f7Stbbdev //! \brief \ref resource_usage
40051c0b2f7Stbbdev TEST_CASE("That all workers sleep when no work") {
401*b95bbc9cSIvan Kochin     int test_array[array_size];
402*b95bbc9cSIvan Kochin     for (std::size_t i = 0; i < array_size; ++i)
403*b95bbc9cSIvan Kochin         test_array[i] = rand() % array_size;
40451c0b2f7Stbbdev 
40551c0b2f7Stbbdev     tbb::parallel_sort(test_array);
40651c0b2f7Stbbdev     TestCPUUserTime(utils::get_platform_max_threads());
40751c0b2f7Stbbdev }
408478de5b1Stbbdev 
409478de5b1Stbbdev #if __TBB_CPP20_CONCEPTS_PRESENT
410478de5b1Stbbdev //! \brief \ref error_guessing
411478de5b1Stbbdev TEST_CASE("parallel_sort constraints") {
412478de5b1Stbbdev     test_psort_iterator_constraints();
413478de5b1Stbbdev     test_psort_compare_constraints();
414478de5b1Stbbdev     test_psort_cbs_constraints();
415478de5b1Stbbdev }
416478de5b1Stbbdev #endif // __TBB_CPP20_CONCEPTS_PRESENT
417