1 // Copyright (c) 2007-2014 Hartmut Kaiser
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6 #include <hpx/hpx_init.hpp>
7 #include <hpx/hpx.hpp>
8 #include <hpx/include/parallel_rotate.hpp>
9 #include <hpx/util/lightweight_test.hpp>
10
11 #include <cstddef>
12 #include <iostream>
13 #include <iterator>
14 #include <numeric>
15 #include <string>
16 #include <vector>
17
18 #include "test_utils.hpp"
19
20 ///////////////////////////////////////////////////////////////////////////////
21 template <typename ExPolicy, typename IteratorTag>
test_rotate(ExPolicy policy,IteratorTag)22 void test_rotate(ExPolicy policy, IteratorTag)
23 {
24 static_assert(
25 hpx::parallel::execution::is_execution_policy<ExPolicy>::value,
26 "hpx::parallel::execution::is_execution_policy<ExPolicy>::value");
27
28 typedef std::vector<std::size_t>::iterator base_iterator;
29 typedef test::test_iterator<base_iterator, IteratorTag> iterator;
30
31 std::vector<std::size_t> c(10007);
32 std::vector<std::size_t> d1;
33
34 std::iota(std::begin(c), std::end(c), std::rand());
35 std::copy(std::begin(c), std::end(c), std::back_inserter(d1));
36
37 std::size_t mid_pos = std::rand() % c.size(); //-V104
38 base_iterator mid = std::begin(c);
39 std::advance(mid, mid_pos);
40
41 hpx::parallel::rotate(policy,
42 iterator(std::begin(c)), iterator(mid), iterator(std::end(c)));
43
44 base_iterator mid1 = std::begin(d1);
45 std::advance(mid1, mid_pos);
46 std::rotate(std::begin(d1), mid1, std::end(d1));
47
48 std::size_t count = 0;
49 HPX_TEST(std::equal(std::begin(c), std::end(c), std::begin(d1),
50 [&count](std::size_t v1, std::size_t v2) -> bool {
51 HPX_TEST_EQ(v1, v2);
52 ++count;
53 return v1 == v2;
54 }));
55 HPX_TEST_EQ(count, d1.size());
56 }
57
58 template <typename ExPolicy, typename IteratorTag>
test_rotate_async(ExPolicy p,IteratorTag)59 void test_rotate_async(ExPolicy p, IteratorTag)
60 {
61 typedef std::vector<std::size_t>::iterator base_iterator;
62 typedef test::test_iterator<base_iterator, IteratorTag> iterator;
63
64 std::vector<std::size_t> c(10007);
65 std::vector<std::size_t> d1;
66
67 std::iota(std::begin(c), std::end(c), std::rand());
68 std::copy(std::begin(c), std::end(c), std::back_inserter(d1));
69
70 std::size_t mid_pos = std::rand() % c.size(); //-V104
71
72 base_iterator mid = std::begin(c);
73 std::advance(mid, mid_pos);
74
75 auto f =
76 hpx::parallel::rotate(p,
77 iterator(std::begin(c)), iterator(mid),
78 iterator(std::end(c)));
79 f.wait();
80
81 base_iterator mid1 = std::begin(d1);
82 std::advance(mid1, mid_pos);
83 std::rotate(std::begin(d1), mid1, std::end(d1));
84
85 std::size_t count = 0;
86 HPX_TEST(std::equal(std::begin(c), std::end(c), std::begin(d1),
87 [&count](std::size_t v1, std::size_t v2) -> bool {
88 HPX_TEST_EQ(v1, v2);
89 ++count;
90 return v1 == v2;
91 }));
92 HPX_TEST_EQ(count, d1.size());
93 }
94
95 template <typename IteratorTag>
test_rotate()96 void test_rotate()
97 {
98 using namespace hpx::parallel;
99 test_rotate(execution::seq, IteratorTag());
100 test_rotate(execution::par, IteratorTag());
101 test_rotate(execution::par_unseq, IteratorTag());
102
103 test_rotate_async(execution::seq(execution::task), IteratorTag());
104 test_rotate_async(execution::par(execution::task), IteratorTag());
105 }
106
rotate_test()107 void rotate_test()
108 {
109 test_rotate<std::random_access_iterator_tag>();
110 test_rotate<std::forward_iterator_tag>();
111 }
112
113 ///////////////////////////////////////////////////////////////////////////////
114 template <typename ExPolicy, typename IteratorTag>
test_rotate_exception(ExPolicy policy,IteratorTag)115 void test_rotate_exception(ExPolicy policy, IteratorTag)
116 {
117 static_assert(
118 hpx::parallel::execution::is_execution_policy<ExPolicy>::value,
119 "hpx::parallel::execution::is_execution_policy<ExPolicy>::value");
120
121 typedef std::vector<std::size_t>::iterator base_iterator;
122 typedef test::decorated_iterator<base_iterator, IteratorTag>
123 decorated_iterator;
124
125 std::vector<std::size_t> c(10007);
126 std::iota(std::begin(c), std::end(c), std::rand());
127
128 base_iterator mid = std::begin(c);
129
130 // move at least one element to guarantee an exception to be thrown
131 std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104
132 std::advance(mid, delta);
133
134 bool caught_exception = false;
135 try {
136 hpx::parallel::rotate(policy,
137 decorated_iterator(
138 std::begin(c),
139 [](){ throw std::runtime_error("test"); }),
140 decorated_iterator(mid),
141 decorated_iterator(std::end(c)));
142 HPX_TEST(false);
143 }
144 catch (hpx::exception_list const& e) {
145 caught_exception = true;
146 test::test_num_exceptions<ExPolicy, IteratorTag>::call(policy, e);
147 }
148 catch (...) {
149 HPX_TEST(false);
150 }
151
152 HPX_TEST(caught_exception);
153 }
154
155 template <typename ExPolicy, typename IteratorTag>
test_rotate_exception_async(ExPolicy p,IteratorTag)156 void test_rotate_exception_async(ExPolicy p, IteratorTag)
157 {
158 typedef std::vector<std::size_t>::iterator base_iterator;
159 typedef test::decorated_iterator<base_iterator, IteratorTag>
160 decorated_iterator;
161
162 std::vector<std::size_t> c(10007);
163 std::iota(std::begin(c), std::end(c), std::rand());
164
165 base_iterator mid = std::begin(c);
166
167 // move at least one element to guarantee an exception to be thrown
168 std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104
169 std::advance(mid, delta);
170
171 bool caught_exception = false;
172 bool returned_from_algorithm = false;
173 try {
174 hpx::future<void> f =
175 hpx::parallel::rotate(p,
176 decorated_iterator(
177 std::begin(c),
178 [](){ throw std::runtime_error("test"); }),
179 decorated_iterator(mid),
180 decorated_iterator(std::end(c)));
181 returned_from_algorithm = true;
182 f.get();
183
184 HPX_TEST(false);
185 }
186 catch (hpx::exception_list const& e) {
187 caught_exception = true;
188 test::test_num_exceptions<ExPolicy, IteratorTag>::call(p, e);
189 }
190 catch (...) {
191 HPX_TEST(false);
192 }
193
194 HPX_TEST(caught_exception);
195 HPX_TEST(returned_from_algorithm);
196 }
197
198 template <typename IteratorTag>
test_rotate_exception()199 void test_rotate_exception()
200 {
201 using namespace hpx::parallel;
202
203 // If the execution policy object is of type vector_execution_policy,
204 // std::terminate shall be called. therefore we do not test exceptions
205 // with a vector execution policy
206 test_rotate_exception(execution::seq, IteratorTag());
207 test_rotate_exception(execution::par, IteratorTag());
208
209 test_rotate_exception_async(execution::seq(execution::task), IteratorTag());
210 test_rotate_exception_async(execution::par(execution::task), IteratorTag());
211 }
212
rotate_exception_test()213 void rotate_exception_test()
214 {
215 test_rotate_exception<std::random_access_iterator_tag>();
216 test_rotate_exception<std::forward_iterator_tag>();
217 }
218
219 //////////////////////////////////////////////////////////////////////////////
220 template <typename ExPolicy, typename IteratorTag>
test_rotate_bad_alloc(ExPolicy policy,IteratorTag)221 void test_rotate_bad_alloc(ExPolicy policy, IteratorTag)
222 {
223 static_assert(
224 hpx::parallel::execution::is_execution_policy<ExPolicy>::value,
225 "hpx::parallel::execution::is_execution_policy<ExPolicy>::value");
226
227 typedef std::vector<std::size_t>::iterator base_iterator;
228 typedef test::decorated_iterator<base_iterator, IteratorTag>
229 decorated_iterator;
230
231 std::vector<std::size_t> c(10007);
232 std::iota(std::begin(c), std::end(c), std::rand());
233
234 base_iterator mid = std::begin(c);
235
236 // move at least one element to guarantee an exception to be thrown
237 std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104
238 std::advance(mid, delta);
239
240 bool caught_bad_alloc = false;
241 try {
242 hpx::parallel::rotate(policy,
243 decorated_iterator(
244 std::begin(c),
245 [](){ throw std::bad_alloc(); }),
246 decorated_iterator(mid),
247 decorated_iterator(std::end(c)));
248 HPX_TEST(false);
249 }
250 catch (std::bad_alloc const&) {
251 caught_bad_alloc = true;
252 }
253 catch (...) {
254 HPX_TEST(false);
255 }
256
257 HPX_TEST(caught_bad_alloc);
258 }
259
260 template <typename ExPolicy, typename IteratorTag>
test_rotate_bad_alloc_async(ExPolicy p,IteratorTag)261 void test_rotate_bad_alloc_async(ExPolicy p, IteratorTag)
262 {
263 typedef std::vector<std::size_t>::iterator base_iterator;
264 typedef test::decorated_iterator<base_iterator, IteratorTag>
265 decorated_iterator;
266
267 std::vector<std::size_t> c(10007);
268 std::iota(std::begin(c), std::end(c), std::rand());
269
270 base_iterator mid = std::begin(c);
271
272 // move at least one element to guarantee an exception to be thrown
273 std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104
274 std::advance(mid, delta);
275
276 bool caught_bad_alloc = false;
277 bool returned_from_algorithm = false;
278 try {
279 hpx::future<void> f =
280 hpx::parallel::rotate(p,
281 decorated_iterator(
282 std::begin(c),
283 [](){ throw std::bad_alloc(); }),
284 decorated_iterator(mid),
285 decorated_iterator(std::end(c)));
286 returned_from_algorithm = true;
287 f.get();
288
289 HPX_TEST(false);
290 }
291 catch(std::bad_alloc const&) {
292 caught_bad_alloc = true;
293 }
294 catch(...) {
295 HPX_TEST(false);
296 }
297
298 HPX_TEST(caught_bad_alloc);
299 HPX_TEST(returned_from_algorithm);
300 }
301
302 template <typename IteratorTag>
test_rotate_bad_alloc()303 void test_rotate_bad_alloc()
304 {
305 using namespace hpx::parallel;
306
307 // If the execution policy object is of type vector_execution_policy,
308 // std::terminate shall be called. therefore we do not test exceptions
309 // with a vector execution policy
310 test_rotate_bad_alloc(execution::seq, IteratorTag());
311 test_rotate_bad_alloc(execution::par, IteratorTag());
312
313 test_rotate_bad_alloc_async(execution::seq(execution::task), IteratorTag());
314 test_rotate_bad_alloc_async(execution::par(execution::task), IteratorTag());
315 }
316
rotate_bad_alloc_test()317 void rotate_bad_alloc_test()
318 {
319 test_rotate_bad_alloc<std::random_access_iterator_tag>();
320 test_rotate_bad_alloc<std::forward_iterator_tag>();
321 }
322
hpx_main(boost::program_options::variables_map & vm)323 int hpx_main(boost::program_options::variables_map& vm)
324 {
325 unsigned int seed = (unsigned int)std::time(nullptr);
326 if (vm.count("seed"))
327 seed = vm["seed"].as<unsigned int>();
328
329 std::cout << "using seed: " << seed << std::endl;
330 std::srand(seed);
331
332 rotate_test();
333 rotate_exception_test();
334 rotate_bad_alloc_test();
335 return hpx::finalize();
336 }
337
main(int argc,char * argv[])338 int main(int argc, char* argv[])
339 {
340 // add command line option which controls the random number generator seed
341 using namespace boost::program_options;
342 options_description desc_commandline(
343 "Usage: " HPX_APPLICATION_STRING " [options]");
344
345 desc_commandline.add_options()
346 ("seed,s", value<unsigned int>(),
347 "the random number generator seed to use for this run")
348 ;
349
350 // By default this test should run on all available cores
351 std::vector<std::string> const cfg = {
352 "hpx.os_threads=all"
353 };
354
355 // Initialize and run HPX
356 HPX_TEST_EQ_MSG(hpx::init(desc_commandline, argc, argv, cfg), 0,
357 "HPX main exited with non-zero status");
358
359 return hpx::util::report_errors();
360
361 }
362