1 // Copyright (c) 2014-2016 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_minmax.hpp>
9 #include <hpx/util/lightweight_test.hpp>
10 #include <hpx/util/iterator_range.hpp>
11
12 #include <cstddef>
13 #include <ctime>
14 #include <iostream>
15 #include <iterator>
16 #include <string>
17 #include <utility>
18 #include <vector>
19
20 #include "test_utils.hpp"
21
22 ///////////////////////////////////////////////////////////////////////////////
23 template <typename ExPolicy, typename IteratorTag>
test_minmax_element(ExPolicy policy,IteratorTag)24 void test_minmax_element(ExPolicy policy, IteratorTag)
25 {
26 static_assert(
27 hpx::parallel::execution::is_execution_policy<ExPolicy>::value,
28 "hpx::parallel::execution::is_execution_policy<ExPolicy>::value");
29
30 typedef std::vector<std::size_t>::iterator base_iterator;
31 typedef test::test_iterator<base_iterator, IteratorTag> iterator;
32
33 typedef test::test_container<std::vector<std::size_t>, IteratorTag>
34 test_vector;
35
36 test_vector c = test::random_iota<test_vector>(10007);
37
38 base_iterator ref_end(std::end(c.base()));
39
40 auto r = hpx::parallel::minmax_element(policy, c, std::less<std::size_t>());
41 HPX_TEST(r.first != std::end(c) && r.second != std::end(c));
42
43 std::pair<base_iterator, base_iterator> ref = std::minmax_element(
44 std::begin(c.base()), std::end(c.base()), std::less<std::size_t>());
45 HPX_TEST(ref.first != ref_end && ref.second != ref_end);
46
47 HPX_TEST_EQ(*ref.first, *r.first);
48 HPX_TEST_EQ(*ref.second, *r.second);
49
50 r = hpx::parallel::minmax_element(policy, c);
51 HPX_TEST(r.first != std::end(c) && r.second != std::end(c));
52
53 ref = std::minmax_element(std::begin(c.base()), std::end(c.base()));
54 HPX_TEST(ref.first != ref_end && ref.second != ref_end);
55
56 HPX_TEST_EQ(*ref.first, *r.first);
57 HPX_TEST_EQ(*ref.second, *r.second);
58 }
59
60 template <typename ExPolicy, typename IteratorTag>
test_minmax_element_async(ExPolicy p,IteratorTag)61 void test_minmax_element_async(ExPolicy p, IteratorTag)
62 {
63 typedef std::vector<std::size_t>::iterator base_iterator;
64 typedef test::test_iterator<base_iterator, IteratorTag> iterator;
65
66 typedef test::test_container<std::vector<std::size_t>, IteratorTag>
67 test_vector;
68
69 test_vector c = test::random_iota<test_vector>(10007);
70
71 base_iterator ref_end(std::end(c.base()));
72
73 auto r = hpx::parallel::minmax_element(p, c, std::less<std::size_t>());
74 auto rit = r.get();
75 HPX_TEST(rit.first != std::end(c) && rit.second != std::end(c));
76
77 std::pair<base_iterator, base_iterator> ref = std::minmax_element(
78 std::begin(c.base()), std::end(c.base()), std::less<std::size_t>());
79 HPX_TEST(ref.first != ref_end && ref.second != ref_end);
80
81 HPX_TEST_EQ(*ref.first, *rit.first);
82 HPX_TEST_EQ(*ref.second, *rit.second);
83
84 r = hpx::parallel::minmax_element(p, c);
85 rit = r.get();
86 HPX_TEST(rit.first != std::end(c) && rit.second != std::end(c));
87
88 ref = std::minmax_element(std::begin(c.base()), std::end(c.base()));
89 HPX_TEST(ref.first != ref_end && ref.second != ref_end);
90
91 HPX_TEST_EQ(*ref.first, *rit.first);
92 HPX_TEST_EQ(*ref.second, *rit.second);
93 }
94
95 template <typename IteratorTag>
test_minmax_element()96 void test_minmax_element()
97 {
98 using namespace hpx::parallel;
99
100 test_minmax_element(execution::seq, IteratorTag());
101 test_minmax_element(execution::par, IteratorTag());
102 test_minmax_element(execution::par_unseq, IteratorTag());
103
104 test_minmax_element_async(execution::seq(execution::task), IteratorTag());
105 test_minmax_element_async(execution::par(execution::task), IteratorTag());
106 }
107
minmax_element_test()108 void minmax_element_test()
109 {
110 test_minmax_element<std::random_access_iterator_tag>();
111 test_minmax_element<std::forward_iterator_tag>();
112 }
113
114 ///////////////////////////////////////////////////////////////////////////////
115 template <typename ExPolicy, typename IteratorTag>
test_minmax_element_exception(ExPolicy policy,IteratorTag)116 void test_minmax_element_exception(ExPolicy policy, IteratorTag)
117 {
118 static_assert(
119 hpx::parallel::execution::is_execution_policy<ExPolicy>::value,
120 "hpx::parallel::execution::is_execution_policy<ExPolicy>::value");
121
122 typedef std::vector<std::size_t>::iterator base_iterator;
123 typedef test::decorated_iterator<base_iterator, IteratorTag>
124 decorated_iterator;
125
126 std::vector<std::size_t> c = test::random_iota(10007);
127
128 {
129 bool caught_exception = false;
130 try {
131 hpx::parallel::minmax_element(policy,
132 hpx::util::make_iterator_range(
133 decorated_iterator(
134 std::begin(c),
135 [](){ throw std::runtime_error("test"); }),
136 decorated_iterator(std::end(c))),
137 std::less<std::size_t>());
138
139 HPX_TEST(false);
140 }
141 catch(hpx::exception_list const& e) {
142 caught_exception = true;
143 test::test_num_exceptions<ExPolicy, IteratorTag>::call(policy, e);
144 }
145 catch(...) {
146 HPX_TEST(false);
147 }
148 HPX_TEST(caught_exception);
149 }
150
151 {
152 bool caught_exception = false;
153 try {
154 hpx::parallel::minmax_element(policy,
155 hpx::util::make_iterator_range(
156 decorated_iterator(
157 std::begin(c),
158 [](){ throw std::runtime_error("test"); }),
159 decorated_iterator(std::end(c))));
160
161 HPX_TEST(false);
162 }
163 catch(hpx::exception_list const& e) {
164 caught_exception = true;
165 test::test_num_exceptions<ExPolicy, IteratorTag>::call(policy, e);
166 }
167 catch(...) {
168 HPX_TEST(false);
169 }
170 HPX_TEST(caught_exception);
171 }
172 }
173
174 template <typename ExPolicy, typename IteratorTag>
test_minmax_element_exception_async(ExPolicy p,IteratorTag)175 void test_minmax_element_exception_async(ExPolicy p, IteratorTag)
176 {
177 typedef std::vector<std::size_t>::iterator base_iterator;
178 typedef test::decorated_iterator<base_iterator, IteratorTag>
179 decorated_iterator;
180
181 std::vector<std::size_t> c = test::random_iota(10007);
182
183 {
184 bool returned_from_algorithm = false;
185 bool caught_exception = false;
186
187 try {
188 auto f =
189 hpx::parallel::minmax_element(p,
190 hpx::util::make_iterator_range(
191 decorated_iterator(
192 std::begin(c),
193 [](){ throw std::runtime_error("test"); }),
194 decorated_iterator(std::end(c))),
195 std::less<std::size_t>());
196
197 returned_from_algorithm = true;
198
199 f.get();
200
201 HPX_TEST(false);
202 }
203 catch(hpx::exception_list const& e) {
204 caught_exception = true;
205 test::test_num_exceptions<ExPolicy, IteratorTag>::call(p, e);
206 }
207 catch(...) {
208 HPX_TEST(false);
209 }
210
211 HPX_TEST(caught_exception);
212 HPX_TEST(returned_from_algorithm);
213 }
214
215 {
216 bool caught_exception = false;
217 bool returned_from_algorithm = false;
218
219 try {
220 auto f =
221 hpx::parallel::minmax_element(p,
222 hpx::util::make_iterator_range(
223 decorated_iterator(
224 std::begin(c),
225 [](){ throw std::runtime_error("test"); }),
226 decorated_iterator(std::end(c))));
227
228 returned_from_algorithm = true;
229
230 f.get();
231
232 HPX_TEST(false);
233 }
234 catch(hpx::exception_list const& e) {
235 caught_exception = true;
236 test::test_num_exceptions<ExPolicy, IteratorTag>::call(p, e);
237 }
238 catch(...) {
239 HPX_TEST(false);
240 }
241
242 HPX_TEST(caught_exception);
243 HPX_TEST(returned_from_algorithm);
244 }
245 }
246
247 template <typename IteratorTag>
test_minmax_element_exception()248 void test_minmax_element_exception()
249 {
250 using namespace hpx::parallel;
251
252 // If the execution policy object is of type vector_execution_policy,
253 // std::terminate shall be called. therefore we do not test exceptions
254 // with a vector execution policy
255 test_minmax_element_exception(execution::seq, IteratorTag());
256 test_minmax_element_exception(execution::par, IteratorTag());
257
258 test_minmax_element_exception_async(execution::seq(execution::task),
259 IteratorTag());
260 test_minmax_element_exception_async(execution::par(execution::task),
261 IteratorTag());
262 }
263
minmax_element_exception_test()264 void minmax_element_exception_test()
265 {
266 test_minmax_element_exception<std::random_access_iterator_tag>();
267 test_minmax_element_exception<std::forward_iterator_tag>();
268 }
269
270 ///////////////////////////////////////////////////////////////////////////////
271 template <typename ExPolicy, typename IteratorTag>
test_minmax_element_bad_alloc(ExPolicy policy,IteratorTag)272 void test_minmax_element_bad_alloc(ExPolicy policy, IteratorTag)
273 {
274 static_assert(
275 hpx::parallel::execution::is_execution_policy<ExPolicy>::value,
276 "hpx::parallel::execution::is_execution_policy<ExPolicy>::value");
277
278 typedef std::vector<std::size_t>::iterator base_iterator;
279 typedef test::decorated_iterator<base_iterator, IteratorTag>
280 decorated_iterator;
281
282 std::vector<std::size_t> c = test::random_iota(10007);
283
284 {
285 bool caught_exception = false;
286 try {
287 hpx::parallel::minmax_element(policy,
288 hpx::util::make_iterator_range(
289 decorated_iterator(
290 std::begin(c),
291 [](){ throw std::bad_alloc(); }),
292 decorated_iterator(std::end(c))),
293 std::less<std::size_t>());
294
295 HPX_TEST(false);
296 }
297 catch(std::bad_alloc const&) {
298 caught_exception = true;
299 }
300 catch(...) {
301 HPX_TEST(false);
302 }
303 HPX_TEST(caught_exception);
304 }
305
306 {
307 bool caught_exception = false;
308 try {
309 hpx::parallel::minmax_element(policy,
310 hpx::util::make_iterator_range(
311 decorated_iterator(
312 std::begin(c),
313 [](){ throw std::bad_alloc(); }),
314 decorated_iterator(std::end(c))));
315
316 HPX_TEST(false);
317 }
318 catch(std::bad_alloc const&) {
319 caught_exception = true;
320 }
321 catch(...) {
322 HPX_TEST(false);
323 }
324 HPX_TEST(caught_exception);
325 }
326 }
327
328 template <typename ExPolicy, typename IteratorTag>
test_minmax_element_bad_alloc_async(ExPolicy p,IteratorTag)329 void test_minmax_element_bad_alloc_async(ExPolicy p, IteratorTag)
330 {
331 typedef std::vector<std::size_t>::iterator base_iterator;
332 typedef test::decorated_iterator<base_iterator, IteratorTag>
333 decorated_iterator;
334
335 std::vector<std::size_t> c = test::random_iota(10007);
336
337 {
338 bool returned_from_algorithm = false;
339 bool caught_exception = false;
340
341 try {
342 auto f =
343 hpx::parallel::minmax_element(p,
344 hpx::util::make_iterator_range(
345 decorated_iterator(
346 std::begin(c),
347 [](){ throw std::bad_alloc(); }),
348 decorated_iterator(std::end(c))),
349 std::less<std::size_t>());
350
351 returned_from_algorithm = true;
352
353 f.get();
354
355 HPX_TEST(false);
356 }
357 catch(std::bad_alloc const&) {
358 caught_exception = true;
359 }
360 catch(...) {
361 HPX_TEST(false);
362 }
363
364 HPX_TEST(caught_exception);
365 HPX_TEST(returned_from_algorithm);
366 }
367
368 {
369 bool caught_exception = false;
370 bool returned_from_algorithm = false;
371
372 try {
373 auto f =
374 hpx::parallel::minmax_element(p,
375 hpx::util::make_iterator_range(
376 decorated_iterator(
377 std::begin(c),
378 [](){ throw std::bad_alloc(); }),
379 decorated_iterator(std::end(c))));
380
381 returned_from_algorithm = true;
382
383 f.get();
384
385 HPX_TEST(false);
386 }
387 catch(std::bad_alloc const&) {
388 caught_exception = true;
389 }
390 catch(...) {
391 HPX_TEST(false);
392 }
393
394 HPX_TEST(caught_exception);
395 HPX_TEST(returned_from_algorithm);
396 }
397 }
398
399 template <typename IteratorTag>
test_minmax_element_bad_alloc()400 void test_minmax_element_bad_alloc()
401 {
402 using namespace hpx::parallel;
403
404 // If the execution policy object is of type vector_execution_policy,
405 // std::terminate shall be called. therefore we do not test exceptions
406 // with a vector execution policy
407 test_minmax_element_bad_alloc(execution::seq, IteratorTag());
408 test_minmax_element_bad_alloc(execution::par, IteratorTag());
409
410 test_minmax_element_bad_alloc_async(execution::seq(execution::task),
411 IteratorTag());
412 test_minmax_element_bad_alloc_async(execution::par(execution::task),
413 IteratorTag());
414 }
415
minmax_element_bad_alloc_test()416 void minmax_element_bad_alloc_test()
417 {
418 test_minmax_element_bad_alloc<std::random_access_iterator_tag>();
419 test_minmax_element_bad_alloc<std::forward_iterator_tag>();
420 }
421
422 ///////////////////////////////////////////////////////////////////////////////
hpx_main(boost::program_options::variables_map & vm)423 int hpx_main(boost::program_options::variables_map& vm)
424 {
425 unsigned int seed = (unsigned int)std::time(nullptr);
426 if (vm.count("seed"))
427 seed = vm["seed"].as<unsigned int>();
428
429 std::cout << "using seed: " << seed << std::endl;
430 std::srand(seed);
431
432 minmax_element_test();
433 minmax_element_exception_test();
434 minmax_element_bad_alloc_test();
435
436 return hpx::finalize();
437 }
438
main(int argc,char * argv[])439 int main(int argc, char* argv[])
440 {
441 // add command line option which controls the random number generator seed
442 using namespace boost::program_options;
443 options_description desc_commandline(
444 "Usage: " HPX_APPLICATION_STRING " [options]");
445
446 desc_commandline.add_options()
447 ("seed,s", value<unsigned int>(),
448 "the random number generator seed to use for this run")
449 ;
450
451 // By default this test should run on all available cores
452 std::vector<std::string> const cfg = {
453 "hpx.os_threads=all"
454 };
455
456 // Initialize and run HPX
457 HPX_TEST_EQ_MSG(hpx::init(desc_commandline, argc, argv, cfg), 0,
458 "HPX main exited with non-zero status");
459
460 return hpx::util::report_errors();
461 }
462
463
464