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