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