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