1 // -*- C++ -*- 2 //===-- transform_reduce.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 // UNSUPPORTED: c++03, c++11, c++14 11 12 #include "support/pstl_test_config.h" 13 14 #include <execution> 15 #include <numeric> 16 17 #include "support/utils.h" 18 19 using namespace TestUtils; 20 21 // Functor for xor-operation for modeling binary operations in inner_product 22 class XOR 23 { 24 public: 25 template <typename T> 26 T 27 operator()(const T& left, const T& right) const 28 { 29 return left ^ right; 30 } 31 }; 32 33 // Model of User-defined class 34 class MyClass 35 { 36 public: 37 int32_t my_field; 38 MyClass() { my_field = 0; } 39 MyClass(int32_t in) { my_field = in; } 40 MyClass(const MyClass& in) { my_field = in.my_field; } 41 42 friend MyClass 43 operator+(const MyClass& x, const MyClass& y) 44 { 45 return MyClass(x.my_field + y.my_field); 46 } 47 friend MyClass 48 operator-(const MyClass& x) 49 { 50 return MyClass(-x.my_field); 51 } 52 friend MyClass operator*(const MyClass& x, const MyClass& y) 53 { 54 return MyClass(x.my_field * y.my_field); 55 } 56 friend bool operator==(const MyClass& x, const MyClass& y) 57 { 58 return x.my_field == y.my_field; 59 } 60 }; 61 62 template <typename T> 63 void 64 CheckResults(const T& expected, const T& in) 65 { 66 EXPECT_TRUE(expected == in, "wrong result of transform_reduce"); 67 } 68 69 // We need to check correctness only for "int" (for example) except cases 70 // if we have "floating-point type"-specialization 71 void 72 CheckResults(const float32_t&, const float32_t&) 73 { 74 } 75 76 // Test for different types and operations with different iterators 77 struct test_transform_reduce 78 { 79 template <typename Policy, typename InputIterator1, typename InputIterator2, typename T, typename BinaryOperation1, 80 typename BinaryOperation2, typename UnaryOp> 81 void 82 operator()(Policy&& exec, InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2, 83 T init, BinaryOperation1 opB1, BinaryOperation2 opB2, UnaryOp opU) 84 { 85 86 auto expectedB = std::inner_product(first1, last1, first2, init, opB1, opB2); 87 auto expectedU = transform_reduce_serial(first1, last1, init, opB1, opU); 88 T resRA = std::transform_reduce(exec, first1, last1, first2, init, opB1, opB2); 89 CheckResults(expectedB, resRA); 90 resRA = std::transform_reduce(exec, first1, last1, init, opB1, opU); 91 CheckResults(expectedU, resRA); 92 } 93 }; 94 95 template <typename T, typename BinaryOperation1, typename BinaryOperation2, typename UnaryOp, typename Initializer> 96 void 97 test_by_type(T init, BinaryOperation1 opB1, BinaryOperation2 opB2, UnaryOp opU, Initializer initObj) 98 { 99 100 std::size_t maxSize = 100000; 101 Sequence<T> in1(maxSize, initObj); 102 Sequence<T> in2(maxSize, initObj); 103 104 for (std::size_t n = 0; n < maxSize; n = n < 16 ? n + 1 : size_t(3.1415 * n)) 105 { 106 invoke_on_all_policies(test_transform_reduce(), in1.begin(), in1.begin() + n, in2.begin(), in2.begin() + n, 107 init, opB1, opB2, opU); 108 invoke_on_all_policies(test_transform_reduce(), in1.cbegin(), in1.cbegin() + n, in2.cbegin(), in2.cbegin() + n, 109 init, opB1, opB2, opU); 110 } 111 } 112 113 int 114 main() 115 { 116 test_by_type<int32_t>(42, std::plus<int32_t>(), std::multiplies<int32_t>(), std::negate<int32_t>(), 117 [](std::size_t) -> int32_t { return int32_t(rand() % 1000); }); 118 test_by_type<int64_t>(0, [](const int64_t& a, const int64_t& b) -> int64_t { return a | b; }, XOR(), 119 [](const int64_t& x) -> int64_t { return x * 2; }, 120 [](std::size_t) -> int64_t { return int64_t(rand() % 1000); }); 121 test_by_type<float32_t>( 122 1.0f, std::multiplies<float32_t>(), [](const float32_t& a, const float32_t& b) -> float32_t { return a + b; }, 123 [](const float32_t& x) -> float32_t { return x + 2; }, [](std::size_t) -> float32_t { return rand() % 1000; }); 124 test_by_type<MyClass>(MyClass(), std::plus<MyClass>(), std::multiplies<MyClass>(), std::negate<MyClass>(), 125 [](std::size_t) -> MyClass { return MyClass(rand() % 1000); }); 126 127 std::cout << done() << std::endl; 128 return 0; 129 } 130