diff options
author | Louis Dionne <ldionne@apple.com> | 2019-03-27 21:28:24 +0000 |
---|---|---|
committer | Louis Dionne <ldionne@apple.com> | 2019-03-27 21:28:24 +0000 |
commit | 3b62047b8b2209bed57d239f581bdbfc91a10b94 (patch) | |
tree | e321a0dea2d7355c3eca7c9cf9ae1f2b89823c1d /pstl/test/std/algorithms | |
parent | 4bc38cfe297746858a7159bd4a537261d628b47e (diff) | |
download | bcm5719-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')
45 files changed, 6226 insertions, 0 deletions
diff --git a/pstl/test/std/algorithms/alg.merge/inplace_merge.pass.cpp b/pstl/test/std/algorithms/alg.merge/inplace_merge.pass.cpp new file mode 100644 index 00000000000..6e89ab82eff --- /dev/null +++ b/pstl/test/std/algorithms/alg.merge/inplace_merge.pass.cpp @@ -0,0 +1,160 @@ +// -*- C++ -*- +//===-- inplace_merge.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 <algorithm> +#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 +{ +#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 BiDirIt1, typename Size, typename Generator1, typename Generator2, typename Compare> + void + operator()(pstl::execution::unsequenced_policy, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2, BiDirIt1 last2, + Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp) + { + } + + template <typename BiDirIt1, typename Size, typename Generator1, typename Generator2, typename Compare> + void + operator()(pstl::execution::parallel_unsequenced_policy, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2, + BiDirIt1 last2, Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp) + { + } +#endif + + // inplace_merge works with bidirectional iterators at least + template <typename Policy, typename BiDirIt1, typename Size, typename Generator1, typename Generator2, + typename Compare> + typename std::enable_if<!is_same_iterator_category<BiDirIt1, std::forward_iterator_tag>::value, void>::type + operator()(Policy&& exec, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2, BiDirIt1 last2, Size n, Size m, + Generator1 generator1, Generator2 generator2, Compare comp) + { + + using T = typename std::iterator_traits<BiDirIt1>::value_type; + const BiDirIt1 mid1 = std::next(first1, m); + fill_data(first1, mid1, generator1); + fill_data(mid1, last1, generator2); + + const BiDirIt1 mid2 = std::next(first2, m); + fill_data(first2, mid2, generator1); + fill_data(mid2, last2, generator2); + + std::inplace_merge(first1, mid1, last1, comp); + std::inplace_merge(exec, first2, mid2, last2, comp); + EXPECT_EQ_N(first1, first2, n, "wrong effect from inplace_merge with predicate"); + } + + template <typename Policy, typename BiDirIt1, typename Size, typename Generator1, typename Generator2, + typename Compare> + typename std::enable_if<is_same_iterator_category<BiDirIt1, std::forward_iterator_tag>::value, void>::type + operator()(Policy&& exec, BiDirIt1 first1, BiDirIt1 last1, BiDirIt1 first2, BiDirIt1 last2, Size n, Size m, + Generator1 generator1, Generator2 generator2, Compare comp) + { + } +}; + +template <typename T, typename Generator1, typename Generator2, typename Compare> +void +test_by_type(Generator1 generator1, Generator2 generator2, Compare comp) +{ + using namespace std; + size_t max_size = 100000; + Sequence<T> in1(max_size, [](size_t v) { return T(v); }); + Sequence<T> exp(max_size, [](size_t v) { return T(v); }); + size_t m; + + for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + m = 0; + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n, exp.begin(), exp.begin() + n, n, m, + generator1, generator2, comp); + + m = n / 3; + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n, exp.begin(), exp.begin() + n, n, m, + generator1, generator2, comp); + + m = 2 * n / 3; + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n, exp.begin(), exp.begin() + n, n, m, + generator1, generator2, comp); + } +} + +template <typename T> +struct LocalWrapper +{ + explicit LocalWrapper(int32_t k) : my_val(k) {} + LocalWrapper(LocalWrapper&& input) { my_val = std::move(input.my_val); } + LocalWrapper& + operator=(LocalWrapper&& input) + { + my_val = std::move(input.my_val); + return *this; + } + bool + operator<(const LocalWrapper<T>& w) const + { + return my_val < w.my_val; + } + friend bool + operator==(const LocalWrapper<T>& x, const LocalWrapper<T>& y) + { + return x.my_val == y.my_val; + } + friend std::ostream& + operator<<(std::ostream& stream, const LocalWrapper<T>& input) + { + return stream << input.my_val; + } + + private: + T my_val; +}; + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + invoke_if(exec, [&]() { inplace_merge(exec, iter, iter, iter, non_const(std::less<T>())); }); + } +}; + +int32_t +main() +{ + test_by_type<float64_t>([](int32_t i) { return -2 * i; }, [](int32_t i) { return -(2 * i + 1); }, + [](const float64_t x, const float64_t y) { return x > y; }); + + test_by_type<int32_t>([](int32_t i) { return 10 * i; }, [](int32_t i) { return i + 1; }, std::less<int32_t>()); + + test_by_type<LocalWrapper<float32_t>>([](int32_t i) { return LocalWrapper<float32_t>(2 * i + 1); }, + [](int32_t i) { return LocalWrapper<float32_t>(2 * i); }, + std::less<LocalWrapper<float32_t>>()); + + test_algo_basic_single<int32_t>(run_for_rnd_bi<test_non_const<int32_t>>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.merge/merge.pass.cpp b/pstl/test/std/algorithms/alg.merge/merge.pass.cpp new file mode 100644 index 00000000000..a80bbae07f8 --- /dev/null +++ b/pstl/test/std/algorithms/alg.merge/merge.pass.cpp @@ -0,0 +1,119 @@ +// -*- C++ -*- +//===-- merge.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 <algorithm> +#include <functional> +#include "pstl/execution" +#include "pstl/algorithm" + +#else +#include <execution> +#include <algorithm> +#endif // PSTL_STANDALONE_TESTS + +#include "support/utils.h" + +using namespace TestUtils; + +struct test_merge +{ + template <typename Policy, typename InputIterator1, typename InputIterator2, typename OutputIterator, + typename Compare> + void + operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + OutputIterator out_first, OutputIterator out_last, Compare comp) + { + using namespace std; + { + const auto res = merge(exec, first1, last1, first2, last2, out_first, comp); + EXPECT_TRUE(res == out_last, "wrong return result from merge with predicate"); + EXPECT_TRUE(is_sorted(out_first, res, comp), "wrong result from merge with predicate"); + EXPECT_TRUE(includes(out_first, res, first1, last1, comp), "first sequence is not a part of result"); + EXPECT_TRUE(includes(out_first, res, first2, last2, comp), "second sequence is not a part of result"); + } + { + const auto res = merge(exec, first1, last1, first2, last2, out_first); + EXPECT_TRUE(res == out_last, "wrong return result from merge"); + EXPECT_TRUE(is_sorted(out_first, res), "wrong result from merge"); + } + } + + // for reverse iterators + template <typename Policy, typename InputIterator1, typename InputIterator2, typename OutputIterator, + typename Compare> + void + operator()(Policy&& exec, std::reverse_iterator<InputIterator1> first1, std::reverse_iterator<InputIterator1> last1, + std::reverse_iterator<InputIterator2> first2, std::reverse_iterator<InputIterator2> last2, + std::reverse_iterator<OutputIterator> out_first, std::reverse_iterator<OutputIterator> out_last, + Compare comp) + { + using namespace std; + typedef typename std::iterator_traits<std::reverse_iterator<InputIterator1>>::value_type T; + const auto res = merge(exec, first1, last1, first2, last2, out_first, std::greater<T>()); + + EXPECT_TRUE(res == out_last, "wrong return result from merge with predicate"); + EXPECT_TRUE(is_sorted(out_first, res, std::greater<T>()), "wrong result from merge with predicate"); + EXPECT_TRUE(includes(out_first, res, first1, last1, std::greater<T>()), + "first sequence is not a part of result"); + EXPECT_TRUE(includes(out_first, res, first2, last2, std::greater<T>()), + "second sequence is not a part of result"); + } +}; + +template <typename T, typename Generator1, typename Generator2> +void +test_merge_by_type(Generator1 generator1, Generator2 generator2) +{ + using namespace std; + size_t max_size = 100000; + Sequence<T> in1(max_size, generator1); + Sequence<T> in2(max_size / 2, generator2); + Sequence<T> out(in1.size() + in2.size()); + std::sort(in1.begin(), in1.end()); + std::sort(in2.begin(), in2.end()); + + for (size_t size = 0; size <= max_size; size = size <= 16 ? size + 1 : size_t(3.1415 * size)) + { + invoke_on_all_policies(test_merge(), in1.cbegin(), in1.cbegin() + size, in2.data(), in2.data() + size / 2, + out.begin(), out.begin() + 1.5 * size, std::less<T>()); + invoke_on_all_policies(test_merge(), in1.data(), in1.data() + size, in2.cbegin(), in2.cbegin() + size / 2, + out.begin(), out.begin() + 3 * size / 2, std::less<T>()); + } +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename InputIterator, typename OutputIterator> + void + operator()(Policy&& exec, InputIterator input_iter, OutputIterator out_iter) + { + merge(exec, input_iter, input_iter, input_iter, input_iter, out_iter, non_const(std::less<T>())); + } +}; + +int32_t +main() +{ + test_merge_by_type<int32_t>([](size_t v) { return (v % 2 == 0 ? v : -v) * 3; }, [](size_t v) { return v * 2; }); + test_merge_by_type<float64_t>([](size_t v) { return float64_t(v); }, [](size_t v) { return float64_t(v - 100); }); + +#if !__PSTL_ICC_16_17_TEST_64_TIMEOUT + test_merge_by_type<Wrapper<int16_t>>([](size_t v) { return Wrapper<int16_t>(v % 100); }, + [](size_t v) { return Wrapper<int16_t>(v % 10); }); +#endif + + 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.modifying.operations/alg.copy/copy_if.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/alg.copy/copy_if.pass.cpp new file mode 100644 index 00000000000..5e6ea34ed80 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/alg.copy/copy_if.pass.cpp @@ -0,0 +1,150 @@ +// -*- C++ -*- +//===-- copy_if.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 copy_if and remove_copy_if +#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 run_copy_if +{ +#if __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN // dummy specializations to skip testing in case of broken configuration + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename Predicate, typename T> + void + operator()(pstl::execution::parallel_policy, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, + Predicate pred, T trash) + { + } + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename Predicate, typename T> + void + operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, + OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first, + OutputIterator2 expected_last, Size n, Predicate pred, T trash) + { + } +#endif + + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename Predicate, typename T> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, + Predicate pred, T trash) + { + // Cleaning + std::fill_n(expected_first, n, trash); + std::fill_n(out_first, n, trash); + + // Run copy_if + auto i = copy_if(first, last, expected_first, pred); + auto k = copy_if(exec, first, last, out_first, pred); + EXPECT_EQ_N(expected_first, out_first, n, "wrong copy_if effect"); + for (size_t j = 0; j < GuardSize; ++j) + { + ++k; + } + EXPECT_TRUE(out_last == k, "wrong return value from copy_if"); + + // Cleaning + std::fill_n(expected_first, n, trash); + std::fill_n(out_first, n, trash); + // Run remove_copy_if + i = remove_copy_if(first, last, expected_first, [=](const T& x) { return !pred(x); }); + k = remove_copy_if(exec, first, last, out_first, [=](const T& x) { return !pred(x); }); + EXPECT_EQ_N(expected_first, out_first, n, "wrong remove_copy_if effect"); + for (size_t j = 0; j < GuardSize; ++j) + { + ++k; + } + EXPECT_TRUE(out_last == k, "wrong return value from remove_copy_if"); + } +}; + +template <typename T, typename Predicate, typename Convert> +void +test(T trash, Predicate pred, Convert convert, bool check_weakness = true) +{ + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + // count is number of output elements, plus a handful + // more for sake of detecting buffer overruns. + size_t count = GuardSize; + Sequence<T> in(n, [&](size_t k) -> T { + T val = convert(n ^ k); + count += pred(val) ? 1 : 0; + return val; + }); + + Sequence<T> out(count, [=](size_t) { return trash; }); + Sequence<T> expected(count, [=](size_t) { return trash; }); + if (check_weakness) + { + auto expected_result = copy_if(in.cfbegin(), in.cfend(), expected.begin(), pred); + size_t m = expected_result - expected.begin(); + EXPECT_TRUE(n / 4 <= m && m <= 3 * (n + 1) / 4, "weak test for copy_if"); + } + invoke_on_all_policies(run_copy_if(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), + expected.end(), count, pred, trash); + invoke_on_all_policies(run_copy_if(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), + expected.end(), count, pred, trash); + } +} + +struct test_non_const +{ + template <typename Policy, typename InputIterator, typename OutputInterator> + void + operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + copy_if(exec, input_iter, input_iter, out_iter, non_const(is_even)); + + invoke_if(exec, [&]() { remove_copy_if(exec, input_iter, input_iter, out_iter, non_const(is_even)); }); + } +}; + +int32_t +main() +{ + test<float64_t>(-666.0, [](const float64_t& x) { return x * x <= 1024; }, + [](size_t j) { return ((j + 1) % 7 & 2) != 0 ? float64_t(j % 32) : float64_t(j % 33 + 34); }); + + test<int32_t>(-666, [](const int32_t& x) { return x != 42; }, + [](size_t j) { return ((j + 1) % 5 & 2) != 0 ? int32_t(j + 1) : 42; }); + +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN + test<Number>(Number(42, OddTag()), IsMultiple(3, OddTag()), [](int32_t j) { return Number(j, OddTag()); }); +#endif + +#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN + test<int32_t>(-666, [](const int32_t& x) { return true; }, [](size_t j) { return j; }, false); +#endif + + test_algo_basic_double<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/is_partitioned.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/is_partitioned.pass.cpp new file mode 100644 index 00000000000..5d665d25516 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/is_partitioned.pass.cpp @@ -0,0 +1,104 @@ +// -*- C++ -*- +//===-- is_partitioned.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_one_policy +{ + //dummy specialization by policy type, in case of broken configuration +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN + + template <typename Iterator1, typename Predicate> + void + operator()(pstl::execution::unsequenced_policy, Iterator1 begin1, Iterator1 end1, Predicate pred) + { + } + template <typename Iterator1, typename Predicate> + void + operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 begin1, Iterator1 end1, Predicate pred) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator1, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator1 begin1, Iterator1 end1, Predicate pred) + { + const bool expected = std::is_partitioned(begin1, end1, pred); + const bool actual = std::is_partitioned(exec, begin1, end1, pred); + EXPECT_TRUE(actual == expected, "wrong return result from is_partitioned"); + } +}; + +template <typename T, typename Predicate> +void +test(Predicate pred) +{ + + const std::size_t max_n = 1000000; + Sequence<T> in(max_n, [](std::size_t k) { return T(k); }); + + for (std::size_t n1 = 0; n1 <= max_n; n1 = n1 <= 16 ? n1 + 1 : std::size_t(3.1415 * n1)) + { + invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n1, pred); + std::partition(in.begin(), in.begin() + n1, pred); + invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cbegin() + n1, pred); + } +} + +template <typename T> +struct LocalWrapper +{ + explicit LocalWrapper(std::size_t k) : my_val(k) {} + + private: + T my_val; +}; + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + invoke_if(exec, [&]() { is_partitioned(exec, iter, iter, non_const(is_even)); }); + } +}; + +int32_t +main() +{ + test<float64_t>([](const float64_t x) { return x < 0; }); + test<int32_t>([](const int32_t x) { return x > 1000; }); + test<uint16_t>([](const uint16_t x) { return x % 5 < 3; }); +#if !__PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN && !__PSTL_ICC_19_TEST_IS_PARTITIONED_RELEASE_BROKEN + test<LocalWrapper<float64_t>>([](const LocalWrapper<float64_t>& x) { return true; }); +#endif + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp new file mode 100644 index 00000000000..b79a27a44a0 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/partition.pass.cpp @@ -0,0 +1,183 @@ +// -*- C++ -*- +//===-- partition.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 stable_partition and partition +#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 <iterator> +#include <type_traits> + +using namespace TestUtils; + +template <typename T> +struct DataType +{ + explicit DataType(int32_t k) : my_val(k) {} + DataType(DataType&& input) { my_val = std::move(input.my_val); } + DataType& + operator=(DataType&& input) + { + my_val = std::move(input.my_val); + return *this; + } + T + get_val() const + { + return my_val; + } + + friend std::ostream& + operator<<(std::ostream& stream, const DataType<T>& input) + { + return stream << input.my_val; + } + + private: + T my_val; +}; + +template <typename Iterator> +typename std::enable_if<std::is_trivial<typename std::iterator_traits<Iterator>::value_type>::value, bool>::type +is_equal(Iterator first, Iterator last, Iterator d_first) +{ + return std::equal(first, last, d_first); +} + +template <typename Iterator> +typename std::enable_if<!std::is_trivial<typename std::iterator_traits<Iterator>::value_type>::value, bool>::type +is_equal(Iterator first, Iterator last, Iterator d_first) +{ + return true; +} + +struct test_one_policy +{ +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \ + __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN //dummy specializations to skip testing in case of broken configuration + template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator> + void + operator()(pstl::execution::unsequenced_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last, + Size n, UnaryOp unary_op, Generator generator) + { + } + + template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator> + void + operator()(pstl::execution::parallel_unsequenced_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first, + BiDirIt exp_last, Size n, UnaryOp unary_op, Generator generator) + { + } +#elif __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN //dummy specializations to skip testing in case of broken configuration + template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator> + void + operator()(pstl::execution::parallel_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last, + Size n, UnaryOp unary_op, Generator generator) + { + } + + template <typename BiDirIt, typename Size, typename UnaryOp, typename Generator> + void + operator()(pstl::execution::parallel_unsequenced_policy, BiDirIt first, BiDirIt last, BiDirIt exp_first, + BiDirIt exp_last, Size n, UnaryOp unary_op, Generator generator) + { + } +#endif + + template <typename Policy, typename BiDirIt, typename Size, typename UnaryOp, typename Generator> + typename std::enable_if<!is_same_iterator_category<BiDirIt, std::forward_iterator_tag>::value, void>::type + operator()(Policy&& exec, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last, Size n, + UnaryOp unary_op, Generator generator) + { + // partition + { + fill_data(first, last, generator); + BiDirIt actual_ret = std::partition(exec, first, last, unary_op); + EXPECT_TRUE(std::all_of(first, actual_ret, unary_op) && !std::any_of(actual_ret, last, unary_op), + "wrong effect from partition"); + } + // stable_partition + { + fill_data(exp_first, exp_last, generator); + BiDirIt exp_ret = std::stable_partition(exp_first, exp_last, unary_op); + fill_data(first, last, generator); + BiDirIt actual_ret = std::stable_partition(exec, first, last, unary_op); + + EXPECT_TRUE(std::distance(first, actual_ret) == std::distance(exp_first, exp_ret), + "wrong result from stable_partition"); + EXPECT_TRUE((is_equal<BiDirIt>(exp_first, exp_last, first)), "wrong effect from stable_partition"); + } + } + template <typename Policy, typename BiDirIt, typename Size, typename UnaryOp, typename Generator> + typename std::enable_if<is_same_iterator_category<BiDirIt, std::forward_iterator_tag>::value, void>::type + operator()(Policy&& exec, BiDirIt first, BiDirIt last, BiDirIt exp_first, BiDirIt exp_last, Size n, + UnaryOp unary_op, Generator generator) + { + } +}; + +template <typename T, typename Generator, typename UnaryPred> +void +test_by_type(Generator generator, UnaryPred pred) +{ + + using namespace std; + size_t max_size = 100000; + Sequence<T> in(max_size, [](size_t v) { return T(v); }); + Sequence<T> exp(max_size, [](size_t v) { return T(v); }); + + for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n, exp.begin(), exp.begin() + n, n, pred, + generator); + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + invoke_if(exec, [&]() { + partition(exec, iter, iter, non_const(is_even)); + stable_partition(exec, iter, iter, non_const(is_even)); + }); + } +}; + +int32_t +main() +{ +#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN + test_by_type<int32_t>([](int32_t i) { return i; }, [](int32_t) { return true; }); +#endif + test_by_type<float64_t>([](int32_t i) { return -i; }, [](const float64_t x) { return x < 0; }); + test_by_type<int64_t>([](int32_t i) { return i + 1; }, [](int64_t x) { return x % 3 == 0; }); + test_by_type<DataType<float32_t>>([](int32_t i) { return DataType<float32_t>(2 * i + 1); }, + [](const DataType<float32_t>& x) { return x.get_val() < 0; }); + + test_algo_basic_single<int32_t>(run_for_rnd_bi<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/partition_copy.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/partition_copy.pass.cpp new file mode 100644 index 00000000000..c27e51ca798 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/alg.partitions/partition_copy.pass.cpp @@ -0,0 +1,120 @@ +// -*- C++ -*- +//===-- partition_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 stable_partition and partition_copy +#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 <cstdlib> +#include <iterator> + +using namespace TestUtils; + +struct test_partition_copy +{ + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, + typename UnaryOp> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator true_first, + OutputIterator true_last, OutputIterator2 false_first, OutputIterator2 false_last, UnaryOp unary_op) + { + + auto actual_ret = std::partition_copy(exec, first, last, true_first, false_first, unary_op); + + EXPECT_TRUE(std::distance(true_first, actual_ret.first) == std::count_if(first, last, unary_op), + "partition_copy has wrong effect from true sequence"); + EXPECT_TRUE(std::distance(false_first, actual_ret.second) == + std::count_if(first, last, __pstl::internal::not_pred<UnaryOp>(unary_op)), + "partition_copy has wrong effect from false sequence"); + } + + //dummy specialization by iterator type and policy type, in case of broken configuration +#if __PSTL_ICC_1800_TEST_MONOTONIC_RELEASE_64_BROKEN + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename UnaryOp> + void + operator()(pstl::execution::unsequenced_policy, std::reverse_iterator<InputIterator> first, + std::reverse_iterator<InputIterator> last, std::reverse_iterator<OutputIterator> true_first, + std::reverse_iterator<OutputIterator> true_last, std::reverse_iterator<OutputIterator2> false_first, + OutputIterator2 false_last, UnaryOp unary_op) + { + } + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename UnaryOp> + void + operator()(pstl::execution::parallel_unsequenced_policy, std::reverse_iterator<InputIterator> first, + std::reverse_iterator<InputIterator> last, std::reverse_iterator<OutputIterator> true_first, + std::reverse_iterator<OutputIterator> true_last, std::reverse_iterator<OutputIterator2> false_first, + OutputIterator2 false_last, UnaryOp unary_op) + { + } +#endif +}; + +template <typename T, typename UnaryPred> +void +test(UnaryPred pred) +{ + + const std::size_t max_size = 100000; + Sequence<T> in(max_size, [](std::size_t v) -> T { return T(v); }); + Sequence<T> actual_true(max_size); + Sequence<T> actual_false(max_size); + for (std::size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : std::size_t(3.1415 * n)) + { + + // for non-const input iterators + invoke_on_all_policies(test_partition_copy(), in.begin(), in.begin() + n, actual_true.begin(), + actual_true.begin() + n, actual_false.begin(), actual_false.begin() + n, pred); + + // for const input iterators + invoke_on_all_policies(test_partition_copy(), in.cbegin(), in.cbegin() + n, actual_true.begin(), + actual_true.begin() + n, actual_false.begin(), actual_false.begin() + n, pred); + } +} + +struct test_non_const +{ + template <typename Policy, typename InputIterator, typename OutputInterator> + void + operator()(Policy&& exec, InputIterator input_iter, OutputInterator out_iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + + partition_copy(exec, input_iter, input_iter, out_iter, out_iter, non_const(is_even)); + } +}; + +int32_t +main() +{ + test<int32_t>([](const int32_t value) { return value % 2; }); + +#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN + test<int32_t>([](const int32_t value) { return true; }); +#endif + + test<float64_t>([](const float64_t value) { return value > 2 << 6; }); + test<Wrapper<float64_t>>([](const Wrapper<float64_t>& value) -> bool { return value.get_my_field() != nullptr; }); + + test_algo_basic_double<int32_t>(run_for_rnd_bi<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/alg.reverse/reverse.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/alg.reverse/reverse.pass.cpp new file mode 100644 index 00000000000..ad722df3a83 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/alg.reverse/reverse.pass.cpp @@ -0,0 +1,108 @@ +// -*- C++ -*- +//===-- reverse.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 <iterator> + +#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 +{ +#if __PSTL_ICC_18_VC141_TEST_SIMD_LAMBDA_RELEASE_BROKEN || __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 Iterator1, typename Iterator2> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, + Iterator2 actual_e) + { + } + template <typename Iterator1, typename Iterator2> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, + Iterator2 actual_e) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2> + typename std::enable_if<!is_same_iterator_category<Iterator1, std::forward_iterator_tag>::value>::type + operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e) + { + using namespace std; + + copy(data_b, data_e, actual_b); + + reverse(exec, actual_b, actual_e); + + bool check = equal(data_b, data_e, reverse_iterator<Iterator2>(actual_e)); + + EXPECT_TRUE(check, "wrong result of reverse"); + } + + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2> + typename std::enable_if<is_same_iterator_category<Iterator1, std::forward_iterator_tag>::value>::type + operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e) + { + } +}; + +template <typename T> +void +test() +{ + const std::size_t max_len = 100000; + + Sequence<T> actual(max_len); + + Sequence<T> data(max_len, [](std::size_t i) { return T(i); }); + + for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len)) + { + invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(), + actual.begin() + len); + } +} + +template <typename T> +struct wrapper +{ + T t; + wrapper() {} + explicit wrapper(T t_) : t(t_) {} + bool + operator==(const wrapper<T>& a) const + { + return t == a.t; + } +}; + +int32_t +main() +{ + test<int32_t>(); + test<uint16_t>(); + test<float64_t>(); +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN + test<wrapper<float64_t>>(); +#endif + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/alg.reverse/reverse_copy.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/alg.reverse/reverse_copy.pass.cpp new file mode 100644 index 00000000000..d26f41f175d --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/alg.reverse/reverse_copy.pass.cpp @@ -0,0 +1,137 @@ +// -*- C++ -*- +//===-- reverse_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 +// +//===----------------------------------------------------------------------===// + +#include "support/pstl_test_config.h" + +#ifdef PSTL_STANDALONE_TESTS +#include <iterator> + +#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 wrapper +{ + T t; + wrapper() {} + explicit wrapper(T t_) : t(t_) {} + wrapper& + operator=(const T& t_) + { + t = t_; + return *this; + } + bool + operator==(const wrapper& t_) const + { + return t == t_.t; + } +}; + +template <typename T1, typename T2> +bool +eq(const wrapper<T1>& a, const wrapper<T2>& b) +{ + return a.t == b.t; +} + +template <typename T1, typename T2> +bool +eq(const T1& a, const T2& b) +{ + return a == b; +} + +// we need to save state here, because we need to test with different types of iterators +// due to the caller invoke_on_all_policies does forcing modification passed iterator type to cover additional usage cases. +template <typename Iterator> +struct test_one_policy +{ + Iterator data_b; + Iterator data_e; + test_one_policy(Iterator b, Iterator e) : data_b(b), data_e(e) {} + +#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 Iterator1> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::unsequenced_policy, Iterator1 actual_b, Iterator1 actual_e) + { + } + template <typename Iterator1> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 actual_b, Iterator1 actual_e) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator1> + void + operator()(ExecutionPolicy&& exec, Iterator1 actual_b, Iterator1 actual_e) + { + using namespace std; + using T = typename iterator_traits<Iterator1>::value_type; + using DifferenceType = typename iterator_traits<Iterator1>::difference_type; + + fill(actual_b, actual_e, T(-123)); + Iterator1 actual_return = reverse_copy(exec, data_b, data_e, actual_b); + + EXPECT_TRUE(actual_return == actual_e, "wrong result of reverse_copy"); + + const auto n = std::distance(data_b, data_e); + Sequence<T> res(n); + std::copy(std::reverse_iterator<Iterator>(data_e), std::reverse_iterator<Iterator>(data_b), res.begin()); + + EXPECT_EQ_N(res.begin(), actual_b, n, "wrong effect of reverse_copy"); + } +}; + +template <typename T1, typename T2> +void +test() +{ + typedef typename Sequence<T1>::iterator iterator_type; + typedef typename Sequence<T1>::const_bidirectional_iterator cbi_iterator_type; + + const std::size_t max_len = 100000; + + Sequence<T2> actual(max_len); + + Sequence<T1> data(max_len, [](std::size_t i) { return T1(i); }); + + for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len)) + { + invoke_on_all_policies(test_one_policy<iterator_type>(data.begin(), data.begin() + len), actual.begin(), + actual.begin() + len); + invoke_on_all_policies(test_one_policy<cbi_iterator_type>(data.cbibegin(), std::next(data.cbibegin(), len)), + actual.begin(), actual.begin() + len); + } +} + +int32_t +main() +{ + // clang-3.8 fails to correctly auto vectorize the loop in some cases of different types of container's elements, + // for example: int32_t and int8_t. This issue isn't detected for clang-3.9 and newer versions. + test<int16_t, int8_t>(); + test<uint16_t, float32_t>(); + test<float64_t, int64_t>(); + test<wrapper<float64_t>, wrapper<float64_t>>(); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/copy_move.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/copy_move.pass.cpp new file mode 100644 index 00000000000..89de3f92c9e --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/copy_move.pass.cpp @@ -0,0 +1,204 @@ +// -*- C++ -*- +//===-- copy_move.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 copy, move and copy_n + +#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 run_copy +{ + +#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 OutputIterator, typename OutputIterator2, typename Size, typename T> + void + operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, + Size n, T trash) + { + } + + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, typename T> + void + operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, + OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first, + OutputIterator2 expected_last, Size size, Size n, T trash) + { + } +#endif + + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename T> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, + Size n, T trash) + { + // Cleaning + std::fill_n(expected_first, size, trash); + std::fill_n(out_first, size, trash); + + // Run copy + copy(first, last, expected_first); + auto k = copy(exec, first, last, out_first); + for (size_t j = 0; j < GuardSize; ++j) + ++k; + EXPECT_EQ_N(expected_first, out_first, size, "wrong effect from copy"); + EXPECT_TRUE(out_last == k, "wrong return value from copy"); + + // Cleaning + std::fill_n(out_first, size, trash); + // Run copy_n + k = copy_n(exec, first, n, out_first); + for (size_t j = 0; j < GuardSize; ++j) + ++k; + EXPECT_EQ_N(expected_first, out_first, size, "wrong effect from copy_n"); + EXPECT_TRUE(out_last == k, "wrong return value from copy_n"); + } +}; + +template <typename T> +struct run_move +{ + +#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 OutputIterator, typename OutputIterator2, typename Size> + void + operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, + Size n, T trash) + { + } + + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size> + void + operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, + OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first, + OutputIterator2 expected_last, Size size, Size n, T trash) + { + } +#endif + + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, + Size n, T trash) + { + // Cleaning + std::fill_n(expected_first, size, trash); + std::fill_n(out_first, size, trash); + + // Run move + move(first, last, expected_first); + auto k = move(exec, first, last, out_first); + for (size_t j = 0; j < GuardSize; ++j) + ++k; + EXPECT_EQ_N(expected_first, out_first, size, "wrong effect from move"); + EXPECT_TRUE(out_last == k, "wrong return value from move"); + } +}; + +template <typename T> +struct run_move<Wrapper<T>> +{ + +#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 OutputIterator, typename OutputIterator2, typename Size> + void + operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, + Size n, Wrapper<T> trash) + { + } + + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size> + void + operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, + OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first, + OutputIterator2 expected_last, Size size, Size n, Wrapper<T> trash) + { + } +#endif + + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size size, + Size n, Wrapper<T> trash) + { + // Cleaning + std::fill_n(out_first, size, trash); + Wrapper<T>::SetMoveCount(0); + + // Run move + auto k = move(exec, first, last, out_first); + for (size_t j = 0; j < GuardSize; ++j) + ++k; + EXPECT_TRUE(Wrapper<T>::MoveCount() == size, "wrong effect from move"); + EXPECT_TRUE(out_last == k, "wrong return value from move"); + } +}; + +template <typename T, typename Convert> +void +test(T trash, Convert convert) +{ + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + // count is number of output elements, plus a handful + // more for sake of detecting buffer overruns. + Sequence<T> in(n, [&](size_t k) -> T { + T val = convert(n ^ k); + return val; + }); + + const size_t outN = n + GuardSize; + Sequence<T> out(outN, [=](size_t) { return trash; }); + Sequence<T> expected(outN, [=](size_t) { return trash; }); + invoke_on_all_policies(run_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), + expected.end(), outN, n, trash); + invoke_on_all_policies(run_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), + expected.end(), outN, n, trash); + invoke_on_all_policies(run_move<T>(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), + expected.end(), n, n, trash); + + // For this test const iterator isn't suitable + // because const rvalue-reference call copy assignment operator + } +} + +int32_t +main() +{ + test<int32_t>(-666, [](size_t j) { return int32_t(j); }); + test<Wrapper<float64_t>>(Wrapper<float64_t>(-666.0), [](int32_t j) { return Wrapper<float64_t>(j); }); + +#if !__PSTL_ICC_16_17_TEST_64_TIMEOUT + test<float64_t>(-666.0, [](size_t j) { return float64_t(j); }); + test<Number>(Number(42, OddTag()), [](int32_t j) { return Number(j, OddTag()); }); +#endif + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/fill.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/fill.pass.cpp new file mode 100644 index 00000000000..19bc150b31b --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/fill.pass.cpp @@ -0,0 +1,104 @@ +// -*- C++ -*- +//===-- fill.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_fill +{ + template <typename It, typename T> + bool + check(It first, It last, const T& value) + { + for (; first != last; ++first) + if (*first != value) + return false; + return true; + } + + template <typename Policy, typename Iterator, typename T> + void + operator()(Policy&& exec, Iterator first, Iterator last, const T& value) + { + fill(first, last, T(value + 1)); // initialize memory with different value + + fill(exec, first, last, value); + EXPECT_TRUE(check(first, last, value), "fill wrong result"); + } +}; + +struct test_fill_n +{ + template <typename It, typename Size, typename T> + bool + check(It first, Size n, const T& value) + { + for (Size i = 0; i < n; ++i, ++first) + if (*first != value) + return false; + return true; + } + + template <typename Policy, typename Iterator, typename Size, typename T> + void + operator()(Policy&& exec, Iterator first, Size n, const T& value) + { + fill_n(first, n, T(value + 1)); // initialize memory with different value + + const Iterator one_past_last = fill_n(exec, first, n, value); + const Iterator expected_return = std::next(first, n); + + EXPECT_TRUE(expected_return == one_past_last, "fill_n should return Iterator to one past the element assigned"); + EXPECT_TRUE(check(first, n, value), "fill_n wrong result"); + + //n == -1 + const Iterator res = fill_n(exec, first, -1, value); + EXPECT_TRUE(res == first, "fill_n wrong result for n == -1"); + } +}; + +template <typename T> +void +test_fill_by_type(std::size_t n) +{ + Sequence<T> in(n, [](std::size_t v) -> T { return T(0); }); //fill with zeros + T value = -1; + + invoke_on_all_policies(test_fill(), in.begin(), in.end(), value); + invoke_on_all_policies(test_fill_n(), in.begin(), n, value); +} + +int32_t +main() +{ + + const std::size_t N = 100000; + + for (std::size_t n = 0; n < N; n = n < 16 ? n + 1 : size_t(3.1415 * n)) + { + test_fill_by_type<int32_t>(n); + test_fill_by_type<float64_t>(n); + } + + std::cout << done() << std::endl; + + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/generate.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/generate.pass.cpp new file mode 100644 index 00000000000..9862f14ba62 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/generate.pass.cpp @@ -0,0 +1,107 @@ +// -*- C++ -*- +//===-- generate.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 <atomic> + +#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 Generator_count +{ + const T def_val = T(-1); + T + operator()() + { + return def_val; + } + T + default_value() const + { + return def_val; + } +}; + +struct test_generate +{ + template <typename Policy, typename Iterator, typename Size> + void + operator()(Policy&& exec, Iterator first, Iterator last, Size n) + { + using namespace std; + typedef typename std::iterator_traits<Iterator>::value_type T; + + // Try random-access iterator + { + Generator_count<T> g; + generate(exec, first, last, g); + EXPECT_TRUE(std::count(first, last, g.default_value()) == n, "generate wrong result for generate"); + std::fill(first, last, T(0)); + } + + { + Generator_count<T> g; + const auto m = n / 2; + auto last = generate_n(exec, first, m, g); + EXPECT_TRUE(std::count(first, last, g.default_value()) == m && last == std::next(first, m), + "generate_n wrong result for generate_n"); + std::fill(first, last, T(0)); + } + } +}; + +template <typename T> +void +test_generate_by_type() +{ + for (size_t n = 0; n <= 100000; n = n < 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<T> in(n, [](size_t v) -> T { return T(0); }); //fill by zero + + invoke_on_all_policies(test_generate(), in.begin(), in.end(), in.size()); + } +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto gen = []() { return T(0); }; + + generate(exec, iter, iter, non_const(gen)); + generate_n(exec, iter, 0, non_const(gen)); + } +}; + +int32_t +main() +{ + + test_generate_by_type<int32_t>(); + test_generate_by_type<float64_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.modifying.operations/remove.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/remove.pass.cpp new file mode 100644 index 00000000000..82b986bcfbf --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/remove.pass.cpp @@ -0,0 +1,157 @@ +// -*- C++ -*- +//===-- remove.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 +// +//===----------------------------------------------------------------------===// + +// Test for remove, remove_if +#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 run_remove +{ +#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 OutputIterator, typename Size, typename T> + void + operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n, + const T& value) + { + } + template <typename InputIterator, typename OutputIterator, typename Size, typename T> + void + operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, + OutputIterator out_first, OutputIterator out_last, OutputIterator expected_first, + OutputIterator expected_last, Size n, const T& value) + { + } +#endif + + template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename T> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size, + const T& value) + { + // Cleaning + std::copy(first, last, expected_first); + std::copy(first, last, out_first); + + // Run remove + OutputIterator i = remove(expected_first, expected_last, value); + OutputIterator k = remove(exec, out_first, out_last, value); + EXPECT_TRUE(std::distance(expected_first, i) == std::distance(out_first, k), "wrong return value from remove"); + EXPECT_EQ_N(expected_first, out_first, std::distance(expected_first, i), "wrong remove effect"); + } +}; + +struct run_remove_if +{ +#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 OutputIterator, typename Size, typename Predicate> + void + operator()(pstl::execution::unsequenced_policy, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n, + Predicate pred) + { + } + template <typename InputIterator, typename OutputIterator, typename Size, typename Predicate> + void + operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, + OutputIterator out_first, OutputIterator out_last, OutputIterator expected_first, + OutputIterator expected_last, Size n, Predicate pred) + { + } +#endif + + template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename Predicate> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size, + Predicate pred) + { + // Cleaning + std::copy(first, last, expected_first); + std::copy(first, last, out_first); + + // Run remove_if + OutputIterator i = remove_if(expected_first, expected_last, pred); + OutputIterator k = remove_if(exec, out_first, out_last, pred); + EXPECT_TRUE(std::distance(expected_first, i) == std::distance(out_first, k), + "wrong return value from remove_if"); + EXPECT_EQ_N(expected_first, out_first, std::distance(expected_first, i), "wrong remove_if effect"); + } +}; + +template <typename T, typename Predicate, typename Convert> +void +test(T trash, const T& value, Predicate pred, Convert convert) +{ + const std::size_t max_size = 100000; + Sequence<T> out(max_size, [trash](size_t) { return trash; }); + Sequence<T> expected(max_size, [trash](size_t) { return trash; }); + + for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<T> data(n, [&](size_t k) -> T { return convert(k); }); + + invoke_on_all_policies(run_remove(), data.begin(), data.end(), out.begin(), out.begin() + n, expected.begin(), + expected.begin() + n, n, value); + invoke_on_all_policies(run_remove_if(), data.begin(), data.end(), out.begin(), out.begin() + n, + expected.begin(), expected.begin() + n, n, pred); + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + + invoke_if(exec, [&]() { remove_if(exec, iter, iter, non_const(is_even)); }); + } +}; + +int32_t +main() +{ +#if !__PSTL_ICC_18_TEST_EARLY_EXIT_MONOTONIC_RELEASE_BROKEN + test<int32_t>(666, 42, [](int32_t val) { return true; }, [](size_t j) { return j; }); +#endif + + test<int32_t>(666, 2001, [](const int32_t& val) { return val != 2001; }, + [](size_t j) { return ((j + 1) % 5 & 2) != 0 ? 2001 : -1 - int32_t(j); }); + test<float64_t>(-666.0, 8.5, [](const float64_t& val) { return val != 8.5; }, + [](size_t j) { return ((j + 1) % 7 & 2) != 0 ? 8.5 : float64_t(j % 32 + j); }); + +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN + test<Number>(Number(-666, OddTag()), Number(42, OddTag()), IsMultiple(3, OddTag()), + [](int32_t j) { return Number(j, OddTag()); }); +#endif + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/remove_copy.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/remove_copy.pass.cpp new file mode 100644 index 00000000000..0437292af4f --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/remove_copy.pass.cpp @@ -0,0 +1,94 @@ +// -*- C++ -*- +//===-- remove_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 +// +//===----------------------------------------------------------------------===// + +#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 run_remove_copy +{ + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename T> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, + const T& value, T trash) + { + // Cleaning + std::fill_n(expected_first, n, trash); + std::fill_n(out_first, n, trash); + + // Run copy_if + auto i = remove_copy(first, last, expected_first, value); + auto k = remove_copy(exec, first, last, out_first, value); + EXPECT_EQ_N(expected_first, out_first, n, "wrong remove_copy effect"); + for (size_t j = 0; j < GuardSize; ++j) + { + ++k; + } + EXPECT_TRUE(out_last == k, "wrong return value from remove_copy"); + } +}; + +template <typename T, typename Convert> +void +test(T trash, const T& value, Convert convert, bool check_weakness = true) +{ + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + // count is number of output elements, plus a handful + // more for sake of detecting buffer overruns. + size_t count = GuardSize; + Sequence<T> in(n, [&](size_t k) -> T { + T x = convert(n ^ k); + count += !(x == value) ? 1 : 0; + return x; + }); + using namespace std; + + Sequence<T> out(count, [=](size_t) { return trash; }); + Sequence<T> expected(count, [=](size_t) { return trash; }); + if (check_weakness) + { + auto expected_result = remove_copy(in.cfbegin(), in.cfend(), expected.begin(), value); + size_t m = expected_result - expected.begin(); + EXPECT_TRUE(n / 4 <= m && m <= 3 * (n + 1) / 4, "weak test for remove_copy"); + } + invoke_on_all_policies(run_remove_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), + expected.end(), count, value, trash); + invoke_on_all_policies(run_remove_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), + expected.end(), count, value, trash); + } +} + +int32_t +main() +{ + + test<float64_t>(-666.0, 8.5, [](size_t j) { return ((j + 1) % 7 & 2) != 0 ? 8.5 : float64_t(j % 32 + j); }); + + test<int32_t>(-666, 42, [](size_t j) { return ((j + 1) % 5 & 2) != 0 ? 42 : -1 - int32_t(j); }); + + test<Number>(Number(42, OddTag()), Number(2001, OddTag()), + [](int32_t j) { return ((j + 1) % 3 & 2) != 0 ? Number(2001, OddTag()) : Number(j, OddTag()); }); + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/replace.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/replace.pass.cpp new file mode 100644 index 00000000000..5aeaac88812 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/replace.pass.cpp @@ -0,0 +1,163 @@ +// -*- C++ -*- +//===-- replace.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; + +// This class is needed to check the self-copying +struct copy_int +{ + int32_t value; + int32_t copied_times = 0; + explicit copy_int(int32_t val = 0) { value = val; } + + copy_int& + operator=(const copy_int& other) + { + if (&other == this) + copied_times++; + else + { + value = other.value; + copied_times = other.copied_times; + } + return *this; + } + + bool + operator==(const copy_int& other) const + { + return (value == other.value); + } +}; + +template <typename Iterator> +struct test_one_policy +{ + std::size_t len; + Iterator data_b; + Iterator data_e; + test_one_policy(Iterator data_, std::size_t len_) + { + len = len_; + data_b = data_; + data_e = std::next(data_b, len); + } + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename T, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator1 expected_b, Iterator1 expected_e, Iterator2 actual_b, + Iterator2 actual_e, Predicate pred, const T& value, const T& old_value) + { + using namespace std; + + copy(data_b, data_e, expected_b); + copy(data_b, data_e, actual_b); + + replace(expected_b, expected_e, old_value, value); + replace(exec, actual_b, actual_e, old_value, value); + + EXPECT_TRUE((check<T, Iterator2>(actual_b, actual_e)), "wrong result of self assignment check"); + EXPECT_TRUE(equal(expected_b, expected_e, actual_b), "wrong result of replace"); + + copy(data_b, data_e, expected_b); + copy(data_b, data_e, actual_b); + + replace_if(expected_b, expected_e, pred, value); + replace_if(exec, actual_b, actual_e, pred, value); + EXPECT_TRUE(equal(expected_b, expected_e, actual_b), "wrong result of replace_if"); + } + + template <typename T, typename Iterator1> + bool + check(Iterator1 b, Iterator1 e) + { + return true; + } + + template <typename T, typename Iterator1> + typename std::enable_if<std::is_same<T, copy_int>::value, bool>::type_t + check(Iterator1 b, Iterator1 e) + { + return std::all_of(b, e, [](const copy_int& elem) { return elem.copied_times == 0; }); + } +}; + +template <typename T1, typename T2, typename Pred> +void +test(Pred pred) +{ + typedef typename Sequence<T2>::iterator iterator_type; + + const std::size_t max_len = 100000; + + const T1 value = T1(0); + const T1 new_value = T1(666); + + Sequence<T2> expected(max_len); + Sequence<T2> actual(max_len); + + Sequence<T2> data(max_len, [&value](std::size_t i) { + if (i % 3 == 2) + { + return T1(i); + } + else + { + return value; + } + }); + + for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len)) + { + test_one_policy<iterator_type> temp(data.begin(), len); + + invoke_on_all_policies(temp, expected.begin(), expected.begin() + len, actual.begin(), actual.begin() + len, + pred, new_value, value); + } +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + invoke_if(exec, [&]() { replace_if(exec, iter, iter, non_const(is_even), T(0)); }); + } +}; + +int32_t +main() +{ + test<int32_t, float32_t>(__pstl::internal::equal_value<int32_t>(666)); + test<uint16_t, uint8_t>([](const uint16_t& elem) { return elem % 3 < 2; }); + test<float64_t, int64_t>([](const float64_t& elem) { return elem * elem - 3.5 * elem > 10; }); + test<copy_int, copy_int>([](const copy_int& val) { return val.value / 5 > 2; }); + + 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.modifying.operations/replace_copy.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/replace_copy.pass.cpp new file mode 100644 index 00000000000..7ebbf4c0c7f --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/replace_copy.pass.cpp @@ -0,0 +1,108 @@ +// -*- C++ -*- +//===-- replace_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 replace_copy and replace_copy_if + +#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_replace_copy +{ + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename Predicate, typename T> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, + Predicate pred, const T& old_value, const T& new_value, T trash) + { + // Cleaning + std::fill_n(expected_first, n, trash); + std::fill_n(out_first, n, trash); + // Run replace_copy + auto i = std::replace_copy(first, last, expected_first, old_value, new_value); + auto k = std::replace_copy(exec, first, last, out_first, old_value, new_value); + EXPECT_EQ_N(expected_first, out_first, n, "wrong replace_copy effect"); + EXPECT_TRUE(out_last == k, "wrong return value from replace_copy"); + + // Cleaning + std::fill_n(expected_first, n, trash); + std::fill_n(out_first, n, trash); + // Run replace_copy_if + i = replace_copy_if(first, last, expected_first, pred, new_value); + k = replace_copy_if(exec, first, last, out_first, pred, new_value); + EXPECT_EQ_N(expected_first, out_first, n, "wrong replace_copy_if effect"); + EXPECT_TRUE(out_last == k, "wrong return value from replace_copy_if"); + } +}; + +template <typename T, typename Convert, typename Predicate> +void +test(T trash, const T& old_value, const T& new_value, Predicate pred, Convert convert) +{ + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<T> in(n, [&](size_t k) -> T { return convert(n ^ k); }); + Sequence<T> out(n, [=](size_t) { return trash; }); + Sequence<T> expected(n, [=](size_t) { return trash; }); + + invoke_on_all_policies(test_replace_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), + expected.end(), out.size(), pred, old_value, new_value, trash); + invoke_on_all_policies(test_replace_copy(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), + expected.end(), out.size(), pred, old_value, new_value, 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) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + + invoke_if(exec, [&]() { replace_copy_if(exec, input_iter, input_iter, out_iter, non_const(is_even), T(0)); }); + } +}; + +int32_t +main() +{ + + test<float64_t>(-666.0, 8.5, 0.33, [](const float64_t& x) { return x * x <= 1024; }, + [](size_t j) { return ((j + 1) % 7 & 2) != 0 ? 8.5 : float64_t(j % 32 + j); }); + + test<int32_t>(-666, 42, 99, [](const int32_t& x) { return x != 42; }, + [](size_t j) { return ((j + 1) % 5 & 2) != 0 ? 42 : -1 - int32_t(j); }); + +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN + test<Number>(Number(42, OddTag()), Number(2001, OddTag()), Number(2017, OddTag()), IsMultiple(3, OddTag()), + [](int32_t j) { return ((j + 1) % 3 & 2) != 0 ? Number(2001, OddTag()) : Number(j, OddTag()); }); +#endif + + 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.modifying.operations/rotate.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/rotate.pass.cpp new file mode 100644 index 00000000000..2bebc4e57da --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/rotate.pass.cpp @@ -0,0 +1,177 @@ +// -*- C++ -*- +//===-- rotate.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 <iterator> + +#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 wrapper +{ + T t; + int move_count; + explicit wrapper(T t_) : t(t_), move_count(0) {} + wrapper& + operator=(const T& t_) + { + t = t_; + return *this; + } + + wrapper(const wrapper<T>& a) : move_count(0) { t = a.t; } + + wrapper<T>& + operator=(wrapper<T>& a) + { + t = a.t; + return *this; + } + + wrapper<T>& + operator=(wrapper<T>&& a) + { + t = a.t; + move_count += 1; + return *this; + } +}; + +template <typename T> +struct compare +{ + bool + operator()(const T& a, const T& b) + { + return a == b; + } +}; + +template <typename T> +struct compare<wrapper<T>> +{ + bool + operator()(const wrapper<T>& a, const wrapper<T>& b) + { + return a.t == b.t; + } +}; +#include <typeinfo> + +struct test_one_policy +{ + +#if __PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN || \ + __PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN // dummy specializations to skip testing in case of broken configuration + template <typename Iterator, typename Size> + void + operator()(pstl::execution::unsequenced_policy, Iterator data_b, Iterator data_e, Iterator actual_b, + Iterator actual_e, Size shift) + { + } + template <typename Iterator, typename Size> + void + operator()(pstl::execution::parallel_unsequenced_policy, Iterator data_b, Iterator data_e, Iterator actual_b, + Iterator actual_e, Size shift) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator, typename Size> + void + operator()(ExecutionPolicy&& exec, Iterator data_b, Iterator data_e, Iterator actual_b, Iterator actual_e, + Size shift) + { + using namespace std; + using T = typename iterator_traits<Iterator>::value_type; + Iterator actual_m = std::next(actual_b, shift); + + copy(data_b, data_e, actual_b); + Iterator actual_return = rotate(exec, actual_b, actual_m, actual_e); + + EXPECT_TRUE(actual_return == std::next(actual_b, std::distance(actual_m, actual_e)), "wrong result of rotate"); + auto comparator = compare<T>(); + bool check = std::equal(actual_return, actual_e, data_b, comparator); + check = check && std::equal(actual_b, actual_return, std::next(data_b, shift), comparator); + + EXPECT_TRUE(check, "wrong effect of rotate"); + EXPECT_TRUE(check_move(exec, actual_b, actual_e, shift), "wrong move test of rotate"); + } + + template <typename ExecutionPolicy, typename Iterator, typename Size> + typename std::enable_if< + is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value && + !std::is_same<ExecutionPolicy, pstl::execution::sequenced_policy>::value && + std::is_same<typename std::iterator_traits<Iterator>::value_type, wrapper<float32_t>>::value, + bool>::type + check_move(ExecutionPolicy&& exec, Iterator b, Iterator e, Size shift) + { + bool result = all_of(b, e, [](wrapper<float32_t>& a) { + bool temp = a.move_count > 0; + a.move_count = 0; + return temp; + }); + return shift == 0 || result; + } + + template <typename ExecutionPolicy, typename Iterator, typename Size> + typename std::enable_if< + !(is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value && + !std::is_same<ExecutionPolicy, pstl::execution::sequenced_policy>::value && + std::is_same<typename std::iterator_traits<Iterator>::value_type, wrapper<float32_t>>::value), + bool>::type + check_move(ExecutionPolicy&& exec, Iterator b, Iterator e, Size shift) + { + return true; + } +}; + +template <typename T> +void +test() +{ + const int32_t max_len = 100000; + + Sequence<T> actual(max_len, [](std::size_t i) { return T(i); }); + Sequence<T> data(max_len, [](std::size_t i) { return T(i); }); + + for (int32_t len = 0; len < max_len; len = len <= 16 ? len + 1 : int32_t(3.1415 * len)) + { + int32_t shifts[] = {0, 1, 2, len / 3, (2 * len) / 3, len - 1}; + for (auto shift : shifts) + { + if (shift >= 0 && shift < len) + { + invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(), + actual.begin() + len, shift); + } + } + } +} + +int32_t +main() +{ + test<int32_t>(); + test<wrapper<float64_t>>(); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/rotate_copy.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/rotate_copy.pass.cpp new file mode 100644 index 00000000000..7d0ec7ec450 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/rotate_copy.pass.cpp @@ -0,0 +1,150 @@ +// -*- C++ -*- +//===-- rotate_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 +// +//===----------------------------------------------------------------------===// + +#include "support/pstl_test_config.h" + +#ifdef PSTL_STANDALONE_TESTS +#include <iterator> + +#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 wrapper; + +template <typename T> +bool +compare(const wrapper<T>& a, const wrapper<T>& b) +{ + return a.t == b.t; +} + +template <typename T> +bool +compare(const T& a, const T& b) +{ + return a == b; +} + +template <typename T> +struct wrapper +{ + explicit wrapper(T t_) : t(t_) {} + wrapper& + operator=(const T& t_) + { + t = t_; + return *this; + } + friend bool + compare<T>(const wrapper<T>& a, const wrapper<T>& b); + + private: + T t; +}; + +template <typename T, typename It1, typename It2> +struct comparator +{ + using T1 = typename std::iterator_traits<It1>::value_type; + using T2 = typename std::iterator_traits<It2>::value_type; + bool + operator()(T1 a, T2 b) + { + T temp = a; + return compare(temp, b); + } +}; + +struct test_one_policy +{ + +#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 Iterator1, typename Iterator2> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, + Iterator2 actual_e, std::size_t shift) + { + } + template <typename Iterator1, typename Iterator2> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, + Iterator2 actual_e, std::size_t shift) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2> + void + operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e, + std::size_t shift) + { + using namespace std; + using T = typename iterator_traits<Iterator2>::value_type; + Iterator1 data_m = std::next(data_b, shift); + + fill(actual_b, actual_e, T(-123)); + Iterator2 actual_return = rotate_copy(exec, data_b, data_m, data_e, actual_b); + + EXPECT_TRUE(actual_return == actual_e, "wrong result of rotate_copy"); + auto comparer = comparator<T, Iterator1, Iterator2>(); + bool check = std::equal(data_m, data_e, actual_b, comparer); + check = check && std::equal(data_b, data_m, std::next(actual_b, std::distance(data_m, data_e)), comparer); + + EXPECT_TRUE(check, "wrong effect of rotate_copy"); + } +}; + +template <typename T1, typename T2> +void +test() +{ + + const std::size_t max_len = 100000; + + Sequence<T2> actual(max_len, [](std::size_t i) { return T1(i); }); + + Sequence<T1> data(max_len, [](std::size_t i) { return T1(i); }); + + for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len)) + { + std::size_t shifts[] = {0, 1, 2, len / 3, (2 * len) / 3, len - 1}; + for (std::size_t shift : shifts) + { + if (shift > 0 && shift < len) + { + invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(), + actual.begin() + len, shift); + invoke_on_all_policies(test_one_policy(), data.cbegin(), data.cbegin() + len, actual.begin(), + actual.begin() + len, shift); + } + } + } +} + +int32_t +main() +{ + test<int32_t, int8_t>(); + test<uint16_t, float32_t>(); + test<float64_t, int64_t>(); + test<wrapper<float64_t>, wrapper<float64_t>>(); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/swap_ranges.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/swap_ranges.pass.cpp new file mode 100644 index 00000000000..b53003c4626 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/swap_ranges.pass.cpp @@ -0,0 +1,137 @@ +// -*- C++ -*- +//===-- swap_ranges.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 <iterator> + +#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 wrapper +{ + T t; + std::size_t number_of_swaps = 0; + wrapper() {} + explicit wrapper(T t_) : t(t_) {} + template <typename U> + void + operator=(const U& b) + { + t = b; + } + bool + operator==(const wrapper<T>& a) const + { + return t == a.t; + } +}; + +template <typename T> +void +swap(wrapper<T>& a, wrapper<T>& b) +{ + std::swap(a.t, b.t); + a.number_of_swaps++; + b.number_of_swaps++; +} + +template <typename T> +struct check_swap +{ + bool + operator()(T& a) + { + return true; + } +}; + +template <typename T> +struct check_swap<wrapper<T>> +{ + bool + operator()(wrapper<T>& a) + { + bool temp = (a.number_of_swaps == 1); + a.number_of_swaps = 0; + return temp; + } +}; + +struct test_one_policy +{ + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2> + void + operator()(ExecutionPolicy&& exec, Iterator1 data_b, Iterator1 data_e, Iterator2 actual_b, Iterator2 actual_e) + { + using namespace std; + using T_ref = typename iterator_traits<Iterator1>::reference; + using T = typename iterator_traits<Iterator1>::value_type; + + iota(data_b, data_e, 0); + iota(actual_b, actual_e, std::distance(data_b, data_e)); + + Iterator2 actual_return = swap_ranges(exec, data_b, data_e, actual_b); + bool check_return = (actual_return == actual_e); + EXPECT_TRUE(check_return, "wrong result of swap_ranges"); + if (check_return) + { + std::size_t i = 0; + bool check = all_of(actual_b, actual_e, [&i](T_ref a) { return a == T(i++); }) && + all_of(data_b, data_e, [&i](T_ref a) { return a == T(i++); }); + + EXPECT_TRUE(check, "wrong effect of swap_ranges"); + + if (check) + { + bool swap_check = + all_of(data_b, data_e, check_swap<T>()) && all_of(actual_b, actual_e, check_swap<T>()); + EXPECT_TRUE(swap_check, "wrong effect of swap_ranges swap check"); + } + } + } +}; + +template <typename T> +void +test() +{ + const std::size_t max_len = 100000; + + Sequence<T> data(max_len); + Sequence<T> actual(max_len); + + for (std::size_t len = 0; len < max_len; len = len <= 16 ? len + 1 : std::size_t(3.1415 * len)) + { + invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(), + actual.begin() + len); + } +} + +int32_t +main() +{ + test<wrapper<uint16_t>>(); + test<wrapper<float64_t>>(); + test<int32_t>(); + test<float32_t>(); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.modifying.operations/transform_binary.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/transform_binary.pass.cpp new file mode 100644 index 00000000000..2d680c369f2 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/transform_binary.pass.cpp @@ -0,0 +1,124 @@ +// -*- C++ -*- +//===-- transform_binary.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/algorithm" +#include "pstl/execution" +#else +#include <execution> +#include <algorithm> +#endif // PSTL_STANDALONE_TESTS + +#include "support/utils.h" + +using namespace TestUtils; + +template <typename In1, typename In2, typename Out> +class TheOperation +{ + Out val; + + public: + TheOperation(Out v) : val(v) {} + Out + operator()(const In1& x, const In2& y) const + { + return Out(val + x - y); + } +}; + +template <typename InputIterator1, typename InputIterator2, typename OutputIterator> +void +check_and_reset(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator out_first) +{ + typedef typename std::iterator_traits<OutputIterator>::value_type Out; + typename std::iterator_traits<OutputIterator>::difference_type k = 0; + for (; first1 != last1; ++first1, ++first2, ++out_first, ++k) + { + // check + Out expected = Out(1.5) + *first1 - *first2; + Out actual = *out_first; + if (std::is_floating_point<Out>::value) + { + EXPECT_TRUE((expected > actual ? expected - actual : actual - expected) < 1e7, + "wrong value in output sequence"); + } + else + { + EXPECT_EQ(expected, actual, "wrong value in output sequence"); + } + // reset + *out_first = k % 7 != 4 ? 7 * k - 5 : 0; + } +} + +struct test_one_policy +{ + template <typename Policy, typename InputIterator1, typename InputIterator2, typename OutputIterator, + typename BinaryOp> + void + operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, + OutputIterator out_first, OutputIterator out_last, BinaryOp op) + { + auto orrr = std::transform(exec, first1, last1, first2, out_first, op); + check_and_reset(first1, last1, first2, out_first); + } +}; + +template <typename In1, typename In2, typename Out, typename Predicate> +void +test(Predicate pred) +{ + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<In1> in1(n, [](size_t k) { return k % 5 != 1 ? 3 * k - 7 : 0; }); + Sequence<In2> in2(n, [](size_t k) { return k % 7 != 2 ? 5 * k - 5 : 0; }); + + Sequence<Out> out(n, [](size_t k) { return -1; }); + + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.end(), in2.begin(), in2.end(), out.begin(), + out.end(), pred); + invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cend(), in2.cbegin(), in2.cend(), out.begin(), + out.end(), pred); + } +} + +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, [&]() { + InputIterator input_iter2 = input_iter; + transform(exec, input_iter, input_iter, input_iter2, out_iter, non_const(std::plus<T>())); + }); + } +}; + +int32_t +main() +{ + //const operator() + test<int32_t, int32_t, int32_t>(TheOperation<int32_t, int32_t, int32_t>(1)); + test<float32_t, float32_t, float32_t>(TheOperation<float32_t, float32_t, float32_t>(1.5)); + //non-const operator() + test<int32_t, float32_t, float32_t>(non_const(TheOperation<int32_t, float32_t, float32_t>(1.5))); + test<int64_t, float64_t, float32_t>(non_const(TheOperation<int64_t, float64_t, float32_t>(1.5))); + //lambda + test<int8_t, float64_t, int8_t>([](const int8_t& x, const float64_t& y) { return int8_t(int8_t(1.5) + 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.modifying.operations/transform_unary.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/transform_unary.pass.cpp new file mode 100644 index 00000000000..e198c6e2a8b --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/transform_unary.pass.cpp @@ -0,0 +1,94 @@ +// -*- C++ -*- +//===-- transform_unary.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/algorithm" +#include "pstl/execution" +#else +#include <execution> +#include <algorithm> +#endif // PSTL_STANDALONE_TESTS + +#include "support/utils.h" + +using namespace TestUtils; + +template <typename InputIterator, typename OutputIterator> +void +check_and_reset(InputIterator first, InputIterator last, OutputIterator out_first) +{ + typedef typename std::iterator_traits<OutputIterator>::value_type Out; + typename std::iterator_traits<OutputIterator>::difference_type k = 0; + for (; first != last; ++first, ++out_first, ++k) + { + // check + Out expected = 1 - *first; + Out actual = *out_first; + EXPECT_EQ(expected, actual, "wrong value in output sequence"); + // reset + *out_first = k % 7 != 4 ? 7 * k - 5 : 0; + } +} + +struct test_one_policy +{ + template <typename Policy, typename InputIterator, typename OutputIterator, typename UnaryOp> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, UnaryOp op) + { + auto orr = std::transform(exec, first, last, out_first, op); + EXPECT_TRUE(out_last == orr, "transform returned wrong iterator"); + check_and_reset(first, last, out_first); + } +}; + +template <typename Tin, typename Tout> +void +test() +{ + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<Tin> in(n, [](int32_t k) { return k % 5 != 1 ? 3 * k - 7 : 0; }); + + Sequence<Tout> out(n); + + const auto flip = Complement<Tin, Tout>(1); + invoke_on_all_policies(test_one_policy(), in.begin(), in.end(), out.begin(), out.end(), flip); + invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cend(), out.begin(), out.end(), flip); + } +} + +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, [&]() { transform(exec, input_iter, input_iter, out_iter, non_const(std::negate<T>())); }); + } +}; + +int32_t +main() +{ + test<int32_t, int32_t>(); + test<int32_t, float32_t>(); + test<uint16_t, float32_t>(); + test<float32_t, float64_t>(); + test<float64_t, float64_t>(); + + 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.modifying.operations/unique.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/unique.pass.cpp new file mode 100644 index 00000000000..06639ccf685 --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/unique.pass.cpp @@ -0,0 +1,160 @@ +// -*- C++ -*- +//===-- unique.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 +// +//===----------------------------------------------------------------------===// + +// Test for unique +#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 run_unique +{ +#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 ForwardIt, typename Generator> + void + operator()(pstl::execution::unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2, + ForwardIt last2, Generator generator) + { + } + + template <typename ForwardIt, typename Generator> + void + operator()(pstl::execution::parallel_unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2, + ForwardIt last2, Generator generator) + { + } + + template <typename ForwardIt, typename BinaryPred, typename Generator> + void + operator()(pstl::execution::unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2, + ForwardIt last2, BinaryPred pred, Generator generator) + { + } + + template <typename ForwardIt, typename BinaryPred, typename Generator> + void + operator()(pstl::execution::parallel_unsequenced_policy, ForwardIt first1, ForwardIt last1, ForwardIt first2, + ForwardIt last2, BinaryPred pred, Generator generator) + { + } +#endif + + template <typename Policy, typename ForwardIt, typename Generator> + void + operator()(Policy&& exec, ForwardIt first1, ForwardIt last1, ForwardIt first2, ForwardIt last2, Generator generator) + { + using namespace std; + + // Preparation + fill_data(first1, last1, generator); + fill_data(first2, last2, generator); + + ForwardIt i = unique(first1, last1); + ForwardIt k = unique(exec, first2, last2); + + auto n = std::distance(first1, i); + EXPECT_TRUE(std::distance(first2, k) == n, "wrong return value from unique without predicate"); + EXPECT_EQ_N(first1, first2, n, "wrong effect from unique without predicate"); + } + + template <typename Policy, typename ForwardIt, typename BinaryPred, typename Generator> + void + operator()(Policy&& exec, ForwardIt first1, ForwardIt last1, ForwardIt first2, ForwardIt last2, BinaryPred pred, + Generator generator) + { + using namespace std; + + // Preparation + fill_data(first1, last1, generator); + fill_data(first2, last2, generator); + + ForwardIt i = unique(first1, last1, pred); + ForwardIt k = unique(exec, first2, last2, pred); + + auto n = std::distance(first1, i); + EXPECT_TRUE(std::distance(first2, k) == n, "wrong return value from unique with predicate"); + EXPECT_EQ_N(first1, first2, n, "wrong effect from unique with predicate"); + } +}; + +template <typename T, typename Generator, typename Predicate> +void +test(Generator generator, Predicate pred) +{ + const std::size_t max_size = 1000000; + Sequence<T> in(max_size, [](size_t v) { return T(v); }); + Sequence<T> exp(max_size, [](size_t v) { return T(v); }); + + for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + invoke_on_all_policies(run_unique(), exp.begin(), exp.begin() + n, in.begin(), in.begin() + n, generator); + invoke_on_all_policies(run_unique(), exp.begin(), exp.begin() + n, in.begin(), in.begin() + n, pred, generator); + } +} + +template <typename T> +struct LocalWrapper +{ + T my_val; + + explicit LocalWrapper(T k) : my_val(k) {} + LocalWrapper(LocalWrapper&& input) : my_val(std::move(input.my_val)) {} + LocalWrapper& + operator=(LocalWrapper&& input) + { + my_val = std::move(input.my_val); + return *this; + } + friend bool + operator==(const LocalWrapper<T>& x, const LocalWrapper<T>& y) + { + return x.my_val == y.my_val; + } +}; + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + invoke_if(exec, [&]() { unique(exec, iter, iter, non_const(std::equal_to<T>())); }); + } +}; + +int32_t +main() +{ +#if !__PSTL_ICC_16_17_18_TEST_UNIQUE_MASK_RELEASE_BROKEN + test<int32_t>([](size_t j) { return j / 3; }, + [](const int32_t& val1, const int32_t& val2) { return val1 * val1 == val2 * val2; }); + test<float64_t>([](size_t) { return float64_t(1); }, + [](const float64_t& val1, const float64_t& val2) { return val1 != val2; }); +#endif + test<LocalWrapper<uint32_t>>([](size_t j) { return LocalWrapper<uint32_t>(j); }, + [](const LocalWrapper<uint32_t>& val1, const LocalWrapper<uint32_t>& val2) { + return val1.my_val != val2.my_val; + }); + + 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.modifying.operations/unique_copy_equal.pass.cpp b/pstl/test/std/algorithms/alg.modifying.operations/unique_copy_equal.pass.cpp new file mode 100644 index 00000000000..c948e80d45a --- /dev/null +++ b/pstl/test/std/algorithms/alg.modifying.operations/unique_copy_equal.pass.cpp @@ -0,0 +1,138 @@ +// -*- C++ -*- +//===-- unique_copy_equal.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 unique_copy +#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 run_unique_copy +{ +#if __PSTL_ICC_16_VC14_TEST_PAR_TBB_RT_RELEASE_64_BROKEN // dummy specializations to skip testing in case of broken configuration + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename Predicate, typename T> + void + operator()(pstl::execution::parallel_policy, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, + Predicate pred, T trash) + { + } + + template <typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename Predicate, typename T> + void + operator()(pstl::execution::parallel_unsequenced_policy, InputIterator first, InputIterator last, + OutputIterator out_first, OutputIterator out_last, OutputIterator2 expected_first, + OutputIterator2 expected_last, Size n, Predicate pred, T trash) + { + } +#endif + + template <typename Policy, typename InputIterator, typename OutputIterator, typename OutputIterator2, typename Size, + typename Predicate, typename T> + void + operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, + OutputIterator out_last, OutputIterator2 expected_first, OutputIterator2 expected_last, Size n, + Predicate pred, T trash) + { + // Cleaning + std::fill_n(expected_first, n, trash); + std::fill_n(out_first, n, trash); + + // Run unique_copy + auto i = unique_copy(first, last, expected_first); + auto k = unique_copy(exec, first, last, out_first); + EXPECT_EQ_N(expected_first, out_first, n, "wrong unique_copy effect"); + for (size_t j = 0; j < GuardSize; ++j) + { + ++k; + } + EXPECT_TRUE(out_last == k, "wrong return value from unique_copy"); + + // Cleaning + std::fill_n(expected_first, n, trash); + std::fill_n(out_first, n, trash); + // Run unique_copy with predicate + i = unique_copy(first, last, expected_first, pred); + k = unique_copy(exec, first, last, out_first, pred); + EXPECT_EQ_N(expected_first, out_first, n, "wrong unique_copy with predicate effect"); + for (size_t j = 0; j < GuardSize; ++j) + { + ++k; + } + EXPECT_TRUE(out_last == k, "wrong return value from unique_copy with predicate"); + } +}; + +template <typename T, typename BinaryPredicate, typename Convert> +void +test(T trash, BinaryPredicate pred, Convert convert, bool check_weakness = true) +{ + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + // count is number of output elements, plus a handful + // more for sake of detecting buffer overruns. + Sequence<T> in(n, [&](size_t k) -> T { return convert(k ^ n); }); + using namespace std; + size_t count = GuardSize; + for (size_t k = 0; k < in.size(); ++k) + count += k == 0 || !pred(in[k], in[k - 1]) ? 1 : 0; + Sequence<T> out(count, [=](size_t) { return trash; }); + Sequence<T> expected(count, [=](size_t) { return trash; }); + if (check_weakness) + { + auto expected_result = unique_copy(in.begin(), in.end(), expected.begin(), pred); + size_t m = expected_result - expected.begin(); + EXPECT_TRUE(n / (n < 10000 ? 4 : 6) <= m && m <= (3 * n + 1) / 4, "weak test for unique_copy"); + } + invoke_on_all_policies(run_unique_copy(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), + expected.end(), count, pred, 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) + { + unique_copy(exec, input_iter, input_iter, out_iter, non_const(std::equal_to<T>())); + } +}; + +int32_t +main(int32_t argc, char* argv[]) +{ + test<Number>(Number(42, OddTag()), std::equal_to<Number>(), + [](int32_t j) { return Number(3 * j / 13 ^ (j & 8), OddTag()); }); + + test<float32_t>(float32_t(42), std::equal_to<float32_t>(), + [](int32_t j) { return float32_t(5 * j / 23 ^ (j / 7)); }); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN + test<float32_t>(float32_t(42), [](float32_t x, float32_t y) { return false; }, + [](int32_t j) { return float32_t(j); }, false); +#endif + + 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.nonmodifying/adjacent_find.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/adjacent_find.pass.cpp new file mode 100644 index 00000000000..50b01e38bc1 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/adjacent_find.pass.cpp @@ -0,0 +1,118 @@ +// -*- C++ -*- +//===-- adjacent_find.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_adjacent_find +{ + template <typename Policy, typename Iterator, typename Pred> + void + operator()(Policy&& exec, Iterator first, Iterator last, Pred pred) + { + using namespace std; + + auto k = std::adjacent_find(first, last, pred); + auto i = adjacent_find(exec, first, last, pred); + EXPECT_TRUE(i == k, "wrong return value from adjacent_find with predicate"); + + i = adjacent_find(exec, first, last); + EXPECT_TRUE(i == k, "wrong return value from adjacent_find without predicate"); + } +}; + +template <typename T> +void +test_adjacent_find_by_type() +{ + + size_t counts[] = {2, 3, 500}; + for (int32_t c = 0; c < const_size(counts); ++c) + { + + for (int32_t e = 0; e < (counts[c] >= 64 ? 64 : (counts[c] == 2 ? 1 : 2)); ++e) + { + Sequence<T> in(counts[c], [](int32_t v) -> T { return T(v); }); //fill 0...n + in[e] = in[e + 1] = -1; //make an adjacent pair + + auto i = std::adjacent_find(in.cbegin(), in.cend(), std::equal_to<T>()); + EXPECT_TRUE(i == in.cbegin() + e, "std::adjacent_find returned wrong result"); + + invoke_on_all_policies(test_adjacent_find(), in.begin(), in.end(), std::equal_to<T>()); + invoke_on_all_policies(test_adjacent_find(), in.cbegin(), in.cend(), std::equal_to<T>()); + } + } + + //special cases: size=0, size=1; + for (int32_t expect = 0; expect < 1; ++expect) + { + Sequence<T> in(expect, [](int32_t v) -> T { return T(v); }); //fill 0...n + auto i = std::adjacent_find(in.cbegin(), in.cend(), std::equal_to<T>()); + EXPECT_TRUE(i == in.cbegin() + expect, "std::adjacent_find returned wrong result"); + + invoke_on_all_policies(test_adjacent_find(), in.begin(), in.end(), std::equal_to<T>()); + invoke_on_all_policies(test_adjacent_find(), in.cbegin(), in.cend(), std::equal_to<T>()); + } + + //special cases: + Sequence<T> a1 = {5, 5, 5, 6, 7, 8, 9}; + invoke_on_all_policies(test_adjacent_find(), a1.begin(), a1.end(), std::equal_to<T>()); + invoke_on_all_policies(test_adjacent_find(), a1.begin() + 1, a1.end(), std::equal_to<T>()); + + invoke_on_all_policies(test_adjacent_find(), a1.cbegin(), a1.cend(), std::equal_to<T>()); + invoke_on_all_policies(test_adjacent_find(), a1.cbegin() + 1, a1.cend(), std::equal_to<T>()); + + Sequence<T> a2 = {5, 6, 7, 8, 9, 9}; + invoke_on_all_policies(test_adjacent_find(), a2.begin(), a2.end(), std::equal_to<T>()); + invoke_on_all_policies(test_adjacent_find(), a2.begin(), a2.end() - 1, std::equal_to<T>()); + + invoke_on_all_policies(test_adjacent_find(), a2.cbegin(), a2.cend(), std::equal_to<T>()); + invoke_on_all_policies(test_adjacent_find(), a2.cbegin(), a2.cend() - 1, std::equal_to<T>()); + + Sequence<T> a3 = {5, 6, 6, 6, 7, 9, 9, 9, 9}; + invoke_on_all_policies(test_adjacent_find(), a3.begin(), a3.end(), std::equal_to<T>()); + + invoke_on_all_policies(test_adjacent_find(), a3.cbegin(), a3.cend(), std::equal_to<T>()); +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + adjacent_find(exec, iter, iter, non_const(std::equal_to<T>())); + } +}; + +int32_t +main() +{ + + test_adjacent_find_by_type<int32_t>(); + test_adjacent_find_by_type<float64_t>(); + + test_algo_basic_single<int32_t>(run_for_rnd_bi<test_non_const<int32_t>>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/all_of.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/all_of.pass.cpp new file mode 100644 index 00000000000..f6372c44bd5 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/all_of.pass.cpp @@ -0,0 +1,120 @@ +// -*- C++ -*- +//===-- all_of.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" + +/* + TODO: consider implementing the following tests for a better code coverage + - correctness + - bad input argument (if applicable) + - data corruption around/of input and output + - correctly work with nested parallelism + - check that algorithm does not require anything more than is described in its requirements section +*/ + +using namespace TestUtils; + +struct test_all_of +{ + template <typename ExecutionPolicy, typename Iterator, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator begin, Iterator end, Predicate pred, bool expected) + { + + auto actualr = std::all_of(exec, begin, end, pred); + EXPECT_EQ(expected, actualr, "result for all_of"); + } +}; + +template <typename T> +struct Parity +{ + bool parity; + + public: + Parity(bool parity_) : parity(parity_) {} + bool + operator()(T value) const + { + return (size_t(value) ^ parity) % 2 == 0; + } +}; + +template <typename T> +void +test(size_t bits) +{ + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + + // Sequence of odd values + Sequence<T> in(n, [n, bits](size_t k) { return T(2 * HashBits(n, bits - 1) ^ 1); }); + + // Even value, or false when T is bool. + T spike(2 * HashBits(n, bits - 1)); + Sequence<T> inCopy(in); + + invoke_on_all_policies(test_all_of(), in.begin(), in.end(), Parity<T>(1), true); + invoke_on_all_policies(test_all_of(), in.cbegin(), in.cend(), Parity<T>(1), true); + EXPECT_EQ(in, inCopy, "all_of modified input sequence"); + if (n > 0) + { + // Sprinkle in a miss + in[2 * n / 3] = spike; + invoke_on_all_policies(test_all_of(), in.begin(), in.end(), Parity<T>(1), false); + invoke_on_all_policies(test_all_of(), in.cbegin(), in.cend(), Parity<T>(1), false); + + // Sprinkle in a few more misses + in[n / 2] = spike; + in[n / 3] = spike; + invoke_on_all_policies(test_all_of(), in.begin(), in.end(), Parity<T>(1), false); + invoke_on_all_policies(test_all_of(), in.cbegin(), in.cend(), Parity<T>(1), false); + } + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + all_of(exec, iter, iter, non_const(is_even)); + } +}; + +int32_t +main() +{ + test<int32_t>(8 * sizeof(int32_t)); + test<uint16_t>(8 * sizeof(uint16_t)); + test<float64_t>(53); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN + test<bool>(1); +#endif + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/any_of.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/any_of.pass.cpp new file mode 100644 index 00000000000..70bd4b2fb3b --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/any_of.pass.cpp @@ -0,0 +1,106 @@ +// -*- C++ -*- +//===-- any_of.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" + +/* + TODO: consider implementing the following tests for a better code coverage + - correctness + - bad input argument (if applicable) + - data corruption around/of input and output + - correctly work with nested parallelism + - check that algorithm does not require anything more than is described in its requirements section +*/ + +using namespace TestUtils; + +struct test_any_of +{ + template <typename ExecutionPolicy, typename Iterator, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator begin, Iterator end, Predicate pred, bool expected) + { + + auto actualr = std::any_of(exec, begin, end, pred); + EXPECT_EQ(expected, actualr, "result for any_of"); + } +}; + +template <typename T> +void +test(size_t bits) +{ + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + + // Sequence of odd values + Sequence<T> in(n, [n, bits](size_t k) { return T(2 * HashBits(n, bits - 1) ^ 1); }); + + // Even value, or false when T is bool. + T spike(2 * HashBits(n, bits - 1)); + Sequence<T> inCopy(in); + + invoke_on_all_policies(test_any_of(), in.begin(), in.end(), is_equal_to<T>(spike), false); + invoke_on_all_policies(test_any_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), false); + EXPECT_EQ(in, inCopy, "any_of modified input sequence"); + if (n > 0) + { + // Sprinkle in a hit + in[2 * n / 3] = spike; + invoke_on_all_policies(test_any_of(), in.begin(), in.end(), is_equal_to<T>(spike), true); + invoke_on_all_policies(test_any_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), true); + + // Sprinkle in a few more hits + in[n / 2] = spike; + in[n / 3] = spike; + invoke_on_all_policies(test_any_of(), in.begin(), in.end(), is_equal_to<T>(spike), true); + invoke_on_all_policies(test_any_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), true); + } + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + any_of(exec, iter, iter, non_const(is_even)); + } +}; + +int32_t +main() +{ + test<int32_t>(8 * sizeof(int32_t)); + test<uint16_t>(8 * sizeof(uint16_t)); + test<float64_t>(53); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN + test<bool>(1); +#endif + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/count.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/count.pass.cpp new file mode 100644 index 00000000000..38c553762f3 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/count.pass.cpp @@ -0,0 +1,111 @@ +// -*- C++ -*- +//===-- count.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 count and count_if +#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_count +{ + template <typename Policy, typename Iterator, typename T> + void + operator()(Policy&& exec, Iterator first, Iterator last, T needle) + { + auto expected = std::count(first, last, needle); + auto result = std::count(exec, first, last, needle); + EXPECT_EQ(expected, result, "wrong count result"); + } +}; + +struct test_count_if +{ + template <typename Policy, typename Iterator, typename Predicate> + void + operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred) + { + auto expected = std::count_if(first, last, pred); + auto result = std::count_if(exec, first, last, pred); + EXPECT_EQ(expected, result, "wrong count_if result"); + } +}; + +template <typename T> +class IsEqual +{ + T value; + + public: + IsEqual(T value_, OddTag) : value(value_) {} + bool + operator()(const T& x) const + { + return x == value; + } +}; + +template <typename In, typename T, typename Predicate, typename Convert> +void +test(T needle, Predicate pred, Convert convert) +{ + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<In> in(n, [=](size_t k) -> In { + // Sprinkle "42" and "50" early, so that short sequences have non-zero count. + return convert((n - k - 1) % 3 == 0 ? 42 : (n - k - 2) % 5 == 0 ? 50 : 3 * (int(k) % 1000 - 500)); + }); + invoke_on_all_policies(test_count(), in.begin(), in.end(), needle); + invoke_on_all_policies(test_count_if(), in.begin(), in.end(), pred); + + invoke_on_all_policies(test_count(), in.cbegin(), in.cend(), needle); + invoke_on_all_policies(test_count_if(), in.cbegin(), in.cend(), pred); + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + count_if(exec, iter, iter, non_const(is_even)); + } +}; + +int32_t +main() +{ + test<int32_t>(42, IsEqual<int32_t>(50, OddTag()), [](int32_t j) { return j; }); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_RELEASE_BROKEN + test<int32_t>(42, [](const int32_t& x) { return true; }, [](int32_t j) { return j; }); +#endif + test<float64_t>(42, IsEqual<float64_t>(50, OddTag()), [](int32_t j) { return float64_t(j); }); + test<Number>(Number(42, OddTag()), IsEqual<Number>(Number(50, OddTag()), OddTag()), + [](int32_t j) { return Number(j, OddTag()); }); + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/equal.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/equal.pass.cpp new file mode 100644 index 00000000000..0e4f38c2eb7 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/equal.pass.cpp @@ -0,0 +1,171 @@ +// -*- C++ -*- +//===-- equal.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 CPP14_ENABLED 0 + +struct UserType +{ + float32_t f; + float64_t d; + int32_t i; + size_t key; + + bool + operator()(UserType a, UserType b) + { + return a.key < b.key; + } + bool + operator<(UserType a) + { + return a.key < key; + } + bool + operator>=(UserType a) + { + return a.key <= key; + } + bool + operator<=(UserType a) + { + return a.key >= key; + } + bool + operator==(UserType a) + { + return a.key == key; + } + bool + operator==(UserType a) const + { + return a.key == key; + } + bool + operator!=(UserType a) + { + return a.key != key; + } + UserType operator!() + { + UserType tmp; + tmp.key = !key; + return tmp; + } + friend std::ostream& + operator<<(std::ostream& stream, const UserType a) + { + stream << a.key; + return stream; + } + + UserType() : key(-1), f(0.0f), d(0.0), i(0) {} + UserType(size_t Number) : key(Number), f(0.0f), d(0.0), i(0) {} + UserType& + operator=(const UserType& other) + { + key = other.key; + return *this; + } + UserType(const UserType& other) : key(other.key), f(other.f), d(other.d), i(other.i) {} + UserType(UserType&& other) : key(other.key), f(other.f), d(other.d), i(other.i) + { + other.key = -1; + other.f = 0.0f; + other.d = 0.0; + other.i = 0; + } +}; + +struct test_one_policy +{ + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2> + void + operator()(ExecutionPolicy&& exec, Iterator1 first1, Iterator1 last1, Iterator2 first2, bool is_true_equal) + { + using namespace std; + + auto expected = equal(first1, last1, first2); + auto actual = equal(exec, first1, last1, first2); + EXPECT_EQ(expected, actual, "result for equal for random-access iterator, checking against std::equal()"); + + // testing bool + EXPECT_TRUE(is_true_equal == actual, "result for equal for random-access iterator, bool"); + +//add C++14 equal symantics tests +//add more cases for inCopy size less than in +#if CPP14_ENABLED + auto actualr14 = std::equal(in.cbegin(), in.cend(), inCopy.cbegin(), inCopy.cend()); + EXPECT_EQ(expected, actualr14, "result for equal for random-access iterator"); +#endif + } +}; + +template <typename T> +void +test(size_t bits) +{ + for (size_t n = 1; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + + // Sequence of odd values + Sequence<T> in(n, [bits](size_t k) { return T(2 * HashBits(k, bits - 1) ^ 1); }); + Sequence<T> inCopy(in); + + invoke_on_all_policies(test_one_policy(), in.begin(), in.end(), inCopy.begin(), true); + invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cend(), inCopy.cbegin(), true); + + // testing bool !equal() + inCopy[0] = !inCopy[0]; + invoke_on_all_policies(test_one_policy(), in.begin(), in.end(), inCopy.begin(), false); + invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cend(), inCopy.cbegin(), false); + } +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename FirstIterator, typename SecondInterator> + void + operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter) + { + equal(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>())); + } +}; + +int32_t +main() +{ + + test<int32_t>(8 * sizeof(int32_t)); + test<uint16_t>(8 * sizeof(uint16_t)); + test<float64_t>(53); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN + test<bool>(1); +#endif + test<UserType>(256); + + 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.nonmodifying/find.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/find.pass.cpp new file mode 100644 index 00000000000..60e56ae4628 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/find.pass.cpp @@ -0,0 +1,99 @@ +// -*- C++ -*- +//===-- find.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 find +#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_find +{ +#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 Value> + void + operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Value value) + { + } + template <typename Iterator, typename Value> + void + operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Value value) + { + } +#endif + + template <typename Policy, typename Iterator, typename Value> + void + operator()(Policy&& exec, Iterator first, Iterator last, Value value) + { + auto i = std::find(first, last, value); + auto j = find(exec, first, last, value); + EXPECT_TRUE(i == j, "wrong return value from find"); + } +}; + +template <typename T, typename Value, typename Hit, typename Miss> +void +test(Value value, Hit hit, Miss miss) +{ + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<T> in(n, [&](size_t k) -> T { return miss(n ^ k); }); + // Try different find positions, including not found. + // By going backwards, we can add extra matches that are *not* supposed to be found. + // The decreasing exponential gives us O(n) total work for the loop since each find takes O(m) time. + for (size_t m = n; m > 0; m *= 0.6) + { + if (m < n) + in[m] = hit(n ^ m); + invoke_on_all_policies(test_find(), in.begin(), in.end(), value); + invoke_on_all_policies(test_find(), in.cbegin(), in.cend(), value); + } + } +} + +// Type defined for sake of checking that std::find works with asymmetric ==. +class Weird +{ + Number value; + + public: + friend bool + operator==(Number x, Weird y) + { + return x == y.value; + } + Weird(int32_t val, OddTag) : value(val, OddTag()) {} +}; + +int32_t +main() +{ + // Note that the "hit" and "miss" functions here avoid overflow issues. + test<Number>(Weird(42, OddTag()), [](int32_t j) { return Number(42, OddTag()); }, // hit + [](int32_t j) { return Number(j == 42 ? 0 : j, OddTag()); }); // miss + + // Test with value that is equal to two different bit patterns (-0.0 and 0.0) + test<float32_t>(-0.0, [](int32_t j) { return j & 1 ? 0.0 : -0.0; }, // hit + [](int32_t j) { return j == 0 ? ~j : j; }); // miss + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/find_end.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/find_end.pass.cpp new file mode 100644 index 00000000000..4059630b3d1 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/find_end.pass.cpp @@ -0,0 +1,126 @@ +// -*- C++ -*- +//===-- find_end.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_one_policy +{ +#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 Iterator1, typename Iterator2, typename Predicate> + void + operator()(pstl::execution::unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, + Predicate pred) + { + } + template <typename Iterator1, typename Iterator2, typename Predicate> + void + operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, + Predicate pred) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) + { + using namespace std; + // For find_end + { + auto expected = find_end(b, e, bsub, esub, pred); + auto actual = find_end(exec, b, e, bsub, esub); + EXPECT_TRUE(actual == expected, "wrong return result from find_end"); + + actual = find_end(exec, b, e, bsub, esub, pred); + EXPECT_TRUE(actual == expected, "wrong return result from find_end with a predicate"); + } + + // For search + { + auto expected = search(b, e, bsub, esub, pred); + auto actual = search(exec, b, e, bsub, esub); + EXPECT_TRUE(actual == expected, "wrong return result from search"); + + actual = search(exec, b, e, bsub, esub, pred); + EXPECT_TRUE(actual == expected, "wrong return result from search with a predicate"); + } + } +}; + +template <typename T> +void +test(const std::size_t bits) +{ + + const std::size_t max_n1 = 1000; + const std::size_t max_n2 = (max_n1 * 10) / 8; + Sequence<T> in(max_n1, [max_n1, bits](std::size_t k) { return T(2 * HashBits(max_n1, bits - 1) ^ 1); }); + Sequence<T> sub(max_n2, [max_n1, bits](std::size_t k) { return T(2 * HashBits(max_n1, bits - 1)); }); + for (std::size_t n1 = 0; n1 <= max_n1; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1)) + { + std::size_t sub_n[] = {0, 1, 3, n1, (n1 * 10) / 8}; + std::size_t res[] = {0, 1, n1 / 2, n1}; + for (auto n2 : sub_n) + { + for (auto r : res) + { + std::size_t i = r, isub = 0; + for (; i < n1 & isub < n2; ++i, ++isub) + in[i] = sub[isub]; + invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n1, sub.begin(), sub.begin() + n2, + std::equal_to<T>()); + invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cbegin() + n1, sub.cbegin(), + sub.cbegin() + n2, std::equal_to<T>()); + } + } + } +} + +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, [&]() { + find_end(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>())); + search(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>())); + }); + } +}; + +int32_t +main() +{ + test<int32_t>(8 * sizeof(int32_t)); + test<uint16_t>(8 * sizeof(uint16_t)); + test<float64_t>(53); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN + test<bool>(1); +#endif + + 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.nonmodifying/find_first_of.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/find_first_of.pass.cpp new file mode 100644 index 00000000000..ee62e84fd16 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/find_first_of.pass.cpp @@ -0,0 +1,115 @@ +// -*- C++ -*- +//===-- find_first_of.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_one_policy +{ +#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 Iterator1, typename Iterator2, typename Predicate> + void + operator()(pstl::execution::unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, + Predicate pred) + { + } + template <typename Iterator1, typename Iterator2, typename Predicate> + void + operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, + Predicate pred) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator1, typename Iterator2, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator1 b, Iterator1 e, Iterator2 bsub, Iterator2 esub, Predicate pred) + { + using namespace std; + Iterator1 expected = find_first_of(b, e, bsub, esub, pred); + Iterator1 actual = find_first_of(exec, b, e, bsub, esub, pred); + EXPECT_TRUE(actual == expected, "wrong return result from find_first_of with a predicate"); + + expected = find_first_of(b, e, bsub, esub); + actual = find_first_of(exec, b, e, bsub, esub); + EXPECT_TRUE(actual == expected, "wrong return result from find_first_of"); + } +}; + +template <typename T, typename Predicate> +void +test(Predicate pred) +{ + + const std::size_t max_n1 = 1000; + const std::size_t max_n2 = (max_n1 * 10) / 8; + Sequence<T> in1(max_n1, [](std::size_t k) { return T(1); }); + Sequence<T> in2(max_n2, [](std::size_t k) { return T(0); }); + for (std::size_t n1 = 0; n1 <= max_n1; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1)) + { + std::size_t sub_n[] = {0, 1, n1 / 3, n1, (n1 * 10) / 8}; + for (const auto n2 : sub_n) + { + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + n1, in2.data(), in2.data() + n2, pred); + + in2[n2 / 2] = T(1); + invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + n1, in2.data(), in2.data() + n2, + pred); + + if (n2 >= 3) + { + in2[2 * n2 / 3] = T(1); + invoke_on_all_policies(test_one_policy(), in1.cbegin(), in1.cbegin() + n1, in2.begin(), + in2.begin() + n2, pred); + in2[2 * n2 / 3] = T(0); + } + in2[n2 / 2] = T(0); + } + } + invoke_on_all_policies(test_one_policy(), in1.begin(), in1.begin() + max_n1 / 10, in1.data(), + in1.data() + max_n1 / 10, pred); +} + +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, [&]() { + find_first_of(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::equal_to<T>())); + }); + } +}; + +int32_t +main() +{ + test<int32_t>(std::equal_to<int32_t>()); + test<uint16_t>(std::not_equal_to<uint16_t>()); + test<float64_t>([](const float64_t x, const float64_t y) { return x * x == y * 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.nonmodifying/find_if.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/find_if.pass.cpp new file mode 100644 index 00000000000..2ea8765077f --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/find_if.pass.cpp @@ -0,0 +1,112 @@ +// -*- C++ -*- +//===-- find_if.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 find_if and find_if_not +#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_find_if +{ +#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 NotPredicate> + void + operator()(pstl::execution::unsequenced_policy, Iterator first, Iterator last, Predicate pred, + NotPredicate not_pred) + { + } + template <typename Iterator, typename Predicate, typename NotPredicate> + void + operator()(pstl::execution::parallel_unsequenced_policy, Iterator first, Iterator last, Predicate pred, + NotPredicate not_pred) + { + } +#endif + + template <typename Policy, typename Iterator, typename Predicate, typename NotPredicate> + void + operator()(Policy&& exec, Iterator first, Iterator last, Predicate pred, NotPredicate not_pred) + { + auto i = std::find_if(first, last, pred); + auto j = find_if(exec, first, last, pred); + EXPECT_TRUE(i == j, "wrong return value from find_if"); + auto i_not = find_if_not(exec, first, last, not_pred); + EXPECT_TRUE(i_not == i, "wrong return value from find_if_not"); + } +}; + +template <typename T, typename Predicate, typename Hit, typename Miss> +void +test(Predicate pred, Hit hit, Miss miss) +{ + auto not_pred = [pred](T x) { return !pred(x); }; + // Try sequences of various lengths. + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<T> in(n, [&](size_t k) -> T { return miss(n ^ k); }); + // Try different find positions, including not found. + // By going backwards, we can add extra matches that are *not* supposed to be found. + // The decreasing exponential gives us O(n) total work for the loop since each find takes O(m) time. + for (size_t m = n; m > 0; m *= 0.6) + { + if (m < n) + in[m] = hit(n ^ m); + invoke_on_all_policies(test_find_if(), in.begin(), in.end(), pred, not_pred); + invoke_on_all_policies(test_find_if(), in.cbegin(), in.cend(), pred, not_pred); + } + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + + invoke_if(exec, [&]() { + find_if(exec, iter, iter, non_const(is_even)); + find_if_not(exec, iter, iter, non_const(is_even)); + }); + } +}; + +int32_t +main() +{ +#if !__PSTL_ICC_17_TEST_MAC_RELEASE_32_BROKEN + // Note that the "hit" and "miss" functions here avoid overflow issues. + test<Number>(IsMultiple(5, OddTag()), [](int32_t j) { return Number(j - j % 5, OddTag()); }, // hit + [](int32_t j) { return Number(j % 5 == 0 ? j ^ 1 : j, OddTag()); }); // miss +#endif + + // Try type for which algorithm can really be vectorized. + test<float32_t>([](float32_t x) { return x >= 0; }, [](float32_t j) { return j * j; }, + [](float32_t j) { return -1 - j * j; }); + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/for_each.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/for_each.pass.cpp new file mode 100644 index 00000000000..cb0fa06dcda --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/for_each.pass.cpp @@ -0,0 +1,105 @@ +// -*- C++ -*- +//===-- for_each.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; + +template <typename Type> +struct Gen +{ + Type + operator()(std::size_t k) + { + return Type(k % 5 != 1 ? 3 * k - 7 : 0); + }; +}; + +template <typename T> +struct Flip +{ + int32_t val; + Flip(int32_t y) : val(y) {} + T + operator()(T& x) const + { + return x = val - x; + } +}; + +struct test_one_policy +{ + template <typename Policy, typename Iterator, typename Size> + void + operator()(Policy&& exec, Iterator first, Iterator last, Iterator expected_first, Iterator expected_last, Size n) + { + typedef typename std::iterator_traits<Iterator>::value_type T; + + // Try for_each + std::for_each(expected_first, expected_last, Flip<T>(1)); + for_each(exec, first, last, Flip<T>(1)); + EXPECT_EQ_N(expected_first, first, n, "wrong effect from for_each"); + + // Try for_each_n + std::for_each_n(pstl::execution::seq, expected_first, n, Flip<T>(1)); + for_each_n(exec, first, n, Flip<T>(1)); + EXPECT_EQ_N(expected_first, first, n, "wrong effect from for_each_n"); + } +}; + +template <typename T> +void +test() +{ + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + Sequence<T> inout(n, Gen<T>()); + Sequence<T> expected(n, Gen<T>()); + invoke_on_all_policies(test_one_policy(), inout.begin(), inout.end(), expected.begin(), expected.end(), + inout.size()); + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + invoke_if(exec, [&]() { + auto f = [](typename std::iterator_traits<Iterator>::reference x) { x = x + 1; }; + + for_each(exec, iter, iter, non_const(f)); + for_each_n(exec, iter, 0, non_const(f)); + }); + } +}; + +int32_t +main() +{ + test<int32_t>(); + test<uint16_t>(); + test<float64_t>(); + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/mismatch.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/mismatch.pass.cpp new file mode 100644 index 00000000000..ec34af08fb0 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/mismatch.pass.cpp @@ -0,0 +1,139 @@ +// -*- C++ -*- +//===-- mismatch.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" +#include "pstl/numeric" +#include "pstl/memory" + +#else +#include <execution> +#include <algorithm> +#endif // PSTL_STANDALONE_TESTS + +#include "support/utils.h" + +using namespace TestUtils; + +struct test_mismatch +{ + template <typename Policy, typename Iterator1, typename Iterator2> + void + operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator2 first2) + { + using namespace std; + typedef typename iterator_traits<Iterator1>::value_type T; + { + const auto expected = std::mismatch(first1, last1, first2, std::equal_to<T>()); + const auto res3 = mismatch(exec, first1, last1, first2, std::equal_to<T>()); + EXPECT_TRUE(expected == res3, "wrong return result from mismatch"); + const auto res4 = mismatch(exec, first1, last1, first2); + EXPECT_TRUE(expected == res4, "wrong return result from mismatch"); + } + } + template <typename Policy, typename Iterator1, typename Iterator2> + void + operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + { + using namespace std; + typedef typename iterator_traits<Iterator1>::value_type T; + { + const auto expected = mismatch(pstl::execution::seq, first1, last1, first2, last2, std::equal_to<T>()); + const auto res1 = mismatch(exec, first1, last1, first2, last2, std::equal_to<T>()); + EXPECT_TRUE(expected == res1, "wrong return result from mismatch"); + const auto res2 = mismatch(exec, first1, last1, first2, last2); + EXPECT_TRUE(expected == res2, "wrong return result from mismatch"); + } + } +}; + +template <typename T> +void +test_mismatch_by_type() +{ + using namespace std; + for (size_t size = 0; size <= 100000; size = size <= 16 ? size + 1 : size_t(3.1415 * size)) + { + const T val = T(-1); + Sequence<T> in(size, [](size_t v) -> T { return T(v % 100); }); + { + Sequence<T> in2(in); + invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin(), in2.end()); + invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin()); + + const size_t min_size = 3; + if (size > min_size) + { + const size_t idx_for_1 = size / min_size; + in[idx_for_1] = val, in[idx_for_1 + 1] = val, in[idx_for_1 + 2] = val; + invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin(), in2.end()); + invoke_on_all_policies(test_mismatch(), in.begin(), in.end(), in2.begin()); + } + + const size_t idx_for_2 = 500; + if (size >= idx_for_2 - 1) + { + in2[size / idx_for_2] = val; + invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin(), in2.cend()); + invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin()); + } + } + { + Sequence<T> in2(100, [](size_t v) -> T { return T(v); }); + invoke_on_all_policies(test_mismatch(), in2.begin(), in2.end(), in.begin(), in.end()); + // We can't call std::mismatch with semantic below when size of second sequence less than size of first sequence + if (in2.size() <= in.size()) + invoke_on_all_policies(test_mismatch(), in2.begin(), in2.end(), in.begin()); + + const size_t idx = 97; + in2[idx] = val; + in2[idx + 1] = val; + invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin(), in2.cend()); + if (in.size() <= in2.size()) + invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin()); + } + { + Sequence<T> in2({}); + invoke_on_all_policies(test_mismatch(), in2.begin(), in2.end(), in.begin(), in.end()); + + invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin(), in2.cend()); + if (in.size() == 0) + invoke_on_all_policies(test_mismatch(), in.cbegin(), in.cend(), in2.cbegin()); + } + } +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename FirstIterator, typename SecondInterator> + void + operator()(Policy&& exec, FirstIterator first_iter, SecondInterator second_iter) + { + mismatch(exec, first_iter, first_iter, second_iter, second_iter, non_const(std::less<T>())); + } +}; + +int32_t +main() +{ + + test_mismatch_by_type<int32_t>(); + test_mismatch_by_type<float64_t>(); + test_mismatch_by_type<Wrapper<int32_t>>(); + + 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.nonmodifying/none_of.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/none_of.pass.cpp new file mode 100644 index 00000000000..47a01a15027 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/none_of.pass.cpp @@ -0,0 +1,104 @@ +// -*- C++ -*- +//===-- none_of.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" + +/* + TODO: consider implementing the following tests for a better code coverage + - correctness + - bad input argument (if applicable) + - data corruption around/of input and output + - correctly work with nested parallelism + - check that algorithm does not require anything more than is described in its requirements section +*/ + +using namespace TestUtils; + +struct test_none_of +{ + template <typename ExecutionPolicy, typename Iterator, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator begin, Iterator end, Predicate pred, bool expected) + { + + auto actualr = std::none_of(exec, begin, end, pred); + EXPECT_EQ(expected, actualr, "result for none_of"); + } +}; + +template <typename T> +void +test(size_t bits) +{ + for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + + // Sequence of odd values + Sequence<T> in(n, [n, bits](size_t k) { return T(2 * HashBits(n, bits - 1) ^ 1); }); + + // Even value, or false when T is bool. + T spike(2 * HashBits(n, bits - 1)); + + invoke_on_all_policies(test_none_of(), in.begin(), in.end(), is_equal_to<T>(spike), true); + invoke_on_all_policies(test_none_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), true); + if (n > 0) + { + // Sprinkle in a hit + in[2 * n / 3] = spike; + invoke_on_all_policies(test_none_of(), in.begin(), in.end(), is_equal_to<T>(spike), false); + invoke_on_all_policies(test_none_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), false); + + // Sprinkle in a few more hits + in[n / 3] = spike; + in[n / 2] = spike; + invoke_on_all_policies(test_none_of(), in.begin(), in.end(), is_equal_to<T>(spike), false); + invoke_on_all_policies(test_none_of(), in.cbegin(), in.cend(), is_equal_to<T>(spike), false); + } + } +} + +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + auto is_even = [&](float64_t v) { + uint32_t i = (uint32_t)v; + return i % 2 == 0; + }; + none_of(exec, iter, iter, non_const(is_even)); + } +}; + +int32_t +main() +{ + test<int32_t>(8 * sizeof(int32_t)); + test<uint16_t>(8 * sizeof(uint16_t)); + test<float64_t>(53); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN + test<bool>(1); +#endif + + test_algo_basic_single<int32_t>(run_for_rnd_fw<test_non_const>()); + + std::cout << done() << std::endl; + return 0; +} diff --git a/pstl/test/std/algorithms/alg.nonmodifying/nth_element.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/nth_element.pass.cpp new file mode 100644 index 00000000000..f8154d2426d --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/nth_element.pass.cpp @@ -0,0 +1,181 @@ +// -*- C++ -*- +//===-- nth_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 <algorithm> +#include <iostream> +#include "pstl/execution" +#include "pstl/algorithm" + +#else +#include <execution> +#include <algorithm> +#endif // PSTL_STANDALONE_TESTS + +#include "support/utils.h" + +using namespace TestUtils; + +// User defined type with minimal requirements +template <typename T> +struct DataType +{ + explicit DataType(int32_t k) : my_val(k) {} + DataType(DataType&& input) + { + my_val = std::move(input.my_val); + input.my_val = T(0); + } + DataType& + operator=(DataType&& input) + { + my_val = std::move(input.my_val); + input.my_val = T(0); + return *this; + } + T + get_val() const + { + return my_val; + } + + friend std::ostream& + operator<<(std::ostream& stream, const DataType<T>& input) + { + return stream << input.my_val; + } + + private: + T my_val; +}; + +template <typename T> +bool +is_equal(const DataType<T>& x, const DataType<T>& y) +{ + return x.get_val() == y.get_val(); +} + +template <typename T> +bool +is_equal(const T& x, const T& y) +{ + return x == y; +} + +struct test_one_policy +{ +#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 Iterator1, typename Size, typename Generator1, typename Generator2, typename Compare> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::unsequenced_policy, Iterator1 first1, Iterator1 last1, Iterator1 first2, + Iterator1 last2, Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp) + { + } + template <typename Iterator1, typename Size, typename Generator1, typename Generator2, typename Compare> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(pstl::execution::parallel_unsequenced_policy, Iterator1 first1, Iterator1 last1, Iterator1 first2, + Iterator1 last2, Size n, Size m, Generator1 generator1, Generator2 generator2, Compare comp) + { + } +#endif + + // nth_element works only with random access iterators + template <typename Policy, typename Iterator1, typename Size, typename Generator1, typename Generator2, + typename Compare> + typename std::enable_if<is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator1 first2, Iterator1 last2, Size n, Size m, + Generator1 generator1, Generator2 generator2, Compare comp) + { + + using T = typename std::iterator_traits<Iterator1>::value_type; + const Iterator1 mid1 = std::next(first1, m); + const Iterator1 mid2 = std::next(first2, m); + + fill_data(first1, mid1, generator1); + fill_data(mid1, last1, generator2); + fill_data(first2, mid2, generator1); + fill_data(mid2, last2, generator2); + std::nth_element(first1, mid1, last1, comp); + std::nth_element(exec, first2, mid2, last2, comp); + if (m > 0 && m < n) + { + EXPECT_TRUE(is_equal(*mid1, *mid2), "wrong result from nth_element with predicate"); + } + EXPECT_TRUE(std::find_first_of(first2, mid2, mid2, last2, [comp](T& x, T& y) { return comp(y, x); }) == mid2, + "wrong effect from nth_element with predicate"); + } + + template <typename Policy, typename Iterator1, typename Size, typename Generator1, typename Generator2, + typename Compare> + typename std::enable_if<!is_same_iterator_category<Iterator1, std::random_access_iterator_tag>::value, void>::type + operator()(Policy&& exec, Iterator1 first1, Iterator1 last1, Iterator1 first2, Iterator1 last2, Size n, Size m, + Generator1 generator1, Generator2 generator2, Compare comp) + { + } +}; + +template <typename T, typename Generator1, typename Generator2, typename Compare> +void +test_by_type(Generator1 generator1, Generator2 generator2, Compare comp) +{ + using namespace std; + size_t max_size = 10000; + Sequence<T> in1(max_size, [](size_t v) { return T(v); }); + Sequence<T> exp(max_size, [](size_t v) { return T(v); }); + size_t m; + + for (size_t n = 0; n <= max_size; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) + { + m = 0; + invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + n, in1.begin(), in1.begin() + n, n, m, + generator1, generator2, comp); + m = n / 7; + invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + n, in1.begin(), in1.begin() + n, n, m, + generator1, generator2, comp); + m = 3 * n / 5; + invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + n, in1.begin(), in1.begin() + n, n, m, + generator1, generator2, comp); + } + invoke_on_all_policies(test_one_policy(), exp.begin(), exp.begin() + max_size, in1.begin(), in1.begin() + max_size, + max_size, max_size, generator1, generator2, comp); +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + invoke_if(exec, [&]() { nth_element(exec, iter, iter, iter, non_const(std::less<T>())); }); + } +}; + +int32_t +main() +{ + test_by_type<int32_t>([](int32_t i) { return 10 * i; }, [](int32_t i) { return i + 1; }, std::less<int32_t>()); + test_by_type<int32_t>([](int32_t) { return 0; }, [](int32_t) { return 0; }, std::less<int32_t>()); + + test_by_type<float64_t>([](int32_t i) { return -2 * i; }, [](int32_t i) { return -(2 * i + 1); }, + [](const float64_t x, const float64_t y) { return x > y; }); + + test_by_type<DataType<float32_t>>( + [](int32_t i) { return DataType<float32_t>(2 * i + 1); }, [](int32_t i) { return DataType<float32_t>(2 * i); }, + [](const DataType<float32_t>& x, const DataType<float32_t>& y) { return x.get_val() < y.get_val(); }); + + 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.nonmodifying/search_n.pass.cpp b/pstl/test/std/algorithms/alg.nonmodifying/search_n.pass.cpp new file mode 100644 index 00000000000..c0c6040e176 --- /dev/null +++ b/pstl/test/std/algorithms/alg.nonmodifying/search_n.pass.cpp @@ -0,0 +1,112 @@ +// -*- C++ -*- +//===-- search_n.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_one_policy +{ +#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 Size, typename T, typename Predicate> + void + operator()(pstl::execution::unsequenced_policy, Iterator b, Iterator e, Size count, const T& value, Predicate pred) + { + } + template <typename Iterator, typename Size, typename T, typename Predicate> + void + operator()(pstl::execution::parallel_unsequenced_policy, Iterator b, Iterator e, Size count, const T& value, + Predicate pred) + { + } +#endif + + template <typename ExecutionPolicy, typename Iterator, typename Size, typename T, typename Predicate> + void + operator()(ExecutionPolicy&& exec, Iterator b, Iterator e, Size count, const T& value, Predicate pred) + { + using namespace std; + auto expected = search_n(b, e, count, value, pred); + auto actual = search_n(exec, b, e, count, value); + EXPECT_TRUE(actual == expected, "wrong return result from search_n"); + + actual = search_n(exec, b, e, count, value, pred); + EXPECT_TRUE(actual == expected, "wrong return result from search_n with a predicate"); + } +}; + +template <typename T> +void +test() +{ + + const std::size_t max_n1 = 100000; + const T value = T(1); + for (std::size_t n1 = 0; n1 <= max_n1; n1 = n1 <= 16 ? n1 + 1 : size_t(3.1415 * n1)) + { + std::size_t sub_n[] = {0, 1, 3, n1, (n1 * 10) / 8}; + std::size_t res[] = {0, 1, n1 / 2, n1}; + for (auto n2 : sub_n) + { + // Some of standard libraries return "first" in this case. We return "last" according to the standard + if (n2 == 0) + { + continue; + } + for (auto r : res) + { + Sequence<T> in(n1, [n1](std::size_t k) { return T(0); }); + std::size_t i = r, isub = 0; + for (; i < n1 & isub < n2; ++i, ++isub) + in[i] = value; + + invoke_on_all_policies(test_one_policy(), in.begin(), in.begin() + n1, n2, value, std::equal_to<T>()); + invoke_on_all_policies(test_one_policy(), in.cbegin(), in.cbegin() + n1, n2, value, std::equal_to<T>()); + } + } + } +} + +template <typename T> +struct test_non_const +{ + template <typename Policy, typename Iterator> + void + operator()(Policy&& exec, Iterator iter) + { + invoke_if(exec, [&]() { search_n(exec, iter, iter, 0, T(0), non_const(std::equal_to<T>())); }); + } +}; + +int32_t +main() +{ + test<int32_t>(); + test<uint16_t>(); + test<float64_t>(); +#if !__PSTL_ICC_16_17_TEST_REDUCTION_BOOL_TYPE_RELEASE_64_BROKEN + test<bool>(); +#endif + + 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/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; +} |