// -*- C++ -*- //===-- test_partial_sort.cpp ---------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // Tests for partial_sort #include #include "pstl/execution" #include "pstl/algorithm" #include "utils.h" using namespace TestUtils; static std::atomic count_val; static std::atomic count_comp; template struct Num { T val; Num() { ++count_val; } Num(T v) : val(v) { ++count_val; } Num(const Num& v) : val(v.val) { ++count_val; } Num(Num&& v) : val(v.val) { ++count_val; } ~Num() { --count_val; } Num& operator=(const Num& v) { val = v.val; return *this; } operator T() const { return val; } bool operator<(const Num& v) const { ++count_comp; return val < v.val; } }; struct test_brick_partial_sort { template typename std::enable_if::value, void>::type operator()(Policy&& exec, InputIterator first, InputIterator last, InputIterator exp_first, InputIterator exp_last, Compare compare) { typedef typename std::iterator_traits::value_type T; // The rand()%(2*n+1) encourages generation of some duplicates. std::srand(42); const std::size_t n = last - first; for (std::size_t k = 0; k < n; ++k) { first[k] = T(rand() % (2 * n + 1)); } std::copy(first, last, exp_first); for (std::size_t p = 0; p < n; p = p <= 16 ? p + 1 : std::size_t(31.415 * p)) { auto m1 = first + p; auto m2 = exp_first + p; std::partial_sort(exp_first, m2, exp_last, compare); count_comp = 0; std::partial_sort(exec, first, m1, last, compare); EXPECT_EQ_N(exp_first, first, p, "wrong effect from partial_sort"); //checking upper bound number of comparisons; O(p*(last-first)log(middle-first)); where p - number of threads; if (m1 - first > 1) { auto complex = std::ceil(n * std::log(float32_t(m1 - first))); #if __PSTL_USE_PAR_POLICIES auto p = tbb::this_task_arena::max_concurrency(); #else auto p = 1; #endif #ifdef _DEBUG if (count_comp > complex * p) { std::cout << "complexity exceeded" << std::endl; } #endif } } } template typename std::enable_if::value, void>::type operator()(Policy&& exec, InputIterator first, InputIterator last, InputIterator exp_first, InputIterator exp_last, Compare compare) { } }; template void test_partial_sort(Compare compare) { const std::size_t n_max = 100000; Sequence in(n_max); Sequence exp(n_max); for (std::size_t n = 0; n < n_max; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) { invoke_on_all_policies(test_brick_partial_sort(), in.begin(), in.begin() + n, exp.begin(), exp.begin() + n, compare); } } template struct test_non_const { template void operator()(Policy&& exec, Iterator iter) { partial_sort(exec, iter, iter, iter, non_const(std::less())); } }; int32_t main() { count_val = 0; test_partial_sort>([](Num x, Num y) { return x < y; }); EXPECT_TRUE(count_val == 0, "cleanup error"); test_partial_sort( [](int32_t x, int32_t y) { return x > y; }); // Reversed so accidental use of < will be detected. test_algo_basic_single(run_for_rnd>()); std::cout << done() << std::endl; return 0; }