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