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