1 // -*- C++ -*- 2 //===-- transform_scan.pass.cpp -------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "support/pstl_test_config.h" 11 12 #ifdef PSTL_STANDALONE_TESTS 13 #include "pstl/execution" 14 #include "pstl/numeric" 15 #else 16 #include <execution> 17 #include <numeric> 18 #endif // PSTL_STANDALONE_TESTS 19 20 #include "support/utils.h" 21 22 using namespace TestUtils; 23 24 // Most of the framework required for testing inclusive and exclusive transform-scans is identical, 25 // so the tests for both are in this file. Which is being tested is controlled by the global 26 // flag inclusive, which is set to each alternative by main(). 27 static bool inclusive; 28 29 template <typename Iterator, typename Size, typename T> 30 void 31 check_and_reset(Iterator expected_first, Iterator out_first, Size n, T trash) 32 { 33 EXPECT_EQ_N(expected_first, out_first, n, 34 inclusive ? "wrong result from transform_inclusive_scan" 35 : "wrong result from transform_exclusive_scan"); 36 std::fill_n(out_first, n, trash); 37 } 38 39 struct test_transform_scan 40 { 41 template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename UnaryOp, 42 typename T, typename BinaryOp> 43 typename std::enable_if<!TestUtils::isReverse<InputIterator>::value, void>::type 44 operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, 45 OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n, 46 UnaryOp unary_op, T init, BinaryOp binary_op, T trash) 47 { 48 using namespace std; 49 50 auto orr1 = inclusive ? transform_inclusive_scan(pstl::execution::seq, first, last, expected_first, binary_op, 51 unary_op, init) 52 : transform_exclusive_scan(pstl::execution::seq, first, last, expected_first, init, 53 binary_op, unary_op); 54 auto orr2 = inclusive ? transform_inclusive_scan(exec, first, last, out_first, binary_op, unary_op, init) 55 : transform_exclusive_scan(exec, first, last, out_first, init, binary_op, unary_op); 56 EXPECT_TRUE(out_last == orr2, "transform...scan returned wrong iterator"); 57 check_and_reset(expected_first, out_first, n, trash); 58 59 // Checks inclusive scan if init is not provided 60 if (inclusive && n > 0) 61 { 62 orr1 = transform_inclusive_scan(pstl::execution::seq, first, last, expected_first, binary_op, unary_op); 63 orr2 = transform_inclusive_scan(exec, first, last, out_first, binary_op, unary_op); 64 EXPECT_TRUE(out_last == orr2, "transform...scan returned wrong iterator"); 65 check_and_reset(expected_first, out_first, n, trash); 66 } 67 } 68 69 template <typename Policy, typename InputIterator, typename OutputIterator, typename Size, typename UnaryOp, 70 typename T, typename BinaryOp> 71 typename std::enable_if<TestUtils::isReverse<InputIterator>::value, void>::type 72 operator()(Policy&& exec, InputIterator first, InputIterator last, OutputIterator out_first, 73 OutputIterator out_last, OutputIterator expected_first, OutputIterator expected_last, Size n, 74 UnaryOp unary_op, T init, BinaryOp binary_op, T trash) 75 { 76 } 77 }; 78 79 const uint32_t encryption_mask = 0x314; 80 81 template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename T, 82 typename BinaryOperation> 83 std::pair<OutputIterator, T> 84 transform_inclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation unary_op, 85 T init, BinaryOperation binary_op) noexcept 86 { 87 for (; first != last; ++first, ++result) 88 { 89 init = binary_op(init, unary_op(*first)); 90 *result = init; 91 } 92 return std::make_pair(result, init); 93 } 94 95 template <typename InputIterator, typename OutputIterator, typename UnaryOperation, typename T, 96 typename BinaryOperation> 97 std::pair<OutputIterator, T> 98 transform_exclusive_scan_serial(InputIterator first, InputIterator last, OutputIterator result, UnaryOperation unary_op, 99 T init, BinaryOperation binary_op) noexcept 100 { 101 for (; first != last; ++first, ++result) 102 { 103 *result = init; 104 init = binary_op(init, unary_op(*first)); 105 } 106 return std::make_pair(result, init); 107 } 108 109 template <typename In, typename Out, typename UnaryOp, typename BinaryOp> 110 void 111 test(UnaryOp unary_op, Out init, BinaryOp binary_op, Out trash) 112 { 113 for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) 114 { 115 Sequence<In> in(n, [](size_t k) { return In(k ^ encryption_mask); }); 116 117 Out tmp = init; 118 Sequence<Out> expected(n, [&](size_t k) -> Out { 119 if (inclusive) 120 { 121 tmp = binary_op(tmp, unary_op(in[k])); 122 return tmp; 123 } 124 else 125 { 126 Out val = tmp; 127 tmp = binary_op(tmp, unary_op(in[k])); 128 return val; 129 } 130 }); 131 132 Sequence<Out> out(n, [&](size_t) { return trash; }); 133 134 auto result = 135 inclusive 136 ? transform_inclusive_scan_serial(in.cbegin(), in.cend(), out.fbegin(), unary_op, init, binary_op) 137 : transform_exclusive_scan_serial(in.cbegin(), in.cend(), out.fbegin(), unary_op, init, binary_op); 138 check_and_reset(expected.begin(), out.begin(), out.size(), trash); 139 140 invoke_on_all_policies(test_transform_scan(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), 141 expected.end(), in.size(), unary_op, init, binary_op, trash); 142 invoke_on_all_policies(test_transform_scan(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), 143 expected.end(), in.size(), unary_op, init, binary_op, trash); 144 } 145 } 146 147 template <typename In, typename Out, typename UnaryOp, typename BinaryOp> 148 void 149 test_matrix(UnaryOp unary_op, Out init, BinaryOp binary_op, Out trash) 150 { 151 for (size_t n = 0; n <= 100000; n = n <= 16 ? n + 1 : size_t(3.1415 * n)) 152 { 153 Sequence<In> in(n, [](size_t k) { return In(k, k + 1); }); 154 155 Sequence<Out> out(n, [&](size_t) { return trash; }); 156 Sequence<Out> expected(n, [&](size_t) { return trash; }); 157 158 invoke_on_all_policies(test_transform_scan(), in.begin(), in.end(), out.begin(), out.end(), expected.begin(), 159 expected.end(), in.size(), unary_op, init, binary_op, trash); 160 invoke_on_all_policies(test_transform_scan(), in.cbegin(), in.cend(), out.begin(), out.end(), expected.begin(), 161 expected.end(), in.size(), unary_op, init, binary_op, trash); 162 } 163 } 164 165 int32_t 166 main() 167 { 168 for (int32_t mode = 0; mode < 2; ++mode) 169 { 170 inclusive = mode != 0; 171 #if !__PSTL_ICC_19_TEST_SIMD_UDS_WINDOWS_RELEASE_BROKEN 172 test_matrix<Matrix2x2<int32_t>, Matrix2x2<int32_t>>([](const Matrix2x2<int32_t> x) { return x; }, 173 Matrix2x2<int32_t>(), multiply_matrix<int32_t>, 174 Matrix2x2<int32_t>(-666, 666)); 175 #endif 176 test<int32_t, uint32_t>([](int32_t x) { return x++; }, -123, [](int32_t x, int32_t y) { return x + y; }, 666); 177 } 178 std::cout << done() << std::endl; 179 return 0; 180 } 181