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