From 0e7fd09d1873707c0634afa480597d41387a50cf Mon Sep 17 00:00:00 2001 From: Bruno Pitrus Date: Wed, 1 Nov 2017 17:21:22 +0100 Subject: [PATCH] Added projection and range version of all_of, any_of, none_of (see #1668) --- hpx/include/parallel_all_any_none_of.hpp | 1 + hpx/parallel/algorithms/all_any_none.hpp | 150 +++++-- .../container_algorithms/all_any_none.hpp | 276 ++++++++++++ tests/unit/parallel/algorithms/all_of.cpp | 54 ++- tests/unit/parallel/algorithms/any_of.cpp | 54 ++- tests/unit/parallel/algorithms/none_of.cpp | 50 ++- .../container_algorithms/CMakeLists.txt | 3 + .../container_algorithms/all_of_range.cpp | 422 ++++++++++++++++++ .../container_algorithms/any_of_range.cpp | 422 ++++++++++++++++++ .../container_algorithms/none_of_range.cpp | 420 +++++++++++++++++ 10 files changed, 1772 insertions(+), 80 deletions(-) create mode 100644 hpx/parallel/container_algorithms/all_any_none.hpp create mode 100644 tests/unit/parallel/container_algorithms/all_of_range.cpp create mode 100644 tests/unit/parallel/container_algorithms/any_of_range.cpp create mode 100644 tests/unit/parallel/container_algorithms/none_of_range.cpp diff --git a/hpx/include/parallel_all_any_none_of.hpp b/hpx/include/parallel_all_any_none_of.hpp index 8f4559759465..d075146f89b0 100644 --- a/hpx/include/parallel_all_any_none_of.hpp +++ b/hpx/include/parallel_all_any_none_of.hpp @@ -8,6 +8,7 @@ #define HPX_PARALLEL_ALL_ANY_NONE_OF_JUL_07_2014_1246PM #include +#include #endif diff --git a/hpx/parallel/algorithms/all_any_none.hpp b/hpx/parallel/algorithms/all_any_none.hpp index 2fbe98104b28..440036133ea5 100644 --- a/hpx/parallel/algorithms/all_any_none.hpp +++ b/hpx/parallel/algorithms/all_any_none.hpp @@ -15,7 +15,9 @@ #include #include +#include #include +#include #include #include #include @@ -40,19 +42,26 @@ namespace hpx { namespace parallel { inline namespace v1 : none_of::algorithm("none_of") {} - template + template static bool - sequential(ExPolicy, InIter first, InIter last, F && f) + sequential(ExPolicy, InIter first, InIter last, + F && f, Proj && proj) { - return std::none_of(first, last, std::forward(f)); + return std::none_of(first, last, + util::invoke_projected( + std::forward(f), + std::forward(proj) + )); } - template + template static typename util::detail::algorithm_result< ExPolicy, bool >::type parallel(ExPolicy && policy, FwdIter first, FwdIter last, - F && op) + F && op, Proj && proj) { if (first == last) { @@ -63,7 +72,7 @@ namespace hpx { namespace parallel { inline namespace v1 util::cancellation_token<> tok; auto f1 = - [op, tok, policy]( + [op, tok, policy, proj]( FwdIter part_begin, std::size_t part_count ) mutable -> bool { @@ -71,9 +80,9 @@ namespace hpx { namespace parallel { inline namespace v1 util::loop_n( part_begin, part_count, tok, - [&op, &tok](FwdIter const& curr) + [&op, &tok, &proj](FwdIter const& curr) { - if (op(*curr)) + if (op(proj(*curr))) tok.cancel(); }); @@ -115,6 +124,8 @@ namespace hpx { namespace parallel { inline namespace v1 /// (deduced). Unlike its sequential form, the parallel /// overload of \a none_of requires \a F to meet the /// requirements of \a CopyConstructible. + /// \tparam Proj The type of an optional projection function. This + /// defaults to \a util::projection_identity /// /// \param policy The execution policy to use for the scheduling of /// the iterations. @@ -135,6 +146,10 @@ namespace hpx { namespace parallel { inline namespace v1 /// to it. The type \a Type must be such that an object /// of type \a FwdIter can be dereferenced and then /// implicitly converted to Type. + /// \param proj Specifies the function (or function object) which + /// will be invoked for each of the elements as a + /// projection operation before the actual predicate + /// \a is invoked. /// /// The application of function objects in parallel algorithm /// invoked with an execution policy object of type @@ -156,12 +171,18 @@ namespace hpx { namespace parallel { inline namespace v1 /// \a f returns true for no elements in the range, false /// otherwise. It returns true if the range is empty. /// - template - inline typename std::enable_if< - execution::is_execution_policy::value, - typename util::detail::algorithm_result::type - >::type - none_of(ExPolicy && policy, FwdIter first, FwdIter last, F && f) + template ::value && + hpx::traits::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + ExPolicy, F, traits::projected + >::value)> + typename util::detail::algorithm_result::type + none_of(ExPolicy && policy, FwdIter first, FwdIter last, F && f, + Proj && proj = Proj()) { #if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) static_assert( @@ -182,7 +203,7 @@ namespace hpx { namespace parallel { inline namespace v1 return detail::none_of().call( std::forward(policy), is_seq(), - first, last, std::forward(f)); + first, last, std::forward(f), std::forward(proj)); } /////////////////////////////////////////////////////////////////////////// @@ -196,19 +217,26 @@ namespace hpx { namespace parallel { inline namespace v1 : any_of::algorithm("any_of") {} - template + template static bool - sequential(ExPolicy, InIter first, InIter last, F && f) + sequential(ExPolicy, InIter first, InIter last, + F && f, Proj && proj) { - return std::any_of(first, last, std::forward(f)); + return std::any_of(first, last, + util::invoke_projected( + std::forward(f), + std::forward(proj) + )); } - template + template static typename util::detail::algorithm_result< ExPolicy, bool >::type parallel(ExPolicy && policy, FwdIter first, FwdIter last, - F && op) + F && op, Proj && proj) { if (first == last) { @@ -219,7 +247,7 @@ namespace hpx { namespace parallel { inline namespace v1 util::cancellation_token<> tok; auto f1 = - [op, tok, policy]( + [op, tok, policy, proj]( FwdIter part_begin, std::size_t part_count ) mutable -> bool { @@ -227,9 +255,9 @@ namespace hpx { namespace parallel { inline namespace v1 util::loop_n( part_begin, part_count, tok, - [&op, &tok](FwdIter const& curr) + [&op, &tok, &proj](FwdIter const& curr) { - if (op(*curr)) + if (op(proj(*curr))) tok.cancel(); }); @@ -271,6 +299,8 @@ namespace hpx { namespace parallel { inline namespace v1 /// (deduced). Unlike its sequential form, the parallel /// overload of \a any_of requires \a F to meet the /// requirements of \a CopyConstructible. + /// \tparam Proj The type of an optional projection function. This + /// defaults to \a util::projection_identity /// /// \param policy The execution policy to use for the scheduling of /// the iterations. @@ -291,6 +321,10 @@ namespace hpx { namespace parallel { inline namespace v1 /// to it. The type \a Type must be such that an object /// of type \a FwdIter can be dereferenced and then /// implicitly converted to Type. + /// \param proj Specifies the function (or function object) which + /// will be invoked for each of the elements as a + /// projection operation before the actual predicate + /// \a is invoked. /// /// The application of function objects in parallel algorithm /// invoked with an execution policy object of type @@ -312,12 +346,18 @@ namespace hpx { namespace parallel { inline namespace v1 /// \a f returns true for at least one element in the range, /// false otherwise. It returns false if the range is empty. /// - template - inline typename std::enable_if< - execution::is_execution_policy::value, - typename util::detail::algorithm_result::type - >::type - any_of(ExPolicy && policy, FwdIter first, FwdIter last, F && f) + template ::value && + hpx::traits::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + ExPolicy, F, traits::projected + >::value)> + typename util::detail::algorithm_result::type + any_of(ExPolicy && policy, FwdIter first, FwdIter last, F && f, + Proj && proj = Proj()) { #if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) static_assert( @@ -338,7 +378,7 @@ namespace hpx { namespace parallel { inline namespace v1 return detail::any_of().call( std::forward(policy), is_seq(), - first, last, std::forward(f)); + first, last, std::forward(f), std::forward(proj)); } /////////////////////////////////////////////////////////////////////////// @@ -352,18 +392,26 @@ namespace hpx { namespace parallel { inline namespace v1 : all_of::algorithm("all_of") {} - template + template static bool - sequential(ExPolicy, InIter first, InIter last, F && f) + sequential(ExPolicy, InIter first, InIter last, + F && f, Proj && proj) { - return std::all_of(first, last, std::forward(f)); + return std::all_of(first, last, + util::invoke_projected( + std::forward(f), + std::forward(proj) + )); } - template + template static typename util::detail::algorithm_result< ExPolicy, bool >::type - parallel(ExPolicy && policy, FwdIter first, FwdIter last, F && op) + parallel(ExPolicy && policy, FwdIter first, FwdIter last, + F && op, Proj && proj) { if (first == last) { @@ -374,7 +422,7 @@ namespace hpx { namespace parallel { inline namespace v1 util::cancellation_token<> tok; auto f1 = - [op, tok, policy]( + [op, tok, policy, proj]( FwdIter part_begin, std::size_t part_count ) mutable -> bool { @@ -382,9 +430,9 @@ namespace hpx { namespace parallel { inline namespace v1 util::loop_n( part_begin, part_count, tok, - [&op, &tok](FwdIter const& curr) + [&op, &tok, &proj](FwdIter const& curr) { - if (!op(*curr)) + if (!op(proj(*curr))) tok.cancel(); }); @@ -426,6 +474,8 @@ namespace hpx { namespace parallel { inline namespace v1 /// (deduced). Unlike its sequential form, the parallel /// overload of \a all_of requires \a F to meet the /// requirements of \a CopyConstructible. + /// \tparam Proj The type of an optional projection function. This + /// defaults to \a util::projection_identity /// /// \param policy The execution policy to use for the scheduling of /// the iterations. @@ -446,6 +496,10 @@ namespace hpx { namespace parallel { inline namespace v1 /// to it. The type \a Type must be such that an object /// of type \a FwdIter can be dereferenced and then /// implicitly converted to Type. + /// \param proj Specifies the function (or function object) which + /// will be invoked for each of the elements as a + /// projection operation before the actual predicate + /// \a is invoked. /// /// The application of function objects in parallel algorithm /// invoked with an execution policy object of type @@ -467,12 +521,18 @@ namespace hpx { namespace parallel { inline namespace v1 /// \a f returns true for all elements in the range, false /// otherwise. It returns true if the range is empty. /// - template - inline typename std::enable_if< - execution::is_execution_policy::value, - typename util::detail::algorithm_result::type - >::type - all_of(ExPolicy && policy, FwdIter first, FwdIter last, F && f) + template ::value && + hpx::traits::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + ExPolicy, F, traits::projected + >::value)> + typename util::detail::algorithm_result::type + all_of(ExPolicy && policy, FwdIter first, FwdIter last, F && f, + Proj && proj = Proj()) { #if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) static_assert( @@ -493,7 +553,7 @@ namespace hpx { namespace parallel { inline namespace v1 return detail::all_of().call( std::forward(policy), is_seq(), - first, last, std::forward(f)); + first, last, std::forward(f), std::forward(proj)); } }}} diff --git a/hpx/parallel/container_algorithms/all_any_none.hpp b/hpx/parallel/container_algorithms/all_any_none.hpp new file mode 100644 index 000000000000..aa0a1a712140 --- /dev/null +++ b/hpx/parallel/container_algorithms/all_any_none.hpp @@ -0,0 +1,276 @@ +// Copyright (c) 2017 Bruno Pitrus +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/// \file parallel/container_algorithms/all_any_none.hpp + +#if !defined(HPX_PARALLEL_CONTAINER_ALGORITHM_ALL_ANY_NONE_NOV_01_2017_1509PM) +#define HPX_PARALLEL_CONTAINER_ALGORITHM_ALL_ANY_NONE_NOV_01_2017_1509PM + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace hpx { namespace parallel { inline namespace v1 +{ + /////////////////////////////////////////////////////////////////////////// + // none_of + + /// Checks if unary predicate \a f returns true for no elements in the + /// range \a rng. + /// + /// \note Complexity: At most std::distance(begin(rng), end(rng)) + /// applications of the predicate \a f + /// + /// \tparam ExPolicy The type of the execution policy to use (deduced). + /// It describes the manner in which the execution + /// of the algorithm may be parallelized and the manner + /// in which it applies user-provided function objects. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of an input iterator. + /// \tparam F The type of the function/function object to use + /// (deduced). Unlike its sequential form, the parallel + /// overload of \a none_of requires \a F to meet the + /// requirements of \a CopyConstructible. + /// \tparam Proj The type of an optional projection function. This + /// defaults to \a util::projection_identity + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param rng Refers to the sequence of elements the algorithm + /// will be applied to. + /// \param f Specifies the function (or function object) which + /// will be invoked for each of the elements in the + /// sequence specified by [first, last). + /// The signature of this predicate + /// should be equivalent to: + /// \code + /// bool pred(const Type &a); + /// \endcode \n + /// The signature does not need to have const&, but + /// the function must not modify the objects passed + /// to it. The type \a Type must be such that an object + /// of type \a FwdIter can be dereferenced and then + /// implicitly converted to Type. + /// \param proj Specifies the function (or function object) which + /// will be invoked for each of the elements as a + /// projection operation before the actual predicate + /// \a is invoked. + /// + /// The application of function objects in parallel algorithm + /// invoked with an execution policy object of type + /// \a sequenced_policy execute in sequential order in the + /// calling thread. + /// + /// The application of function objects in parallel algorithm + /// invoked with an execution policy object of type + /// \a parallel_policy or \a parallel_task_policy are + /// permitted to execute in an unordered fashion in unspecified + /// threads, and indeterminately sequenced within each thread. + /// + /// \returns The \a none_of algorithm returns a \a hpx::future if + /// the execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and returns \a bool + /// otherwise. + /// The \a none_of algorithm returns true if the unary predicate + /// \a f returns true for no elements in the range, false + /// otherwise. It returns true if the range is empty. + /// + template ::value && + hpx::traits::is_range::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + ExPolicy, F, traits::projected_range + >::value)> + typename util::detail::algorithm_result::type + none_of(ExPolicy && policy, Rng && rng, F && f, + Proj && proj = Proj()) + { + return none_of(std::forward(policy), + hpx::util::begin(rng), hpx::util::end(rng), std::forward(f), + std::forward(proj)); + } + + /////////////////////////////////////////////////////////////////////////// + // any_of + + /// Checks if unary predicate \a f returns true for at least one element + /// in the range \a rng. + /// + /// \note Complexity: At most std::distance(begin(rng), end(rng)) + /// applications of the predicate \a f + /// + /// \tparam ExPolicy The type of the execution policy to use (deduced). + /// It describes the manner in which the execution + /// of the algorithm may be parallelized and the manner + /// in which it applies user-provided function objects. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of an input iterator. + /// \tparam F The type of the function/function object to use + /// (deduced). Unlike its sequential form, the parallel + /// overload of \a none_of requires \a F to meet the + /// requirements of \a CopyConstructible. + /// \tparam Proj The type of an optional projection function. This + /// defaults to \a util::projection_identity + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param rng Refers to the sequence of elements the algorithm + /// will be applied to. + /// \param f Specifies the function (or function object) which + /// will be invoked for each of the elements in the + /// sequence specified by [first, last). + /// The signature of this predicate + /// should be equivalent to: + /// \code + /// bool pred(const Type &a); + /// \endcode \n + /// The signature does not need to have const&, but + /// the function must not modify the objects passed + /// to it. The type \a Type must be such that an object + /// of type \a FwdIter can be dereferenced and then + /// implicitly converted to Type. + /// \param proj Specifies the function (or function object) which + /// will be invoked for each of the elements as a + /// projection operation before the actual predicate + /// \a is invoked. + /// + /// The application of function objects in parallel algorithm + /// invoked with an execution policy object of type + /// \a sequenced_policy execute in sequential order in the + /// calling thread. + /// + /// The application of function objects in parallel algorithm + /// invoked with an execution policy object of type + /// \a parallel_policy or \a parallel_task_policy are + /// permitted to execute in an unordered fashion in unspecified + /// threads, and indeterminately sequenced within each thread. + /// + /// \returns The \a any_of algorithm returns a \a hpx::future if + /// the execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a bool otherwise. + /// The \a any_of algorithm returns true if the unary predicate + /// \a f returns true for at least one element in the range, + /// false otherwise. It returns false if the range is empty. + /// + template ::value && + hpx::traits::is_range::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + ExPolicy, F, traits::projected_range + >::value)> + typename util::detail::algorithm_result::type + any_of(ExPolicy && policy, Rng && rng, F && f, + Proj && proj = Proj()) + { + return any_of(std::forward(policy), + hpx::util::begin(rng), hpx::util::end(rng), std::forward(f), + std::forward(proj)); + } + + /////////////////////////////////////////////////////////////////////////// + // all_of + + /// Checks if unary predicate \a f returns true for all elements in the + /// range \a rng. + /// + /// \note Complexity: At most std::distance(begin(rng), end(rng)) + /// applications of the predicate \a f + /// + /// \tparam ExPolicy The type of the execution policy to use (deduced). + /// It describes the manner in which the execution + /// of the algorithm may be parallelized and the manner + /// in which it applies user-provided function objects. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of an input iterator. + /// \tparam F The type of the function/function object to use + /// (deduced). Unlike its sequential form, the parallel + /// overload of \a none_of requires \a F to meet the + /// requirements of \a CopyConstructible. + /// \tparam Proj The type of an optional projection function. This + /// defaults to \a util::projection_identity + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param rng Refers to the sequence of elements the algorithm + /// will be applied to. + /// \param f Specifies the function (or function object) which + /// will be invoked for each of the elements in the + /// sequence specified by [first, last). + /// The signature of this predicate + /// should be equivalent to: + /// \code + /// bool pred(const Type &a); + /// \endcode \n + /// The signature does not need to have const&, but + /// the function must not modify the objects passed + /// to it. The type \a Type must be such that an object + /// of type \a FwdIter can be dereferenced and then + /// implicitly converted to Type. + /// \param proj Specifies the function (or function object) which + /// will be invoked for each of the elements as a + /// projection operation before the actual predicate + /// \a is invoked. + /// + /// The application of function objects in parallel algorithm + /// invoked with an execution policy object of type + /// \a sequenced_policy execute in sequential order in the + /// calling thread. + /// + /// The application of function objects in parallel algorithm + /// invoked with an execution policy object of type + /// \a parallel_policy or \a parallel_task_policy are + /// permitted to execute in an unordered fashion in unspecified + /// threads, and indeterminately sequenced within each thread. + /// + /// \returns The \a all_of algorithm returns a \a hpx::future if + /// the execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a bool otherwise. + /// The \a all_of algorithm returns true if the unary predicate + /// \a f returns true for all elements in the range, false + /// otherwise. It returns true if the range is empty. + /// + template ::value && + hpx::traits::is_range::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + ExPolicy, F, traits::projected_range + >::value)> + typename util::detail::algorithm_result::type + all_of(ExPolicy && policy, Rng && rng, F && f, + Proj && proj = Proj()) + { + return all_of(std::forward(policy), + hpx::util::begin(rng), hpx::util::end(rng), std::forward(f), + std::forward(proj)); + } + +}}} + +#endif diff --git a/tests/unit/parallel/algorithms/all_of.cpp b/tests/unit/parallel/algorithms/all_of.cpp index bb11facdd30c..109001c0f298 100644 --- a/tests/unit/parallel/algorithms/all_of.cpp +++ b/tests/unit/parallel/algorithms/all_of.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -18,8 +19,9 @@ #include "test_utils.hpp" /////////////////////////////////////////////////////////////////////////////// -template -void test_all_of(ExPolicy policy, IteratorTag) +template +void test_all_of(ExPolicy policy, IteratorTag,Proj proj=Proj()) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -38,21 +40,22 @@ void test_all_of(ExPolicy policy, IteratorTag) iterator(std::begin(c)), iterator(std::end(c)), [](std::size_t v) { return v != 0; - }); + },proj); // verify values bool expected = std::all_of(std::begin(c), std::end(c), - [](std::size_t v) { - return v != 0; + [proj](std::size_t v) { + return proj(v) != 0; }); HPX_TEST_EQ(result, expected); } } -template -void test_all_of_async(ExPolicy p, IteratorTag) +template +void test_all_of_async(ExPolicy p, IteratorTag,Proj proj=Proj()) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; @@ -67,14 +70,14 @@ void test_all_of_async(ExPolicy p, IteratorTag) iterator(std::begin(c)), iterator(std::end(c)), [](std::size_t v) { return v != 0; - }); + },proj); f.wait(); // verify values bool expected = std::all_of(std::begin(c), std::end(c), - [](std::size_t v) { - return v != 0; + [proj](std::size_t v) { + return proj(v) != 0; }); HPX_TEST_EQ(expected, f.get()); @@ -84,22 +87,49 @@ void test_all_of_async(ExPolicy p, IteratorTag) template void test_all_of() { + struct proj + { + //This projection should cause tests to fail if it is not applied + //because it causes predicate to evaluate the opposite + constexpr std::size_t operator()(std::size_t x)const + { + return !static_cast(x); + } + }; using namespace hpx::parallel; test_all_of(execution::seq, IteratorTag()); test_all_of(execution::par, IteratorTag()); test_all_of(execution::par_unseq, IteratorTag()); + test_all_of(execution::seq, IteratorTag(), proj()); + test_all_of(execution::par, IteratorTag(), proj()); + test_all_of(execution::par_unseq, IteratorTag(), proj()); + test_all_of_async(execution::seq(execution::task), IteratorTag()); test_all_of_async(execution::par(execution::task), IteratorTag()); + test_all_of_async(execution::seq(execution::task), IteratorTag(), proj()); + test_all_of_async(execution::par(execution::task), IteratorTag(), proj()); + #if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) test_all_of(execution_policy(execution::seq), IteratorTag()); test_all_of(execution_policy(execution::par), IteratorTag()); test_all_of(execution_policy(execution::par_unseq), IteratorTag()); - test_all_of(execution_policy(execution::seq(execution::task)), IteratorTag()); - test_all_of(execution_policy(execution::par(execution::task)), IteratorTag()); + test_all_of(execution_policy(execution::seq), IteratorTag(), proj()); + test_all_of(execution_policy(execution::par), IteratorTag(), proj()); + test_all_of(execution_policy(execution::par_unseq), IteratorTag(), proj()); + + test_all_of(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_all_of(execution_policy(execution::par(execution::task)), + IteratorTag()); + + test_all_of(execution_policy(execution::seq(execution::task)), + IteratorTag(), proj()); + test_all_of(execution_policy(execution::par(execution::task)), + IteratorTag()), proj(); #endif } diff --git a/tests/unit/parallel/algorithms/any_of.cpp b/tests/unit/parallel/algorithms/any_of.cpp index 2d4a08f46c1f..8d792116df53 100644 --- a/tests/unit/parallel/algorithms/any_of.cpp +++ b/tests/unit/parallel/algorithms/any_of.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -18,8 +19,9 @@ #include "test_utils.hpp" /////////////////////////////////////////////////////////////////////////////// -template -void test_any_of(ExPolicy policy, IteratorTag) +template +void test_any_of(ExPolicy policy, IteratorTag,Proj proj=Proj()) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -38,21 +40,22 @@ void test_any_of(ExPolicy policy, IteratorTag) iterator(std::begin(c)), iterator(std::end(c)), [](std::size_t v) { return v != 0; - }); + },proj); // verify values bool expected = std::any_of(std::begin(c), std::end(c), - [](std::size_t v) { - return v != 0; + [proj](std::size_t v) { + return proj(v) != 0; }); HPX_TEST_EQ(result, expected); } } -template -void test_any_of_async(ExPolicy p, IteratorTag) +template +void test_any_of_async(ExPolicy p, IteratorTag,Proj proj=Proj()) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; @@ -67,14 +70,14 @@ void test_any_of_async(ExPolicy p, IteratorTag) iterator(std::begin(c)), iterator(std::end(c)), [](std::size_t v) { return v != 0; - }); + },proj); f.wait(); // verify values bool expected = std::any_of(std::begin(c), std::end(c), - [](std::size_t v) { - return v != 0; + [proj](std::size_t v) { + return proj(v) != 0; }); HPX_TEST_EQ(expected, f.get()); @@ -84,22 +87,49 @@ void test_any_of_async(ExPolicy p, IteratorTag) template void test_any_of() { + struct proj + { + //This projection should cause tests to fail if it is not applied + //because it causes predicate to evaluate the opposite + constexpr std::size_t operator()(std::size_t x)const + { + return !static_cast(x); + } + }; using namespace hpx::parallel; test_any_of(execution::seq, IteratorTag()); test_any_of(execution::par, IteratorTag()); test_any_of(execution::par_unseq, IteratorTag()); + test_any_of(execution::seq, IteratorTag(), proj()); + test_any_of(execution::par, IteratorTag(), proj()); + test_any_of(execution::par_unseq, IteratorTag(), proj()); + test_any_of_async(execution::seq(execution::task), IteratorTag()); test_any_of_async(execution::par(execution::task), IteratorTag()); + test_any_of_async(execution::seq(execution::task), IteratorTag(), proj()); + test_any_of_async(execution::par(execution::task), IteratorTag(), proj()); + #if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) test_any_of(execution_policy(execution::seq), IteratorTag()); test_any_of(execution_policy(execution::par), IteratorTag()); test_any_of(execution_policy(execution::par_unseq), IteratorTag()); - test_any_of(execution_policy(execution::seq(execution::task)), IteratorTag()); - test_any_of(execution_policy(execution::par(execution::task)), IteratorTag()); + test_any_of(execution_policy(execution::seq), IteratorTag(), proj()); + test_any_of(execution_policy(execution::par), IteratorTag(), proj()); + test_any_of(execution_policy(execution::par_unseq), IteratorTag(), proj()); + + test_any_of(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_any_of(execution_policy(execution::par(execution::task)), + IteratorTag()); + + test_any_of(execution_policy(execution::seq(execution::task)), + IteratorTag(), proj()); + test_any_of(execution_policy(execution::par(execution::task)), + IteratorTag()), proj(); #endif } diff --git a/tests/unit/parallel/algorithms/none_of.cpp b/tests/unit/parallel/algorithms/none_of.cpp index eec69ca4b85d..0b5932b1348e 100644 --- a/tests/unit/parallel/algorithms/none_of.cpp +++ b/tests/unit/parallel/algorithms/none_of.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -17,8 +18,9 @@ #include "test_utils.hpp" /////////////////////////////////////////////////////////////////////////////// -template -void test_none_of(ExPolicy policy, IteratorTag) +template +void test_none_of(ExPolicy policy, IteratorTag,Proj proj=Proj()) { static_assert( hpx::parallel::execution::is_execution_policy::value, @@ -37,21 +39,22 @@ void test_none_of(ExPolicy policy, IteratorTag) iterator(std::begin(c)), iterator(std::end(c)), [](std::size_t v) { return v != 0; - }); + },proj); // verify values bool expected = std::none_of(std::begin(c), std::end(c), - [](std::size_t v) { - return v != 0; + [proj](std::size_t v) { + return proj(v)!= 0; }); HPX_TEST_EQ(result, expected); } } -template -void test_none_of_async(ExPolicy p, IteratorTag) +template +void test_none_of_async(ExPolicy p, IteratorTag,Proj proj=Proj()) { typedef std::vector::iterator base_iterator; typedef test::test_iterator iterator; @@ -64,16 +67,16 @@ void test_none_of_async(ExPolicy p, IteratorTag) hpx::future f = hpx::parallel::none_of(p, iterator(std::begin(c)), iterator(std::end(c)), - [](std::size_t v) { + [proj](std::size_t v) { return v != 0; - }); + },proj); f.wait(); // verify values bool expected = std::none_of(std::begin(c), std::end(c), - [](std::size_t v) { - return v != 0; + [proj](std::size_t v) { + return proj(v) != 0; }); HPX_TEST_EQ(expected, f.get()); @@ -83,24 +86,49 @@ void test_none_of_async(ExPolicy p, IteratorTag) template void test_none_of() { + struct proj + { + //This projection should cause tests to fail if it is not applied + //because it causes predicate to evaluate the opposite + constexpr std::size_t operator()(std::size_t x)const + { + return !static_cast(x); + } + }; using namespace hpx::parallel; test_none_of(execution::seq, IteratorTag()); test_none_of(execution::par, IteratorTag()); test_none_of(execution::par_unseq, IteratorTag()); + test_none_of(execution::seq, IteratorTag(), proj()); + test_none_of(execution::par, IteratorTag(), proj()); + test_none_of(execution::par_unseq, IteratorTag(), proj()); + test_none_of_async(execution::seq(execution::task), IteratorTag()); test_none_of_async(execution::par(execution::task), IteratorTag()); + test_none_of_async(execution::seq(execution::task), IteratorTag(), proj()); + test_none_of_async(execution::par(execution::task), IteratorTag(), proj()); + #if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) test_none_of(execution_policy(execution::seq), IteratorTag()); test_none_of(execution_policy(execution::par), IteratorTag()); test_none_of(execution_policy(execution::par_unseq), IteratorTag()); + test_none_of(execution_policy(execution::seq), IteratorTag(), proj()); + test_none_of(execution_policy(execution::par), IteratorTag(), proj()); + test_none_of(execution_policy(execution::par_unseq), IteratorTag(), proj()); + test_none_of(execution_policy(execution::seq(execution::task)), IteratorTag()); test_none_of(execution_policy(execution::par(execution::task)), IteratorTag()); + + test_none_of(execution_policy(execution::seq(execution::task)), + IteratorTag(), proj()); + test_none_of(execution_policy(execution::par(execution::task)), + IteratorTag()), proj(); #endif } diff --git a/tests/unit/parallel/container_algorithms/CMakeLists.txt b/tests/unit/parallel/container_algorithms/CMakeLists.txt index be18e4993bf5..9e6f23215540 100644 --- a/tests/unit/parallel/container_algorithms/CMakeLists.txt +++ b/tests/unit/parallel/container_algorithms/CMakeLists.txt @@ -4,6 +4,8 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) set(tests + all_of_range + any_of_range copy_range copyif_range foreach_range @@ -15,6 +17,7 @@ set(tests merge_range min_element_range minmax_element_range + none_of_range partition_range partition_copy_range remove_copy_range diff --git a/tests/unit/parallel/container_algorithms/all_of_range.cpp b/tests/unit/parallel/container_algorithms/all_of_range.cpp new file mode 100644 index 000000000000..621544f9311f --- /dev/null +++ b/tests/unit/parallel/container_algorithms/all_of_range.cpp @@ -0,0 +1,422 @@ +// Copyright (c) 2014-2017 Hartmut Kaiser +// 2017 Bruno Pitrus + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +#include "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_all_of(ExPolicy policy, IteratorTag,Proj proj=Proj()) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i: iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool result = + hpx::parallel::all_of(policy, c, + [](std::size_t v) { + return v != 0; + },proj); + + // verify values + bool expected = + std::all_of(std::begin(c), std::end(c), + [proj](std::size_t v) { + return proj(v) != 0; + }); + + HPX_TEST_EQ(result, expected); + } +} + +template +void test_all_of_async(ExPolicy p, IteratorTag,Proj proj=Proj()) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i: iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + hpx::future f = + hpx::parallel::all_of(p, c, + [](std::size_t v) { + return v != 0; + },proj); + f.wait(); + + // verify values + bool expected = + std::all_of(std::begin(c), std::end(c), + [proj](std::size_t v) { + return proj(v) != 0; + }); + + HPX_TEST_EQ(expected, f.get()); + } +} + +template +void test_all_of() +{ + struct proj + { + //This projection should cause tests to fail if it is not applied + //because it causes predicate to evaluate the opposite + constexpr std::size_t operator()(std::size_t x)const + { + return !static_cast(x); + } + }; + using namespace hpx::parallel; + + test_all_of(execution::seq, IteratorTag()); + test_all_of(execution::par, IteratorTag()); + test_all_of(execution::par_unseq, IteratorTag()); + + test_all_of(execution::seq, IteratorTag(), proj()); + test_all_of(execution::par, IteratorTag(), proj()); + test_all_of(execution::par_unseq, IteratorTag(), proj()); + + test_all_of_async(execution::seq(execution::task), IteratorTag()); + test_all_of_async(execution::par(execution::task), IteratorTag()); + + test_all_of_async(execution::seq(execution::task), IteratorTag(), proj()); + test_all_of_async(execution::par(execution::task), IteratorTag(), proj()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_all_of(execution_policy(execution::seq), IteratorTag()); + test_all_of(execution_policy(execution::par), IteratorTag()); + test_all_of(execution_policy(execution::par_unseq), IteratorTag()); + + test_all_of(execution_policy(execution::seq), IteratorTag(), proj()); + test_all_of(execution_policy(execution::par), IteratorTag(), proj()); + test_all_of(execution_policy(execution::par_unseq), IteratorTag(), proj()); + + test_all_of(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_all_of(execution_policy(execution::par(execution::task)), + IteratorTag()); + + test_all_of(execution_policy(execution::seq(execution::task)), + IteratorTag(), proj()); + test_all_of(execution_policy(execution::par(execution::task)), + IteratorTag()), proj(); +#endif +} + +// template +// void test_all_of_exec() +// { +// using namespace hpx::parallel; +// +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_all_of(execution::par(exec), IteratorTag()); +// } +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_all_of(task(exec), IteratorTag()); +// } +// +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_all_of(execution_policy(execution::par(exec)), IteratorTag()); +// } +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_all_of(execution_policy(task(exec)), IteratorTag()); +// } +// } + +void all_of_test() +{ + test_all_of(); + test_all_of(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_all_of(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_all_of_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + try { + hpx::parallel::all_of(policy, c, + [](std::size_t v) { + return throw std::runtime_error("test"), v != 0; + }); + + HPX_TEST(false); + } + catch(hpx::exception_list const& e) { + caught_exception = true; + test::test_num_exceptions::call(policy, e); + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + } +} + +template +void test_all_of_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + hpx::future f = + hpx::parallel::all_of(p, c, + [](std::size_t v) { + return throw std::runtime_error("test"), v != 0; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(hpx::exception_list const& e) { + caught_exception = true; + test::test_num_exceptions::call(p, e); + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); + } +} + +template +void test_all_of_exception() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_all_of_exception(execution::seq, IteratorTag()); + test_all_of_exception(execution::par, IteratorTag()); + + test_all_of_exception_async(execution::seq(execution::task), IteratorTag()); + test_all_of_exception_async(execution::par(execution::task), IteratorTag()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_all_of_exception(execution_policy(execution::seq), IteratorTag()); + test_all_of_exception(execution_policy(execution::par), IteratorTag()); + + test_all_of_exception(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_all_of_exception(execution_policy(execution::par(execution::task)), + IteratorTag()); +#endif +} + +void all_of_exception_test() +{ + test_all_of_exception(); + test_all_of_exception(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_all_of_exception(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_all_of_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + try { + hpx::parallel::all_of(policy, c, + [](std::size_t v) { + return throw std::bad_alloc(), v != 0; + }); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_exception = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + } +} + +template +void test_all_of_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + hpx::future f = + hpx::parallel::all_of(p, c, + [](std::size_t v) { + return throw std::bad_alloc(), v != 0; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_exception = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); + } +} + +template +void test_all_of_bad_alloc() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_all_of_bad_alloc(execution::seq, IteratorTag()); + test_all_of_bad_alloc(execution::par, IteratorTag()); + + test_all_of_bad_alloc_async(execution::seq(execution::task), IteratorTag()); + test_all_of_bad_alloc_async(execution::par(execution::task), IteratorTag()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_all_of_bad_alloc(execution_policy(execution::seq), IteratorTag()); + test_all_of_bad_alloc(execution_policy(execution::par), IteratorTag()); + + test_all_of_bad_alloc(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_all_of_bad_alloc(execution_policy(execution::par(execution::task)), + IteratorTag()); +#endif +} + +void all_of_bad_alloc_test() +{ + test_all_of_bad_alloc(); + test_all_of_bad_alloc(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_all_of_bad_alloc(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + all_of_test(); + all_of_exception_test(); + all_of_bad_alloc_test(); + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace boost::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options() + ("seed,s", value(), + "the random number generator seed to use for this run") + ; + + // By default this test should run on all available cores + std::vector const cfg = { + "hpx.os_threads=all" + }; + + // Initialize and run HPX + HPX_TEST_EQ_MSG(hpx::init(desc_commandline, argc, argv, cfg), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} + + diff --git a/tests/unit/parallel/container_algorithms/any_of_range.cpp b/tests/unit/parallel/container_algorithms/any_of_range.cpp new file mode 100644 index 000000000000..d9203d125293 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/any_of_range.cpp @@ -0,0 +1,422 @@ +// Copyright (c) 2014-2017 Hartmut Kaiser +// 2017 Bruno Pitrus + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +#include "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_any_of(ExPolicy policy, IteratorTag,Proj proj=Proj()) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i: iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool result = + hpx::parallel::any_of(policy, c, + [](std::size_t v) { + return v != 0; + },proj); + + // verify values + bool expected = + std::any_of(std::begin(c), std::end(c), + [proj](std::size_t v) { + return proj(v) != 0; + }); + + HPX_TEST_EQ(result, expected); + } +} + +template +void test_any_of_async(ExPolicy p, IteratorTag,Proj proj=Proj()) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i: iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + hpx::future f = + hpx::parallel::any_of(p, c, + [](std::size_t v) { + return v != 0; + },proj); + f.wait(); + + // verify values + bool expected = + std::any_of(std::begin(c), std::end(c), + [proj](std::size_t v) { + return proj(v) != 0; + }); + + HPX_TEST_EQ(expected, f.get()); + } +} + +template +void test_any_of() +{ + struct proj + { + //This projection should cause tests to fail if it is not applied + //because it causes predicate to evaluate the opposite + constexpr std::size_t operator()(std::size_t x)const + { + return !static_cast(x); + } + }; + using namespace hpx::parallel; + + test_any_of(execution::seq, IteratorTag()); + test_any_of(execution::par, IteratorTag()); + test_any_of(execution::par_unseq, IteratorTag()); + + test_any_of(execution::seq, IteratorTag(), proj()); + test_any_of(execution::par, IteratorTag(), proj()); + test_any_of(execution::par_unseq, IteratorTag(), proj()); + + test_any_of_async(execution::seq(execution::task), IteratorTag()); + test_any_of_async(execution::par(execution::task), IteratorTag()); + + test_any_of_async(execution::seq(execution::task), IteratorTag(), proj()); + test_any_of_async(execution::par(execution::task), IteratorTag(), proj()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_any_of(execution_policy(execution::seq), IteratorTag()); + test_any_of(execution_policy(execution::par), IteratorTag()); + test_any_of(execution_policy(execution::par_unseq), IteratorTag()); + + test_any_of(execution_policy(execution::seq), IteratorTag(), proj()); + test_any_of(execution_policy(execution::par), IteratorTag(), proj()); + test_any_of(execution_policy(execution::par_unseq), IteratorTag(), proj()); + + test_any_of(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_any_of(execution_policy(execution::par(execution::task)), + IteratorTag()); + + test_any_of(execution_policy(execution::seq(execution::task)), + IteratorTag(), proj()); + test_any_of(execution_policy(execution::par(execution::task)), + IteratorTag()), proj(); +#endif +} + +// template +// void test_any_of_exec() +// { +// using namespace hpx::parallel; +// +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_any_of(execution::par(exec), IteratorTag()); +// } +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_any_of(task(exec), IteratorTag()); +// } +// +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_any_of(execution_policy(execution::par(exec)), IteratorTag()); +// } +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_any_of(execution_policy(task(exec)), IteratorTag()); +// } +// } + +void any_of_test() +{ + test_any_of(); + test_any_of(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_any_of(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_any_of_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i: iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + try { + hpx::parallel::any_of(policy, c, + [](std::size_t v) { + return throw std::runtime_error("test"), v != 0; + }); + + HPX_TEST(false); + } + catch(hpx::exception_list const& e) { + caught_exception = true; + test::test_num_exceptions::call(policy, e); + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + } +} + +template +void test_any_of_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + hpx::future f = + hpx::parallel::any_of(p, c, + [](std::size_t v) { + return throw std::runtime_error("test"), v != 0; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(hpx::exception_list const& e) { + caught_exception = true; + test::test_num_exceptions::call(p, e); + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); + } +} + +template +void test_any_of_exception() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_any_of_exception(execution::seq, IteratorTag()); + test_any_of_exception(execution::par, IteratorTag()); + + test_any_of_exception_async(execution::seq(execution::task), IteratorTag()); + test_any_of_exception_async(execution::par(execution::task), IteratorTag()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_any_of_exception(execution_policy(execution::seq), IteratorTag()); + test_any_of_exception(execution_policy(execution::par), IteratorTag()); + + test_any_of_exception(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_any_of_exception(execution_policy(execution::par(execution::task)), + IteratorTag()); +#endif +} + +void any_of_exception_test() +{ + test_any_of_exception(); + test_any_of_exception(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_any_of_exception(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_any_of_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + try { + hpx::parallel::any_of(policy, c, + [](std::size_t v) { + return throw std::bad_alloc(), v != 0; + }); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_exception = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + } +} + +template +void test_any_of_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + hpx::future f = + hpx::parallel::any_of(p, c, + [](std::size_t v) { + return throw std::bad_alloc(), v != 0; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_exception = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); + } +} + +template +void test_any_of_bad_alloc() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_any_of_bad_alloc(execution::seq, IteratorTag()); + test_any_of_bad_alloc(execution::par, IteratorTag()); + + test_any_of_bad_alloc_async(execution::seq(execution::task), IteratorTag()); + test_any_of_bad_alloc_async(execution::par(execution::task), IteratorTag()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_any_of_bad_alloc(execution_policy(execution::seq), IteratorTag()); + test_any_of_bad_alloc(execution_policy(execution::par), IteratorTag()); + + test_any_of_bad_alloc(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_any_of_bad_alloc(execution_policy(execution::par(execution::task)), + IteratorTag()); +#endif +} + +void any_of_bad_alloc_test() +{ + test_any_of_bad_alloc(); + test_any_of_bad_alloc(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_any_of_bad_alloc(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + any_of_test(); + any_of_exception_test(); + any_of_bad_alloc_test(); + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace boost::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options() + ("seed,s", value(), + "the random number generator seed to use for this run") + ; + + // By default this test should run on all available cores + std::vector const cfg = { + "hpx.os_threads=all" + }; + + // Initialize and run HPX + HPX_TEST_EQ_MSG(hpx::init(desc_commandline, argc, argv, cfg), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} + + diff --git a/tests/unit/parallel/container_algorithms/none_of_range.cpp b/tests/unit/parallel/container_algorithms/none_of_range.cpp new file mode 100644 index 000000000000..882f1aae1e07 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/none_of_range.cpp @@ -0,0 +1,420 @@ +// Copyright (c) 2014-2017 Hartmut Kaiser +// 2017 Bruno Pitrus + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_none_of(ExPolicy policy, IteratorTag,Proj proj=Proj()) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 1, 3 }; + for (std::size_t i: iseq) + { + std::vector c = test::fill_all_any_none(3, i); //-V106 + + bool result = + hpx::parallel::none_of(policy, c, + [](std::size_t v) { + return v != 0; + },proj); + + // verify values + bool expected = + std::none_of(std::begin(c), std::end(c), + [proj](std::size_t v) { + return proj(v)!= 0; + }); + + HPX_TEST_EQ(result, expected); + } +} + +template +void test_none_of_async(ExPolicy p, IteratorTag,Proj proj=Proj()) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + hpx::future f = + hpx::parallel::none_of(p, c, + [proj](std::size_t v) { + return v != 0; + },proj); + f.wait(); + + // verify values + bool expected = + std::none_of(std::begin(c), std::end(c), + [proj](std::size_t v) { + return proj(v) != 0; + }); + + HPX_TEST_EQ(expected, f.get()); + } +} + +template +void test_none_of() +{ + struct proj + { + //This projection should cause tests to fail if it is not applied + //because it causes predicate to evaluate the opposite + constexpr std::size_t operator()(std::size_t x)const + { + return !static_cast(x); + } + }; + using namespace hpx::parallel; + + test_none_of(execution::seq, IteratorTag()); + test_none_of(execution::par, IteratorTag()); + test_none_of(execution::par_unseq, IteratorTag()); + + test_none_of(execution::seq, IteratorTag(), proj()); + test_none_of(execution::par, IteratorTag(), proj()); + test_none_of(execution::par_unseq, IteratorTag(), proj()); + + test_none_of_async(execution::seq(execution::task), IteratorTag()); + test_none_of_async(execution::par(execution::task), IteratorTag()); + + test_none_of_async(execution::seq(execution::task), IteratorTag(), proj()); + test_none_of_async(execution::par(execution::task), IteratorTag(), proj()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_none_of(execution_policy(execution::seq), IteratorTag()); + test_none_of(execution_policy(execution::par), IteratorTag()); + test_none_of(execution_policy(execution::par_unseq), IteratorTag()); + + test_none_of(execution_policy(execution::seq), IteratorTag(), proj()); + test_none_of(execution_policy(execution::par), IteratorTag(), proj()); + test_none_of(execution_policy(execution::par_unseq), IteratorTag(), proj()); + + test_none_of(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_none_of(execution_policy(execution::par(execution::task)), + IteratorTag()); + + test_none_of(execution_policy(execution::seq(execution::task)), + IteratorTag(), proj()); + test_none_of(execution_policy(execution::par(execution::task)), + IteratorTag()), proj(); +#endif +} + +// template +// void test_none_of_exec() +// { +// using namespace hpx::parallel; +// +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_none_of(execution::par(exec), IteratorTag()); +// } +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_none_of(task(exec), IteratorTag()); +// } +// +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_none_of(execution_policy(execution::par(exec)), IteratorTag()); +// } +// { +// hpx::threads::executors::local_priority_queue_executor exec; +// test_none_of(execution_policy(task(exec)), IteratorTag()); +// } +// } + +void none_of_test() +{ + test_none_of(); + test_none_of(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_none_of(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_none_of_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + try { + hpx::parallel::none_of(policy, c, + [](std::size_t v) { + return throw std::runtime_error("test"), v != 0; + }); + + HPX_TEST(false); + } + catch(hpx::exception_list const& e) { + caught_exception = true; + test::test_num_exceptions::call(policy, e); + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + } +} + +template +void test_none_of_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + hpx::future f = + hpx::parallel::none_of(p, c, + [](std::size_t v) { + return throw std::runtime_error("test"), v != 0; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(hpx::exception_list const& e) { + caught_exception = true; + test::test_num_exceptions::call(p, e); + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); + } +} + +template +void test_none_of_exception() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_none_of_exception(execution::seq, IteratorTag()); + test_none_of_exception(execution::par, IteratorTag()); + + test_none_of_exception_async(execution::seq(execution::task), IteratorTag()); + test_none_of_exception_async(execution::par(execution::task), IteratorTag()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_none_of_exception(execution_policy(execution::seq), IteratorTag()); + test_none_of_exception(execution_policy(execution::par), IteratorTag()); + + test_none_of_exception(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_none_of_exception(execution_policy(execution::par(execution::task)), + IteratorTag()); +#endif +} + +void none_of_exception_test() +{ + test_none_of_exception(); + test_none_of_exception(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_none_of_exception(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_none_of_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::execution::is_execution_policy::value, + "hpx::parallel::execution::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + try { + hpx::parallel::none_of(policy, c, + [](std::size_t v) { + return throw std::bad_alloc(), v != 0; + }); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_exception = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + } +} + +template +void test_none_of_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::size_t iseq[] = { 0, 23, 10007 }; + for (std::size_t i : iseq) + { + std::vector c = test::fill_all_any_none(10007, i); //-V106 + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + hpx::future f = + hpx::parallel::none_of(p, c, + [](std::size_t v) { + return throw std::bad_alloc(), v != 0; + }); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_exception = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_exception); + HPX_TEST(returned_from_algorithm); + } +} + +template +void test_none_of_bad_alloc() +{ + using namespace hpx::parallel; + + // If the execution policy object is of type vector_execution_policy, + // std::terminate shall be called. therefore we do not test exceptions + // with a vector execution policy + test_none_of_bad_alloc(execution::seq, IteratorTag()); + test_none_of_bad_alloc(execution::par, IteratorTag()); + + test_none_of_bad_alloc_async(execution::seq(execution::task), IteratorTag()); + test_none_of_bad_alloc_async(execution::par(execution::task), IteratorTag()); + +#if defined(HPX_HAVE_GENERIC_EXECUTION_POLICY) + test_none_of_bad_alloc(execution_policy(execution::seq), IteratorTag()); + test_none_of_bad_alloc(execution_policy(execution::par), IteratorTag()); + + test_none_of_bad_alloc(execution_policy(execution::seq(execution::task)), + IteratorTag()); + test_none_of_bad_alloc(execution_policy(execution::par(execution::task)), + IteratorTag()); +#endif +} + +void none_of_bad_alloc_test() +{ + test_none_of_bad_alloc(); + test_none_of_bad_alloc(); +#if defined(HPX_HAVE_ALGORITHM_INPUT_ITERATOR_SUPPORT) + test_none_of_bad_alloc(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////// +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(nullptr); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + none_of_test(); + none_of_exception_test(); + none_of_bad_alloc_test(); + return hpx::finalize(); +} + +int main(int argc, char* argv[]) +{ + // add command line option which controls the random number generator seed + using namespace boost::program_options; + options_description desc_commandline( + "Usage: " HPX_APPLICATION_STRING " [options]"); + + desc_commandline.add_options() + ("seed,s", value(), + "the random number generator seed to use for this run") + ; + // By default this test should run on all available cores + std::vector const cfg = { + "hpx.os_threads=all" + }; + + // Initialize and run HPX + HPX_TEST_EQ_MSG(hpx::init(desc_commandline, argc, argv, cfg), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} + +