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) = default; |
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>(init: 42, opB1: std::plus<int32_t>(), opB2: std::multiplies<int32_t>(), opU: std::negate<int32_t>(), |
117 | initObj: [](std::size_t) -> int32_t { return int32_t(rand() % 1000); }); |
118 | test_by_type<int64_t>(init: 0, opB1: [](const int64_t& a, const int64_t& b) -> int64_t { return a | b; }, opB2: XOR(), |
119 | opU: [](const int64_t& x) -> int64_t { return x * 2; }, |
120 | initObj: [](std::size_t) -> int64_t { return int64_t(rand() % 1000); }); |
121 | test_by_type<float32_t>( |
122 | init: 1.0f, opB1: std::multiplies<float32_t>(), opB2: [](const float32_t& a, const float32_t& b) -> float32_t { return a + b; }, |
123 | opU: [](const float32_t& x) -> float32_t { return x + 2; }, initObj: [](std::size_t) -> float32_t { return rand() % 1000; }); |
124 | test_by_type<MyClass>(init: MyClass(), opB1: std::plus<MyClass>(), opB2: std::multiplies<MyClass>(), opU: std::negate<MyClass>(), |
125 | initObj: [](std::size_t) -> MyClass { return MyClass(rand() % 1000); }); |
126 | |
127 | std::cout << done() << std::endl; |
128 | return 0; |
129 | } |
130 | |