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