summaryrefslogtreecommitdiffstats
path: root/pstl/test/std/algorithms/alg.sorting
diff options
context:
space:
mode:
authorLouis Dionne <ldionne@apple.com>2019-03-27 21:28:24 +0000
committerLouis Dionne <ldionne@apple.com>2019-03-27 21:28:24 +0000
commit3b62047b8b2209bed57d239f581bdbfc91a10b94 (patch)
treee321a0dea2d7355c3eca7c9cf9ae1f2b89823c1d /pstl/test/std/algorithms/alg.sorting
parent4bc38cfe297746858a7159bd4a537261d628b47e (diff)
downloadbcm5719-llvm-3b62047b8b2209bed57d239f581bdbfc91a10b94.tar.gz
bcm5719-llvm-3b62047b8b2209bed57d239f581bdbfc91a10b94.zip
Restructure test suite to follow libc++ standard layout
Summary: Subsumes changes requested in https://reviews.llvm.org/D59110 Reviewers: EricWF, ldionne Subscribers: mgorny, krytarowski, jfb, jdoerfert, libcxx-commits Differential Revision: https://reviews.llvm.org/D59856 llvm-svn: 357124
Diffstat (limited to 'pstl/test/std/algorithms/alg.sorting')
-rw-r--r--pstl/test/std/algorithms/alg.sorting/alg.heap.operations/is_heap.pass.cpp148
-rw-r--r--pstl/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp179
-rw-r--r--pstl/test/std/algorithms/alg.sorting/alg.min.max/minmax_element.pass.cpp198
-rw-r--r--pstl/test/std/algorithms/alg.sorting/alg.set.operations/includes.pass.cpp111
-rw-r--r--pstl/test/std/algorithms/alg.sorting/alg.set.operations/set.pass.cpp167
-rw-r--r--pstl/test/std/algorithms/alg.sorting/is_sorted.pass.cpp104
-rw-r--r--pstl/test/std/algorithms/alg.sorting/partial_sort.pass.cpp156
-rw-r--r--pstl/test/std/algorithms/alg.sorting/partial_sort_copy.pass.cpp195
-rw-r--r--pstl/test/std/algorithms/alg.sorting/sort.pass.cpp251
9 files changed, 1509 insertions, 0 deletions
diff --git a/pstl/test/std/algorithms/alg.sorting/alg.heap.operations/is_heap.pass.cpp b/pstl/test/std/algorithms/alg.sorting/alg.heap.operations/is_heap.pass.cpp
new file mode 100644
index 00000000000..0c70342426e
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/alg.heap.operations/is_heap.pass.cpp
@@ -0,0 +1,148 @@
+// -*- C++ -*-
+//===-- is_heap.pass.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Tests for is_heap, is_heap_until
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+#include <iostream>
+
+using namespace TestUtils;
+
+struct WithCmpOp
+{
+ int32_t _first;
+ int32_t _second;
+ WithCmpOp() : _first(0), _second(0){};
+ explicit WithCmpOp(int32_t x) : _first(x), _second(x){};
+ bool
+ operator<(const WithCmpOp& rhs) const
+ {
+ return this->_first < rhs._first;
+ }
+};
+
+struct test_is_heap
+{
+#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
+ __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specialization by policy type, in case of broken configuration
+ template <typename Iterator, typename Predicate>
+ typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
+ operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Predicate pred)
+ {
+ }
+ template <typename Iterator, typename Predicate>
+ typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
+ operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Predicate pred)
+ {
+ }
+#endif
+
+ template <typename Policy, typename Iterator, typename Predicate>
+ typename std::enable_if<is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
+ operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred)
+ {
+ using namespace std;
+ // is_heap
+ {
+ bool expected = is_heap(first, last);
+ bool actual = is_heap(exec, first, last);
+ EXPECT_TRUE(expected == actual, "wrong return value from is_heap");
+ }
+ // is_heap with predicate
+ {
+ bool expected = is_heap(first, last, pred);
+ bool actual = is_heap(exec, first, last, pred);
+ EXPECT_TRUE(expected == actual, "wrong return value from is_heap with predicate");
+ }
+ // is_heap_until
+ {
+ Iterator expected = is_heap_until(first, last);
+ Iterator actual = is_heap_until(exec, first, last);
+ EXPECT_TRUE(expected == actual, "wrong return value from is_heap_until");
+ }
+ // is_heap_until with predicate
+ {
+ const Iterator expected = is_heap_until(first, last, pred);
+ const auto y = std::distance(first, expected);
+ const Iterator actual = is_heap_until(exec, first, last, pred);
+ const auto x = std::distance(first, actual);
+ EXPECT_TRUE(expected == actual, "wrong return value from is_heap_until with predicate");
+ }
+ }
+
+ // is_heap, is_heap_until works only with random access iterators
+ template <typename Policy, typename Iterator, typename Predicate>
+ typename std::enable_if<!is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value, void>::type
+ operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred)
+ {
+ }
+};
+
+template <typename T, typename Comp>
+void
+test_is_heap_by_type(Comp comp)
+{
+ using namespace std;
+
+ const size_t max_size = 100000;
+ for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
+ {
+ Sequence<T> in(n, [](size_t v) -> T { return T(v); });
+
+ invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp);
+
+ std::make_heap(in.begin(), in.begin() + n / 4, comp);
+ invoke_on_all_policies(test_is_heap(), in.cbegin(), in.cend(), comp);
+
+ std::make_heap(in.begin(), in.begin() + n / 3, comp);
+ invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp);
+
+ std::make_heap(in.begin(), in.end(), comp);
+ invoke_on_all_policies(test_is_heap(), in.cbegin(), in.cend(), comp);
+ }
+
+ Sequence<T> in(max_size / 10, [](size_t v) -> T { return T(1); });
+ invoke_on_all_policies(test_is_heap(), in.begin(), in.end(), comp);
+}
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator iter)
+ {
+ invoke_if(exec, [&]() {
+ is_heap(exec, iter, iter, non_const(std::less<T>()));
+ is_heap_until(exec, iter, iter, non_const(std::less<T>()));
+ });
+ }
+};
+
+int32_t
+main()
+{
+ test_is_heap_by_type<float32_t>(std::greater<float32_t>());
+ test_is_heap_by_type<WithCmpOp>(std::less<WithCmpOp>());
+ test_is_heap_by_type<uint64_t>([](uint64_t x, uint64_t y) { return x % 100 < y % 100; });
+
+ test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp b/pstl/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp
new file mode 100644
index 00000000000..236e34290ae
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/alg.lex.comparison/lexicographical_compare.pass.cpp
@@ -0,0 +1,179 @@
+// -*- C++ -*-
+//===-- lexicographical_compare.pass.cpp ----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+#include <iostream>
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+using namespace TestUtils;
+
+struct test_one_policy
+{
+
+ template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Predicate>
+ void
+ operator()(ExecutionPolicy&& exec, Iterator1 begin1, Iterator1 end1, Iterator2 begin2, Iterator2 end2,
+ Predicate pred)
+ {
+ const bool expected = std::lexicographical_compare(begin1, end1, begin2, end2, pred);
+ const bool actual = std::lexicographical_compare(exec, begin1, end1, begin2, end2, pred);
+ EXPECT_TRUE(actual == expected, "wrong return result from lexicographical compare with predicate");
+ }
+
+ template <typename ExecutionPolicy, typename Iterator1, typename Iterator2>
+ void
+ operator()(ExecutionPolicy&& exec, Iterator1 begin1, Iterator1 end1, Iterator2 begin2, Iterator2 end2)
+ {
+ const bool expected = std::lexicographical_compare(begin1, end1, begin2, end2);
+ const bool actual = std::lexicographical_compare(exec, begin1, end1, begin2, end2);
+ EXPECT_TRUE(actual == expected, "wrong return result from lexicographical compare without predicate");
+ }
+};
+
+template <typename T1, typename T2, typename Predicate>
+void
+test(Predicate pred)
+{
+
+ const std::size_t max_n = 1000000;
+ Sequence<T1> in1(max_n, [](std::size_t k) { return T1(k); });
+ Sequence<T2> in2(2 * max_n, [](std::size_t k) { return T2(k); });
+
+ std::size_t n2;
+
+ // Test case: Call algorithm's version without predicate.
+ invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + max_n, in2.cbegin() + 3 * max_n / 10,
+ in2.cbegin() + 5 * max_n / 10);
+
+ // Test case: If one range is a prefix of another, the shorter range is lexicographically less than the other.
+ std::size_t max_n2 = max_n / 10;
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + max_n, in2.cbegin(), in2.cbegin() + max_n2,
+ pred);
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + max_n, in2.begin() + max_n2,
+ in2.begin() + 3 * max_n2, pred);
+
+ // Test case: If one range is a prefix of another, the shorter range is lexicographically less than the other.
+ max_n2 = 2 * max_n;
+ invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + max_n, in2.begin(), in2.begin() + max_n2,
+ pred);
+
+ for (std::size_t n1 = 0; n1 <= max_n; n1 = n1 <= 16 ? n1 + 1 : std::size_t(3.1415 * n1))
+ {
+ // Test case: If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
+ n2 = n1;
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
+
+ n2 = n1;
+ // Test case: two ranges have different elements and are of the same length (second sequence less than first)
+ std::size_t ind = n1 / 2;
+ in2[ind] = T2(-1);
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
+ in2[ind] = T2(ind);
+
+ // Test case: two ranges have different elements and are of the same length (first sequence less than second)
+ ind = n1 / 5;
+ in1[ind] = T1(-1);
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.cbegin(), in2.cbegin() + n2, pred);
+ in1[ind] = T1(ind);
+ }
+}
+
+template <typename Predicate>
+void
+test_string(Predicate pred)
+{
+
+ const std::size_t max_n = 1000000;
+ std::string in1 = "";
+ std::string in2 = "";
+ for (std::size_t n1 = 0; n1 <= max_n; ++n1)
+ {
+ in1 += n1;
+ }
+
+ for (std::size_t n1 = 0; n1 <= 2 * max_n; ++n1)
+ {
+ in2 += n1;
+ }
+
+ std::size_t n2;
+
+ for (std::size_t n1 = 0; n1 < in1.size(); n1 = n1 <= 16 ? n1 + 1 : std::size_t(3.1415 * n1))
+ {
+ // Test case: If two ranges have equivalent elements and are of the same length, then the ranges are lexicographically equal.
+ n2 = n1;
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
+
+ n2 = n1;
+ // Test case: two ranges have different elements and are of the same length (second sequence less than first)
+ in2[n1 / 2] = 'a';
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.begin(), in2.begin() + n2, pred);
+
+ // Test case: two ranges have different elements and are of the same length (first sequence less than second)
+ in1[n1 / 5] = 'a';
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.cbegin(), in2.cbegin() + n2, pred);
+ }
+ invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + max_n, in2.cbegin() + 3 * max_n / 10,
+ in2.cbegin() + 5 * max_n / 10);
+}
+
+template <typename T>
+struct LocalWrapper
+{
+ explicit LocalWrapper(std::size_t k) : my_val(k) {}
+ bool
+ operator<(const LocalWrapper<T>& w) const
+ {
+ return my_val < w.my_val;
+ }
+
+ private:
+ T my_val;
+};
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename FirstIterator, typename SecondInterator>
+ void
+ operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter)
+ {
+ invoke_if(exec, [&]() {
+ lexicographical_compare(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::less<T>()));
+ });
+ }
+};
+
+int32_t
+main()
+{
+ test<uint16_t, float64_t>(std::less<float64_t>());
+ test<float32_t, int32_t>(std::greater<float32_t>());
+#if !__PSTL_ICC_18_TEST_EARLY_EXIT_AVX_RELEASE_BROKEN
+ test<float64_t, int32_t>([](const float64_t x, const int32_t y) { return x * x < y * y; });
+#endif
+ test<LocalWrapper<int32_t>, LocalWrapper<int32_t>>(
+ [](const LocalWrapper<int32_t>& x, const LocalWrapper<int32_t>& y) { return x < y; });
+ test_string([](const char x, const char y) { return x < y; });
+
+ test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/alg.min.max/minmax_element.pass.cpp b/pstl/test/std/algorithms/alg.sorting/alg.min.max/minmax_element.pass.cpp
new file mode 100644
index 00000000000..e3fec868375
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/alg.min.max/minmax_element.pass.cpp
@@ -0,0 +1,198 @@
+// -*- C++ -*-
+//===-- minmax_element.pass.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+#include <set>
+#include <cassert>
+#include <cmath>
+
+using namespace TestUtils;
+
+struct check_minelement
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator begin, Iterator end)
+ {
+ typedef typename std::iterator_traits<Iterator>::value_type T;
+ const Iterator expect = std::min_element(begin, end);
+ const Iterator result = std::min_element(exec, begin, end);
+ const Iterator result_pred = std::min_element(exec, begin, end, std::less<T>());
+ EXPECT_TRUE(expect == result, "wrong return result from min_element");
+ EXPECT_TRUE(expect == result_pred, "wrong return result from min_element");
+ }
+};
+
+struct check_maxelement
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator begin, Iterator end)
+ {
+ typedef typename std::iterator_traits<Iterator>::value_type T;
+ const Iterator expect = std::max_element(begin, end);
+ const Iterator result = std::max_element(exec, begin, end);
+ const Iterator result_pred = std::max_element(exec, begin, end, std::less<T>());
+ EXPECT_TRUE(expect == result, "wrong return result from max_element");
+ EXPECT_TRUE(expect == result_pred, "wrong return result from max_element");
+ }
+};
+
+struct check_minmaxelement
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator begin, Iterator end)
+ {
+ typedef typename std::iterator_traits<Iterator>::value_type T;
+ const std::pair<Iterator, Iterator> expect = std::minmax_element(begin, end);
+ const std::pair<Iterator, Iterator> got = std::minmax_element(exec, begin, end);
+ const std::pair<Iterator, Iterator> got_pred = std::minmax_element(exec, begin, end, std::less<T>());
+ EXPECT_TRUE(expect.first == got.first, "wrong return result from minmax_element (min part)");
+ EXPECT_TRUE(expect.second == got.second, "wrong return result from minmax_element (max part)");
+ EXPECT_TRUE(expect == got_pred, "wrong return result from minmax_element");
+ }
+};
+
+template <typename T>
+struct sequence_wrapper
+{
+ TestUtils::Sequence<T> seq;
+ const T min_value;
+ const T max_value;
+ static const std::size_t bits = 30; // We assume that T can handle signed 2^bits+1 value
+
+ // TestUtils::HashBits returns value between 0 and (1<<bits)-1,
+ // therefore we could threat 1<<bits as maximum and -(1<<bits) as a minimum
+ sequence_wrapper(std::size_t n) : seq(n), min_value(-(1 << bits)), max_value(1 << bits) {}
+
+ void
+ pattern_fill()
+ {
+ seq.fill([](std::size_t i) -> T { return T(TestUtils::HashBits(i, bits)); });
+ }
+
+ // sets first one at position `at` and bunch of them farther
+ void
+ set_desired_value(std::size_t at, T value)
+ {
+ if (seq.size() == 0)
+ return;
+ seq[at] = value;
+
+ //Producing serveral red herrings
+ for (std::size_t i = at + 1; i < seq.size(); i += 1 + TestUtils::HashBits(i, 5))
+ seq[i] = value;
+ }
+};
+
+template <typename T>
+void
+test_by_type(std::size_t n)
+{
+ sequence_wrapper<T> wseq(n);
+
+ // to avoid overtesing we use std::set to leave only unique indexes
+ std::set<std::size_t> targets{0};
+ if (n > 1)
+ {
+ targets.insert(1);
+ targets.insert(2.718282 * n / 3);
+ targets.insert(n / 2);
+ targets.insert(n / 7.389056);
+ targets.insert(n - 1); // last
+ }
+
+ for (std::set<std::size_t>::iterator it = targets.begin(); it != targets.end(); ++it)
+ {
+ wseq.pattern_fill();
+ wseq.set_desired_value(*it, wseq.min_value);
+ TestUtils::invoke_on_all_policies(check_minelement(), wseq.seq.cbegin(), wseq.seq.cend());
+ TestUtils::invoke_on_all_policies(check_minelement(), wseq.seq.begin(), wseq.seq.end());
+
+ wseq.set_desired_value(*it, wseq.max_value);
+ TestUtils::invoke_on_all_policies(check_maxelement(), wseq.seq.cbegin(), wseq.seq.cend());
+ TestUtils::invoke_on_all_policies(check_maxelement(), wseq.seq.begin(), wseq.seq.end());
+
+ if (targets.size() > 1)
+ {
+ for (std::set<std::size_t>::reverse_iterator rit = targets.rbegin(); rit != targets.rend(); ++rit)
+ {
+ if (*rit == *it) // we requires at least 2 unique indexes in targets
+ break;
+ wseq.pattern_fill();
+ wseq.set_desired_value(*it, wseq.min_value); // setting minimum element
+ wseq.set_desired_value(*rit, wseq.max_value); // setting maximum element
+ TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.cbegin(), wseq.seq.cend());
+ TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.begin(), wseq.seq.end());
+ }
+ }
+ else
+ { // we must check this corner case; it can not be tested in loop above
+ TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.cbegin(), wseq.seq.cend());
+ TestUtils::invoke_on_all_policies(check_minmaxelement(), wseq.seq.begin(), wseq.seq.end());
+ }
+ }
+}
+
+// should provide minimal requirements only
+struct OnlyLessCompare
+{
+ int32_t val;
+ OnlyLessCompare() : val(0) {}
+ OnlyLessCompare(int32_t val_) : val(val_) {}
+ bool
+ operator<(const OnlyLessCompare& other) const
+ {
+ return val < other.val;
+ }
+};
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator iter)
+ {
+ max_element(exec, iter, iter, non_const(std::less<T>()));
+ min_element(exec, iter, iter, non_const(std::less<T>()));
+ minmax_element(exec, iter, iter, non_const(std::less<T>()));
+ }
+};
+
+int32_t
+main()
+{
+ using TestUtils::float64_t;
+ const std::size_t N = 100000;
+
+ for (std::size_t n = 0; n < N; n = n < 16 ? n + 1 : size_t(3.14159 * n))
+ {
+ test_by_type<float64_t>(n);
+ test_by_type<OnlyLessCompare>(n);
+ }
+
+ test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
+
+ std::cout << TestUtils::done() << std::endl;
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/alg.set.operations/includes.pass.cpp b/pstl/test/std/algorithms/alg.sorting/alg.set.operations/includes.pass.cpp
new file mode 100644
index 00000000000..b18bb5f69f0
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/alg.set.operations/includes.pass.cpp
@@ -0,0 +1,111 @@
+// -*- C++ -*-
+//===-- includes.pass.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+
+#include <cmath>
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+using namespace TestUtils;
+
+template <typename T>
+struct Num
+{
+ T val;
+ explicit Num(const T& v) : val(v) {}
+
+ //for "includes" checks
+ template <typename T1>
+ bool
+ operator<(const Num<T1>& v1) const
+ {
+ return val < v1.val;
+ }
+
+ //The types Type1 and Type2 must be such that an object of type InputIt can be dereferenced and then implicitly converted to both of them
+ template <typename T1>
+ operator Num<T1>() const
+ {
+ return Num<T1>((T1)val);
+ }
+};
+
+struct test_one_policy
+{
+ template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
+ typename std::enable_if<!TestUtils::isReverse<InputIterator1>::value, void>::type
+ operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
+ Compare comp)
+ {
+
+ auto expect_res = std::includes(first1, last1, first2, last2, comp);
+ auto res = std::includes(exec, first1, last1, first2, last2, comp);
+
+ EXPECT_TRUE(expect_res == res, "wrong result for includes");
+ }
+
+ template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
+ typename std::enable_if<TestUtils::isReverse<InputIterator1>::value, void>::type
+ operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
+ Compare comp)
+ {
+ }
+};
+
+template <typename T1, typename T2, typename Compare>
+void
+test_includes(Compare compare)
+{
+
+ const std::size_t n_max = 1000000;
+
+ // The rand()%(2*n+1) encourages generation of some duplicates.
+ std::srand(42);
+
+ for (std::size_t n = 0; n < n_max; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
+ {
+ for (std::size_t m = 0; m < n_max; m = m <= 16 ? m + 1 : size_t(2.71828 * m))
+ {
+ //prepare the input ranges
+ Sequence<T1> in1(n, [](std::size_t k) { return rand() % (2 * k + 1); });
+ Sequence<T2> in2(m, [](std::size_t k) { return rand() % (k + 1); });
+
+ std::sort(in1.begin(), in1.end(), compare);
+ std::sort(in2.begin(), in2.end(), compare);
+
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.cbegin(), in2.cend(), compare);
+
+ //test w/ non constant predicate
+ if (n < 5 && m < 5)
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.cbegin(), in2.cend(),
+ non_const(compare));
+ }
+ }
+}
+
+int32_t
+main()
+{
+
+ test_includes<float64_t, float64_t>(__pstl::internal::pstl_less());
+ test_includes<Num<int64_t>, Num<int32_t>>([](const Num<int64_t>& x, const Num<int32_t>& y) { return x < y; });
+ std::cout << done() << std::endl;
+
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/alg.set.operations/set.pass.cpp b/pstl/test/std/algorithms/alg.sorting/alg.set.operations/set.pass.cpp
new file mode 100644
index 00000000000..33b7542d4fa
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/alg.set.operations/set.pass.cpp
@@ -0,0 +1,167 @@
+// -*- C++ -*-
+//===-- set.pass.cpp ------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+
+#include <cmath>
+#include <chrono>
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+using namespace TestUtils;
+
+template <typename T>
+struct Num
+{
+ T val;
+
+ Num() : val{} {}
+ Num(const T& v) : val(v) {}
+
+ //for "includes" checks
+ template <typename T1>
+ bool
+ operator<(const Num<T1>& v1) const
+ {
+ return val < v1.val;
+ }
+
+ //The types Type1 and Type2 must be such that an object of type InputIt can be dereferenced and then implicitly converted to both of them
+ template <typename T1>
+ operator Num<T1>() const
+ {
+ return Num<T1>((T1)val);
+ }
+
+ friend bool
+ operator==(const Num& v1, const Num& v2)
+ {
+ return v1.val == v2.val;
+ }
+};
+
+struct test_one_policy
+{
+ template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
+ typename std::enable_if<!TestUtils::isReverse<InputIterator1>::value, void>::type
+ operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
+ Compare comp)
+ {
+ using T1 = typename std::iterator_traits<InputIterator1>::value_type;
+
+ auto n1 = std::distance(first1, last1);
+ auto n2 = std::distance(first2, last2);
+ auto n = n1 + n2;
+ Sequence<T1> expect(n);
+ Sequence<T1> out(n);
+
+ //1. set_union
+ auto expect_res = std::set_union(first1, last1, first2, last2, expect.begin(), comp);
+ auto res = std::set_union(exec, first1, last1, first2, last2, out.begin(), comp);
+
+ EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_union");
+ EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res), "wrong set_union effect");
+
+ //2. set_intersection
+ expect_res = std::set_intersection(first1, last1, first2, last2, expect.begin(), comp);
+ res = std::set_intersection(exec, first1, last1, first2, last2, out.begin(), comp);
+
+ EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_intersection");
+ EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res), "wrong set_intersection effect");
+
+ //3. set_difference
+ expect_res = std::set_difference(first1, last1, first2, last2, expect.begin(), comp);
+ res = std::set_difference(exec, first1, last1, first2, last2, out.begin(), comp);
+
+ EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_difference");
+ EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res), "wrong set_difference effect");
+
+ //4. set_symmetric_difference
+ expect_res = std::set_symmetric_difference(first1, last1, first2, last2, expect.begin(), comp);
+ res = std::set_symmetric_difference(exec, first1, last1, first2, last2, out.begin(), comp);
+
+ EXPECT_TRUE(expect_res - expect.begin() == res - out.begin(), "wrong result for set_symmetric_difference");
+ EXPECT_EQ_N(expect.begin(), out.begin(), std::distance(out.begin(), res),
+ "wrong set_symmetric_difference effect");
+ }
+
+ template <typename Policy, typename InputIterator1, typename InputIterator2, typename Compare>
+ typename std::enable_if<TestUtils::isReverse<InputIterator1>::value, void>::type
+ operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2,
+ Compare comp)
+ {
+ }
+};
+
+template <typename T1, typename T2, typename Compare>
+void
+test_set(Compare compare)
+{
+
+ const std::size_t n_max = 100000;
+
+ // The rand()%(2*n+1) encourages generation of some duplicates.
+ std::srand(4200);
+
+ for (std::size_t n = 0; n < n_max; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
+ {
+ for (std::size_t m = 0; m < n_max; m = m <= 16 ? m + 1 : size_t(2.71828 * m))
+ {
+ //prepare the input ranges
+ Sequence<T1> in1(n, [n](std::size_t k) { return rand() % (2 * k + 1); });
+ Sequence<T2> in2(m, [m](std::size_t k) { return (m % 2) * rand() + rand() % (k + 1); });
+
+ std::sort(in1.begin(), in1.end(), compare);
+ std::sort(in2.begin(), in2.end(), compare);
+
+ invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.cbegin(), in2.cend(), compare);
+ }
+ }
+}
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename InputIterator, typename OutputInterator>
+ void
+ operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
+ {
+ set_difference(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>()));
+
+ set_intersection(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>()));
+
+ set_symmetric_difference(exec, input_iter, input_iter, input_iter, input_iter, out_iter,
+ non_const(std::less<T>()));
+
+ set_union(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>()));
+ }
+};
+
+int32_t
+main()
+{
+
+ test_set<float64_t, float64_t>(__pstl::internal::pstl_less());
+ test_set<Num<int64_t>, Num<int32_t>>([](const Num<int64_t>& x, const Num<int32_t>& y) { return x < y; });
+
+ test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/is_sorted.pass.cpp b/pstl/test/std/algorithms/alg.sorting/is_sorted.pass.cpp
new file mode 100644
index 00000000000..a5219f79669
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/is_sorted.pass.cpp
@@ -0,0 +1,104 @@
+// -*- C++ -*-
+//===-- is_sorted.pass.cpp ------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+using namespace TestUtils;
+
+struct test_is_sorted
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator first, Iterator last, bool exam)
+ {
+ using namespace std;
+ typedef typename std::iterator_traits<Iterator>::value_type T;
+
+ //try random-access iterator
+ bool res = is_sorted(exec, first, last);
+ EXPECT_TRUE(exam == res, "is_sorted wrong result for random-access iterator");
+ auto iexam = is_sorted_until(first, last);
+ auto ires = is_sorted_until(exec, first, last);
+ EXPECT_TRUE(iexam == ires, "is_sorted_until wrong result for random-access iterator");
+
+ //try random-access iterator with a predicate
+ res = is_sorted(exec, first, last, std::less<T>());
+ EXPECT_TRUE(exam == res, "is_sorted wrong result for random-access iterator");
+ iexam = is_sorted_until(first, last, std::less<T>());
+ ires = is_sorted_until(exec, first, last, std::less<T>());
+ EXPECT_TRUE(iexam == ires, "is_sorted_until wrong result for random-access iterator");
+ }
+};
+
+template <typename T>
+void
+test_is_sorted_by_type()
+{
+
+ Sequence<T> in(99999, [](size_t v) -> T { return T(v); }); //fill 0..n
+
+ invoke_on_all_policies(test_is_sorted(), in.begin(), in.end(), std::is_sorted(in.begin(), in.end()));
+ invoke_on_all_policies(test_is_sorted(), in.cbegin(), in.cend(), std::is_sorted(in.begin(), in.end()));
+
+ in[in.size() / 2] = -1;
+ invoke_on_all_policies(test_is_sorted(), in.begin(), in.end(), std::is_sorted(in.begin(), in.end()));
+ invoke_on_all_policies(test_is_sorted(), in.cbegin(), in.cend(), std::is_sorted(in.begin(), in.end()));
+
+ in[1] = -1;
+ invoke_on_all_policies(test_is_sorted(), in.begin(), in.end(), std::is_sorted(in.begin(), in.end()));
+ invoke_on_all_policies(test_is_sorted(), in.cbegin(), in.cend(), std::is_sorted(in.begin(), in.end()));
+
+ //an empty container
+ Sequence<T> in0(0);
+ invoke_on_all_policies(test_is_sorted(), in0.begin(), in0.end(), std::is_sorted(in0.begin(), in0.end()));
+ invoke_on_all_policies(test_is_sorted(), in0.cbegin(), in0.cend(), std::is_sorted(in0.begin(), in0.end()));
+
+ //non-descending order
+ Sequence<T> in1(9, [](size_t v) -> T { return T(0); });
+ invoke_on_all_policies(test_is_sorted(), in1.begin(), in1.end(), std::is_sorted(in1.begin(), in1.end()));
+ invoke_on_all_policies(test_is_sorted(), in1.cbegin(), in1.cend(), std::is_sorted(in1.begin(), in1.end()));
+}
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator iter)
+ {
+ is_sorted(exec, iter, iter, std::less<T>());
+ is_sorted_until(exec, iter, iter, std::less<T>());
+ }
+};
+
+int32_t
+main()
+{
+
+ test_is_sorted_by_type<int32_t>();
+ test_is_sorted_by_type<float64_t>();
+
+ test_is_sorted_by_type<Wrapper<int32_t>>();
+
+ test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/partial_sort.pass.cpp b/pstl/test/std/algorithms/alg.sorting/partial_sort.pass.cpp
new file mode 100644
index 00000000000..6e9d7d21d66
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/partial_sort.pass.cpp
@@ -0,0 +1,156 @@
+// -*- C++ -*-
+//===-- partial_sort.pass.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+
+#include <cmath>
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+using namespace TestUtils;
+
+static std::atomic<int32_t> count_val;
+static std::atomic<int32_t> count_comp;
+
+template <typename T>
+struct Num
+{
+ T val;
+
+ Num() { ++count_val; }
+ Num(T v) : val(v) { ++count_val; }
+ Num(const Num<T>& v) : val(v.val) { ++count_val; }
+ Num(Num<T>&& v) : val(v.val) { ++count_val; }
+ ~Num() { --count_val; }
+ Num<T>&
+ operator=(const Num<T>& v)
+ {
+ val = v.val;
+ return *this;
+ }
+ operator T() const { return val; }
+ bool
+ operator<(const Num<T>& v) const
+ {
+ ++count_comp;
+ return val < v.val;
+ }
+};
+
+struct test_brick_partial_sort
+{
+ template <typename Policy, typename InputIterator, typename Compare>
+ typename std::enable_if<is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
+ void>::type
+ operator()(Policy&& exec, InputIterator first, InputIterator last, InputIterator exp_first, InputIterator exp_last,
+ Compare compare)
+ {
+
+ typedef typename std::iterator_traits<InputIterator>::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 defined(__PSTL_PAR_BACKEND_TBB)
+ 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 Policy, typename InputIterator, typename Compare>
+ typename std::enable_if<!is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
+ void>::type
+ operator()(Policy&& exec, InputIterator first, InputIterator last, InputIterator exp_first, InputIterator exp_last,
+ Compare compare)
+ {
+ }
+};
+
+template <typename T, typename Compare>
+void
+test_partial_sort(Compare compare)
+{
+
+ const std::size_t n_max = 100000;
+ Sequence<T> in(n_max);
+ Sequence<T> 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 <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator iter)
+ {
+ partial_sort(exec, iter, iter, iter, non_const(std::less<T>()));
+ }
+};
+
+int32_t
+main()
+{
+ count_val = 0;
+
+ test_partial_sort<Num<float32_t>>([](Num<float32_t> x, Num<float32_t> y) { return x < y; });
+
+ EXPECT_TRUE(count_val == 0, "cleanup error");
+
+ test_partial_sort<int32_t>(
+ [](int32_t x, int32_t y) { return x > y; }); // Reversed so accidental use of < will be detected.
+
+ test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/partial_sort_copy.pass.cpp b/pstl/test/std/algorithms/alg.sorting/partial_sort_copy.pass.cpp
new file mode 100644
index 00000000000..8f132022c64
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/partial_sort_copy.pass.cpp
@@ -0,0 +1,195 @@
+// -*- C++ -*-
+//===-- partial_sort_copy.pass.cpp ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Tests for partial_sort_copy
+
+#include <cmath>
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+using namespace TestUtils;
+
+template <typename T>
+struct Num
+{
+ T val;
+
+ Num() : val(0) {}
+ Num(T v) : val(v) {}
+ Num(const Num<T>& v) : val(v.val) {}
+ Num(Num<T>&& v) : val(v.val) {}
+ Num<T>&
+ operator=(const Num<T>& v)
+ {
+ val = v.val;
+ return *this;
+ }
+ operator T() const { return val; }
+ bool
+ operator<(const Num<T>& v) const
+ {
+ return val < v.val;
+ }
+};
+
+template <typename RandomAccessIterator>
+struct test_one_policy
+{
+ RandomAccessIterator d_first;
+ RandomAccessIterator d_last;
+ RandomAccessIterator exp_first;
+ RandomAccessIterator exp_last;
+ // This ctor is needed because output shouldn't be transformed to any iterator type (only random access iterators are allowed)
+ test_one_policy(RandomAccessIterator b1, RandomAccessIterator e1, RandomAccessIterator b2, RandomAccessIterator e2)
+ : d_first(b1), d_last(e1), exp_first(b2), exp_last(e2)
+ {
+ }
+#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \
+ __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specialization by policy type, in case of broken configuration
+ template <typename InputIterator, typename Size, typename T, typename Compare>
+ void
+ operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
+ const T& trash, Compare compare)
+ {
+ }
+
+ template <typename InputIterator, typename Size, typename T, typename Compare>
+ void
+ operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
+ const T& trash, Compare compare)
+ {
+ }
+
+ template <typename InputIterator, typename Size, typename T>
+ void
+ operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
+ const T& trash)
+ {
+ }
+
+ template <typename InputIterator, typename Size, typename T>
+ void
+ operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, Size n1, Size n2,
+ const T& trash)
+ {
+ }
+#endif
+
+ template <typename Policy, typename InputIterator, typename Size, typename T, typename Compare>
+ void
+ operator()(Policy&& exec, InputIterator first, InputIterator last, Size n1, Size n2, const T& trash,
+ Compare compare)
+ {
+ prepare_data(first, last, n1, trash);
+ RandomAccessIterator exp = std::partial_sort_copy(first, last, exp_first, exp_last, compare);
+ RandomAccessIterator res = std::partial_sort_copy(exec, first, last, d_first, d_last, compare);
+
+ EXPECT_TRUE((exp - exp_first) == (res - d_first), "wrong result from partial_sort_copy with predicate");
+ EXPECT_EQ_N(exp_first, d_first, n2, "wrong effect from partial_sort_copy with predicate");
+ }
+
+ template <typename Policy, typename InputIterator, typename Size, typename T>
+ void
+ operator()(Policy&& exec, InputIterator first, InputIterator last, Size n1, Size n2, const T& trash)
+ {
+ prepare_data(first, last, n1, trash);
+ RandomAccessIterator exp = std::partial_sort_copy(first, last, exp_first, exp_last);
+ RandomAccessIterator res = std::partial_sort_copy(exec, first, last, d_first, d_last);
+
+ EXPECT_TRUE((exp - exp_first) == (res - d_first), "wrong result from partial_sort_copy without predicate");
+ EXPECT_EQ_N(exp_first, d_first, n2, "wrong effect from partial_sort_copy without predicate");
+ }
+
+ private:
+ template <typename InputIterator, typename Size, typename T>
+ void
+ prepare_data(InputIterator first, InputIterator last, Size n1, const T& trash)
+ {
+ // The rand()%(2*n+1) encourages generation of some duplicates.
+ std::srand(42);
+ std::generate(first, last, [n1]() { return T(rand() % (2 * n1 + 1)); });
+
+ std::fill(exp_first, exp_last, trash);
+ std::fill(d_first, d_last, trash);
+ }
+};
+
+template <typename T, typename Compare>
+void
+test_partial_sort_copy(Compare compare)
+{
+
+ typedef typename Sequence<T>::iterator iterator_type;
+ const std::size_t n_max = 100000;
+ Sequence<T> in(n_max);
+ Sequence<T> out(2 * n_max);
+ Sequence<T> exp(2 * n_max);
+ std::size_t n1 = 0;
+ std::size_t n2;
+ T trash = T(-666);
+ for (; n1 < n_max; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1))
+ {
+ // If both sequences are equal
+ n2 = n1;
+ invoke_on_all_policies(
+ test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2), in.begin(),
+ in.begin() + n1, n1, n2, trash, compare);
+
+ // If first sequence is greater than second
+ n2 = n1 / 3;
+ invoke_on_all_policies(
+ test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2), in.begin(),
+ in.begin() + n1, n1, n2, trash, compare);
+
+ // If first sequence is less than second
+ n2 = 2 * n1;
+ invoke_on_all_policies(
+ test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2), in.begin(),
+ in.begin() + n1, n1, n2, trash, compare);
+ }
+ // Test partial_sort_copy without predicate
+ n1 = n_max;
+ n2 = 2 * n1;
+ invoke_on_all_policies(test_one_policy<iterator_type>(out.begin(), out.begin() + n2, exp.begin(), exp.begin() + n2),
+ in.begin(), in.begin() + n1, n1, n2, trash);
+}
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename InputIterator, typename OutputInterator>
+ void
+ operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter)
+ {
+ invoke_if(exec, [&]() {
+ partial_sort_copy(exec, input_iter, input_iter, out_iter, out_iter, non_const(std::less<T>()));
+ });
+ }
+};
+
+int32_t
+main()
+{
+ test_partial_sort_copy<Num<float32_t>>([](Num<float32_t> x, Num<float32_t> y) { return x < y; });
+ test_partial_sort_copy<int32_t>([](int32_t x, int32_t y) { return x > y; });
+
+ test_algo_basic_double<int32_t>(run_for_rnd<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+ return 0;
+}
diff --git a/pstl/test/std/algorithms/alg.sorting/sort.pass.cpp b/pstl/test/std/algorithms/alg.sorting/sort.pass.cpp
new file mode 100644
index 00000000000..e2eb9cecd2d
--- /dev/null
+++ b/pstl/test/std/algorithms/alg.sorting/sort.pass.cpp
@@ -0,0 +1,251 @@
+// -*- C++ -*-
+//===-- sort.pass.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "support/pstl_test_config.h"
+
+#ifdef PSTL_STANDALONE_TESTS
+
+#include "pstl/execution"
+#include "pstl/algorithm"
+#else
+#include <execution>
+#include <algorithm>
+#endif // PSTL_STANDALONE_TESTS
+
+#include "support/utils.h"
+
+using namespace TestUtils;
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <atomic>
+
+static bool Stable;
+
+//! Number of extant keys
+static std::atomic<int32_t> KeyCount;
+
+//! One more than highest index in array to be sorted.
+static uint32_t LastIndex;
+
+//! Keeping Equal() static and a friend of ParanoidKey class (C++, paragraphs 3.5/7.1.1)
+class ParanoidKey;
+static bool
+Equal(const ParanoidKey& x, const ParanoidKey& y);
+
+//! A key to be sorted, with lots of checking.
+class ParanoidKey
+{
+ //! Value used by comparator
+ int32_t value;
+ //! Original position or special value (Empty or Dead)
+ int32_t index;
+ //! Special value used to mark object without a comparable value, e.g. after being moved from.
+ static const int32_t Empty = -1;
+ //! Special value used to mark destroyed objects.
+ static const int32_t Dead = -2;
+ // True if key object has comparable value
+ bool
+ isLive() const
+ {
+ return (uint32_t)(index) < LastIndex;
+ }
+ // True if key object has been constructed.
+ bool
+ isConstructed() const
+ {
+ return isLive() || index == Empty;
+ }
+
+ public:
+ ParanoidKey()
+ {
+ ++KeyCount;
+ index = Empty;
+ value = Empty;
+ }
+ ParanoidKey(const ParanoidKey& k) : value(k.value), index(k.index)
+ {
+ EXPECT_TRUE(k.isLive(), "source for copy-constructor is dead");
+ ++KeyCount;
+ }
+ ~ParanoidKey()
+ {
+ EXPECT_TRUE(isConstructed(), "double destruction");
+ index = Dead;
+ --KeyCount;
+ }
+ ParanoidKey&
+ operator=(const ParanoidKey& k)
+ {
+ EXPECT_TRUE(k.isLive(), "source for copy-assignment is dead");
+ EXPECT_TRUE(isConstructed(), "destination for copy-assignment is dead");
+ value = k.value;
+ index = k.index;
+ return *this;
+ }
+ ParanoidKey(int32_t index, int32_t value, OddTag) : index(index), value(value) {}
+ ParanoidKey(ParanoidKey&& k) : value(k.value), index(k.index)
+ {
+ EXPECT_TRUE(k.isConstructed(), "source for move-construction is dead");
+// std::stable_sort() fails in move semantics on paranoid test before VS2015
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+ k.index = Empty;
+#endif
+ ++KeyCount;
+ }
+ ParanoidKey&
+ operator=(ParanoidKey&& k)
+ {
+ EXPECT_TRUE(k.isConstructed(), "source for move-assignment is dead");
+ EXPECT_TRUE(isConstructed(), "destination for move-assignment is dead");
+ value = k.value;
+ index = k.index;
+// std::stable_sort() fails in move semantics on paranoid test before VS2015
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+ k.index = Empty;
+#endif
+ return *this;
+ }
+ friend class KeyCompare;
+ friend bool
+ Equal(const ParanoidKey& x, const ParanoidKey& y);
+};
+
+class KeyCompare
+{
+ enum statusType
+ {
+ //! Special value used to mark defined object.
+ Live = 0xabcd,
+ //! Special value used to mark destroyed objects.
+ Dead = -1
+ } status;
+
+ public:
+ KeyCompare(OddTag) : status(Live) {}
+ ~KeyCompare() { status = Dead; }
+ bool
+ operator()(const ParanoidKey& j, const ParanoidKey& k) const
+ {
+ EXPECT_TRUE(status == Live, "key comparison object not defined");
+ EXPECT_TRUE(j.isLive(), "first key to operator() is not live");
+ EXPECT_TRUE(k.isLive(), "second key to operator() is not live");
+ return j.value < k.value;
+ }
+};
+
+// Equal is equality comparison used for checking result of sort against expected result.
+static bool
+Equal(const ParanoidKey& x, const ParanoidKey& y)
+{
+ return (x.value == y.value && !Stable) || (x.index == y.index);
+}
+
+static bool
+Equal(float32_t x, float32_t y)
+{
+ return x == y;
+}
+
+static bool
+Equal(int32_t x, int32_t y)
+{
+ return x == y;
+}
+
+struct test_sort_with_compare
+{
+ template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
+ typename Compare>
+ typename std::enable_if<is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
+ void>::type
+ operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first,
+ OutputIterator2 expected_last, InputIterator first, InputIterator last, Size n, Compare compare)
+ {
+ using namespace std;
+ copy_n(first, n, expected_first);
+ copy_n(first, n, tmp_first);
+ if (Stable)
+ std::stable_sort(expected_first + 1, expected_last - 1, compare);
+ else
+ std::sort(expected_first + 1, expected_last - 1, compare);
+ int32_t count0 = KeyCount;
+ if (Stable)
+ stable_sort(exec, tmp_first + 1, tmp_last - 1, compare);
+ else
+ sort(exec, tmp_first + 1, tmp_last - 1, compare);
+
+ for (size_t i = 0; i < n; ++i, ++expected_first, ++tmp_first)
+ {
+ // Check that expected[i] is equal to tmp[i]
+ EXPECT_TRUE(Equal(*expected_first, *tmp_first), "bad sort");
+ }
+ int32_t count1 = KeyCount;
+ EXPECT_EQ(count0, count1, "key cleanup error");
+ }
+ template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size,
+ typename Compare>
+ typename std::enable_if<!is_same_iterator_category<InputIterator, std::random_access_iterator_tag>::value,
+ void>::type
+ operator()(Policy&& exec, OutputIterator tmp_first, OutputIterator tmp_last, OutputIterator2 expected_first,
+ OutputIterator2 expected_last, InputIterator first, InputIterator last, Size n, Compare compare)
+ {
+ }
+};
+
+template <typename T, typename Compare, typename Convert>
+void
+test_sort(Compare compare, Convert convert)
+{
+ for (size_t n = 0; n < 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n))
+ {
+ LastIndex = n + 2;
+ // The rand()%(2*n+1) encourages generation of some duplicates.
+ // Sequence is padded with an extra element at front and back, to detect overwrite bugs.
+ Sequence<T> in(n + 2, [=](size_t k) { return convert(k, rand() % (2 * n + 1)); });
+ Sequence<T> expected(in);
+ Sequence<T> tmp(in);
+ invoke_on_all_policies(test_sort_with_compare(), tmp.begin(), tmp.end(), expected.begin(), expected.end(),
+ in.begin(), in.end(), in.size(), compare);
+ }
+}
+
+template <typename T>
+struct test_non_const
+{
+ template <typename Policy, typename Iterator>
+ void
+ operator()(Policy&& exec, Iterator iter)
+ {
+ sort(exec, iter, iter, non_const(std::less<T>()));
+ stable_sort(exec, iter, iter, non_const(std::less<T>()));
+ }
+};
+
+int32_t
+main()
+{
+ std::srand(42);
+ for (int32_t kind = 0; kind < 2; ++kind)
+ {
+ Stable = kind != 0;
+ test_sort<ParanoidKey>(KeyCompare(OddTag()),
+ [](size_t k, size_t val) { return ParanoidKey(k, val, OddTag()); });
+ test_sort<float32_t>([](float32_t x, float32_t y) { return x < y; },
+ [](size_t, size_t val) { return float32_t(val); });
+ test_sort<int32_t>(
+ [](int32_t x, int32_t y) { return x > y; }, // Reversed so accidental use of < will be detected.
+ [](size_t, size_t val) { return int32_t(val); });
+ }
+
+ test_algo_basic_single<int32_t>(run_for_rnd<test_non_const<int32_t>>());
+
+ std::cout << done() << std::endl;
+ return 0;
+}
OpenPOWER on IntegriCloud