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