1 | // -*- C++ -*- |
2 | //===-- rotate.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 <iterator> |
15 | #include <execution> |
16 | #include <algorithm> |
17 | |
18 | #include "support/utils.h" |
19 | |
20 | using namespace TestUtils; |
21 | |
22 | template <typename T> |
23 | struct wrapper |
24 | { |
25 | T t; |
26 | int move_count; |
27 | explicit wrapper(T t_) : t(t_), move_count(0) {} |
28 | wrapper& |
29 | operator=(const T& t_) |
30 | { |
31 | t = t_; |
32 | return *this; |
33 | } |
34 | |
35 | wrapper(const wrapper<T>& a) : move_count(0) { t = a.t; } |
36 | |
37 | wrapper<T>& |
38 | operator=(wrapper<T>& a) |
39 | { |
40 | t = a.t; |
41 | return *this; |
42 | } |
43 | |
44 | wrapper<T>& |
45 | operator=(wrapper<T>&& a) |
46 | { |
47 | t = a.t; |
48 | move_count += 1; |
49 | return *this; |
50 | } |
51 | }; |
52 | |
53 | template <typename T> |
54 | struct compare |
55 | { |
56 | bool |
57 | operator()(const T& a, const T& b) |
58 | { |
59 | return a == b; |
60 | } |
61 | }; |
62 | |
63 | template <typename T> |
64 | struct compare<wrapper<T>> |
65 | { |
66 | bool |
67 | operator()(const wrapper<T>& a, const wrapper<T>& b) |
68 | { |
69 | return a.t == b.t; |
70 | } |
71 | }; |
72 | #include <typeinfo> |
73 | |
74 | struct test_one_policy |
75 | { |
76 | |
77 | #if defined(_PSTL_ICC_17_VC141_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN) || \ |
78 | defined(_PSTL_ICC_16_VC14_TEST_SIMD_LAMBDA_DEBUG_32_BROKEN) // dummy specializations to skip testing in case of broken configuration |
79 | template <typename Iterator, typename Size> |
80 | void |
81 | operator()(pstl::execution::unsequenced_policy, Iterator data_b, Iterator data_e, Iterator actual_b, |
82 | Iterator actual_e, Size shift) |
83 | { |
84 | } |
85 | template <typename Iterator, typename Size> |
86 | void |
87 | operator()(pstl::execution::parallel_unsequenced_policy, Iterator data_b, Iterator data_e, Iterator actual_b, |
88 | Iterator actual_e, Size shift) |
89 | { |
90 | } |
91 | #endif |
92 | |
93 | template <typename ExecutionPolicy, typename Iterator, typename Size> |
94 | void |
95 | operator()(ExecutionPolicy&& exec, Iterator data_b, Iterator data_e, Iterator actual_b, Iterator actual_e, |
96 | Size shift) |
97 | { |
98 | using namespace std; |
99 | using T = typename iterator_traits<Iterator>::value_type; |
100 | Iterator actual_m = std::next(actual_b, shift); |
101 | |
102 | copy(data_b, data_e, actual_b); |
103 | Iterator actual_return = rotate(exec, actual_b, actual_m, actual_e); |
104 | |
105 | EXPECT_TRUE(actual_return == std::next(actual_b, std::distance(actual_m, actual_e)), "wrong result of rotate" ); |
106 | auto comparator = compare<T>(); |
107 | bool check = std::equal(actual_return, actual_e, data_b, comparator); |
108 | check = check && std::equal(actual_b, actual_return, std::next(data_b, shift), comparator); |
109 | |
110 | EXPECT_TRUE(check, "wrong effect of rotate" ); |
111 | EXPECT_TRUE(check_move(exec, actual_b, actual_e, shift), "wrong move test of rotate" ); |
112 | } |
113 | |
114 | template <typename ExecutionPolicy, typename Iterator, typename Size> |
115 | typename std::enable_if< |
116 | is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value && |
117 | !std::is_same<ExecutionPolicy, std::execution::sequenced_policy>::value && |
118 | std::is_same<typename std::iterator_traits<Iterator>::value_type, wrapper<float32_t>>::value, |
119 | bool>::type |
120 | check_move(ExecutionPolicy&&, Iterator b, Iterator e, Size shift) |
121 | { |
122 | bool result = all_of(b, e, [](wrapper<float32_t>& a) { |
123 | bool temp = a.move_count > 0; |
124 | a.move_count = 0; |
125 | return temp; |
126 | }); |
127 | return shift == 0 || result; |
128 | } |
129 | |
130 | template <typename ExecutionPolicy, typename Iterator, typename Size> |
131 | typename std::enable_if< |
132 | !(is_same_iterator_category<Iterator, std::random_access_iterator_tag>::value && |
133 | !std::is_same<ExecutionPolicy, std::execution::sequenced_policy>::value && |
134 | std::is_same<typename std::iterator_traits<Iterator>::value_type, wrapper<float32_t>>::value), |
135 | bool>::type |
136 | check_move(ExecutionPolicy&&, Iterator, Iterator, Size) |
137 | { |
138 | return true; |
139 | } |
140 | }; |
141 | |
142 | template <typename T> |
143 | void |
144 | test() |
145 | { |
146 | const int32_t max_len = 100000; |
147 | |
148 | Sequence<T> actual(max_len, [](std::size_t i) { return T(i); }); |
149 | Sequence<T> data(max_len, [](std::size_t i) { return T(i); }); |
150 | |
151 | for (int32_t len = 0; len < max_len; len = len <= 16 ? len + 1 : int32_t(3.1415 * len)) |
152 | { |
153 | int32_t shifts[] = {0, 1, 2, len / 3, (2 * len) / 3, len - 1}; |
154 | for (auto shift : shifts) |
155 | { |
156 | if (shift >= 0 && shift < len) |
157 | { |
158 | invoke_on_all_policies(test_one_policy(), data.begin(), data.begin() + len, actual.begin(), |
159 | actual.begin() + len, shift); |
160 | } |
161 | } |
162 | } |
163 | } |
164 | |
165 | int |
166 | main() |
167 | { |
168 | test<int32_t>(); |
169 | test<wrapper<float64_t>>(); |
170 | test<MemoryChecker>(); |
171 | EXPECT_FALSE(MemoryChecker::alive_objects() < 0, "wrong effect from rotate: number of ctors calls < num of dtors calls" ); |
172 | EXPECT_FALSE(MemoryChecker::alive_objects() > 0, "wrong effect from rotate: number of ctors calls > num of dtors calls" ); |
173 | |
174 | std::cout << done() << std::endl; |
175 | return 0; |
176 | } |
177 | |