diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 4b884f8e48f4..404816a1fe44 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -98,6 +98,10 @@ set(doxygen_dependencies "${PROJECT_SOURCE_DIR}/hpx/parallel/algorithms/uninitialized_fill.hpp" "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/copy.hpp" "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/for_each.hpp" + "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/remove_copy.hpp" + "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/replace.hpp" + "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/reverse.hpp" + "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/rotate.hpp" "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/sort.hpp" "${PROJECT_SOURCE_DIR}/hpx/parallel/container_algorithms/transform.hpp" "${PROJECT_SOURCE_DIR}/hpx/parallel/executors/auto_chunk_size.hpp" diff --git a/docs/hpx.qbk b/docs/hpx.qbk index 305bf2e3aebd..66edf35d2a27 100644 --- a/docs/hpx.qbk +++ b/docs/hpx.qbk @@ -141,6 +141,7 @@ [def __cpp11_n4107__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4313.html N4313]] [def __cpp11_n4406__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4406.pdf N4406]] [def __cpp17_n4399__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4399.html N4399]] +[def __cpp17_n4560__ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4560.pdf N4560]] [def __ini_file_format__ [@http://en.wikipedia.org/wiki/INI_file Windows INI file format]] diff --git a/docs/manual/build_system/cmake_variables.qbk b/docs/manual/build_system/cmake_variables.qbk index a1cd78a66cbd..d7e433effe85 100644 --- a/docs/manual/build_system/cmake_variables.qbk +++ b/docs/manual/build_system/cmake_variables.qbk @@ -28,6 +28,7 @@ The options are split into these categories: [#build_system.cmake_variables.Generic][h3 Generic Options] * [link build_system.cmake_variables.HPX_WITH_AUTOMATIC_SERIALIZATION_REGISTRATION HPX_WITH_AUTOMATIC_SERIALIZATION_REGISTRATION] * [link build_system.cmake_variables.HPX_WITH_BENCHMARK_SCRIPTS_PATH HPX_WITH_BENCHMARK_SCRIPTS_PATH] +* [link build_system.cmake_variables.HPX_WITH_BOOST_ALL_DYNAMIC_LINK HPX_WITH_BOOST_ALL_DYNAMIC_LINK] * [link build_system.cmake_variables.HPX_WITH_COLOCATED_BACKWARDS_COMPATIBILITY HPX_WITH_COLOCATED_BACKWARDS_COMPATIBILITY] * [link build_system.cmake_variables.HPX_WITH_COMPILER_WARNINGS HPX_WITH_COMPILER_WARNINGS] * [link build_system.cmake_variables.HPX_WITH_COMPONENT_GET_GID_COMPATIBILITY HPX_WITH_COMPONENT_GET_GID_COMPATIBILITY] @@ -35,11 +36,13 @@ The options are split into these categories: * [link build_system.cmake_variables.HPX_WITH_COMPRESSION_SNAPPY HPX_WITH_COMPRESSION_SNAPPY] * [link build_system.cmake_variables.HPX_WITH_COMPRESSION_ZLIB HPX_WITH_COMPRESSION_ZLIB] * [link build_system.cmake_variables.HPX_WITH_FORTRAN HPX_WITH_FORTRAN] +* [link build_system.cmake_variables.HPX_WITH_FPGA_QUEUES HPX_WITH_FPGA_QUEUES] * [link build_system.cmake_variables.HPX_WITH_FULL_RPATH HPX_WITH_FULL_RPATH] * [link build_system.cmake_variables.HPX_WITH_GCC_VERSION_CHECK HPX_WITH_GCC_VERSION_CHECK] * [link build_system.cmake_variables.HPX_WITH_GENERIC_CONTEXT_COROUTINES HPX_WITH_GENERIC_CONTEXT_COROUTINES] * [link build_system.cmake_variables.HPX_WITH_HIDDEN_VISIBILITY HPX_WITH_HIDDEN_VISIBILITY] * [link build_system.cmake_variables.HPX_WITH_HWLOC HPX_WITH_HWLOC] +* [link build_system.cmake_variables.HPX_WITH_LOCAL_DATAFLOW_COMPATIBILITY HPX_WITH_LOCAL_DATAFLOW_COMPATIBILITY] * [link build_system.cmake_variables.HPX_WITH_LOGGING HPX_WITH_LOGGING] * [link build_system.cmake_variables.HPX_WITH_MALLOC HPX_WITH_MALLOC] * [link build_system.cmake_variables.HPX_WITH_NATIVE_TLS HPX_WITH_NATIVE_TLS] @@ -50,6 +53,7 @@ The options are split into these categories: [variablelist [[[#build_system.cmake_variables.HPX_WITH_AUTOMATIC_SERIALIZATION_REGISTRATION] `HPX_WITH_AUTOMATIC_SERIALIZATION_REGISTRATION:BOOL`][Use automatic serialization registration for actions and functions. This affects compatibility between HPX applications compiled with different compilers (default ON)]] [[[#build_system.cmake_variables.HPX_WITH_BENCHMARK_SCRIPTS_PATH] `HPX_WITH_BENCHMARK_SCRIPTS_PATH:PATH`][Directory to place batch scripts in]] + [[[#build_system.cmake_variables.HPX_WITH_BOOST_ALL_DYNAMIC_LINK] `HPX_WITH_BOOST_ALL_DYNAMIC_LINK:BOOL`][Add BOOST_ALL_DYN_LINK to compile flags]] [[[#build_system.cmake_variables.HPX_WITH_COLOCATED_BACKWARDS_COMPATIBILITY] `HPX_WITH_COLOCATED_BACKWARDS_COMPATIBILITY:BOOL`][Enable backwards compatibility for apply_colocated, async_colocated and friends]] [[[#build_system.cmake_variables.HPX_WITH_COMPILER_WARNINGS] `HPX_WITH_COMPILER_WARNINGS:BOOL`][Enable compiler warnings (default: ON)]] [[[#build_system.cmake_variables.HPX_WITH_COMPONENT_GET_GID_COMPATIBILITY] `HPX_WITH_COMPONENT_GET_GID_COMPATIBILITY:BOOL`][Enable backwards compatibility for component::get_gid() functions]] @@ -57,11 +61,13 @@ The options are split into these categories: [[[#build_system.cmake_variables.HPX_WITH_COMPRESSION_SNAPPY] `HPX_WITH_COMPRESSION_SNAPPY:BOOL`][Enable snappy compression for parcel data (default: OFF).]] [[[#build_system.cmake_variables.HPX_WITH_COMPRESSION_ZLIB] `HPX_WITH_COMPRESSION_ZLIB:BOOL`][Enable zlib compression for parcel data (default: OFF).]] [[[#build_system.cmake_variables.HPX_WITH_FORTRAN] `HPX_WITH_FORTRAN:BOOL`][Enable or disable the compilation of Fortran examples using HPX]] + [[[#build_system.cmake_variables.HPX_WITH_FPGA_QUEUES] `HPX_WITH_FPGA_QUEUES:BOOL`][Enable special FPGA based queues and schedulers (default: OFF)]] [[[#build_system.cmake_variables.HPX_WITH_FULL_RPATH] `HPX_WITH_FULL_RPATH:BOOL`][Build and link HPX libraries and executables with full RPATHs (default: ON)]] [[[#build_system.cmake_variables.HPX_WITH_GCC_VERSION_CHECK] `HPX_WITH_GCC_VERSION_CHECK:BOOL`][Don't ignore version reported by gcc (default: ON)]] [[[#build_system.cmake_variables.HPX_WITH_GENERIC_CONTEXT_COROUTINES] `HPX_WITH_GENERIC_CONTEXT_COROUTINES:BOOL`][Use Boost.Context as the underlying coroutines context switch implementation.]] [[[#build_system.cmake_variables.HPX_WITH_HIDDEN_VISIBILITY] `HPX_WITH_HIDDEN_VISIBILITY:BOOL`][Use -fvisibility=hidden for builds on platforms which support it (default ON)]] [[[#build_system.cmake_variables.HPX_WITH_HWLOC] `HPX_WITH_HWLOC:BOOL`][Use Hwloc for hardware topolgy information and thread pinning. If disabled, performance might be reduced.]] + [[[#build_system.cmake_variables.HPX_WITH_LOCAL_DATAFLOW_COMPATIBILITY] `HPX_WITH_LOCAL_DATAFLOW_COMPATIBILITY:BOOL`][Enable backwards compatibility for hpx::lcos::local::dataflow() functions]] [[[#build_system.cmake_variables.HPX_WITH_LOGGING] `HPX_WITH_LOGGING:BOOL`][Build HPX with logging enabled (default: ON).]] [[[#build_system.cmake_variables.HPX_WITH_MALLOC] `HPX_WITH_MALLOC:STRING`][Define which allocator should be linked in. Options are: system, tcmalloc, jemalloc, tbbmalloc, and custom (default is: tcmalloc)]] [[[#build_system.cmake_variables.HPX_WITH_NATIVE_TLS] `HPX_WITH_NATIVE_TLS:BOOL`][Use native TLS support if available (default: ON)]] @@ -93,8 +99,8 @@ The options are split into these categories: [[[#build_system.cmake_variables.HPX_WITH_DOCUMENTATION] `HPX_WITH_DOCUMENTATION:BOOL`][Build the HPX documentation (default OFF).]] [[[#build_system.cmake_variables.HPX_WITH_DOCUMENTATION_SINGLEPAGE] `HPX_WITH_DOCUMENTATION_SINGLEPAGE:BOOL`][The HPX documentation should be build as a single page HTML (default OFF).]] [[[#build_system.cmake_variables.HPX_WITH_EXAMPLES] `HPX_WITH_EXAMPLES:BOOL`][Build the HPX examples (default ON)]] - [[[#build_system.cmake_variables.HPX_WITH_IO_COUNTERS] `HPX_WITH_IO_COUNTERS:BOOL`][Build HPX runtime (default: ON)]] - [[[#build_system.cmake_variables.HPX_WITH_PSEUDO_DEPENDENCIES] `HPX_WITH_PSEUDO_DEPENDENCIES:BOOL`][Force creating pseudo targets and pseudo dependencies (default ON).]] + [[[#build_system.cmake_variables.HPX_WITH_IO_COUNTERS] `HPX_WITH_IO_COUNTERS:BOOL`][Build HPX runtime (default: OFF)]] + [[[#build_system.cmake_variables.HPX_WITH_PSEUDO_DEPENDENCIES] `HPX_WITH_PSEUDO_DEPENDENCIES:BOOL`][Force creating pseudo targets and pseudo dependencies (default OFF).]] [[[#build_system.cmake_variables.HPX_WITH_RUNTIME] `HPX_WITH_RUNTIME:BOOL`][Build HPX runtime (default: ON)]] [[[#build_system.cmake_variables.HPX_WITH_TESTS] `HPX_WITH_TESTS:BOOL`][Build the HPX tests (default ON)]] [[[#build_system.cmake_variables.HPX_WITH_TESTS_BENCHMARKS] `HPX_WITH_TESTS_BENCHMARKS:BOOL`][Build HPX benchmark tests (default: ON)]] diff --git a/docs/whats_new.qbk b/docs/whats_new.qbk index 1d2c7d18ac5c..6ee69a9679f0 100644 --- a/docs/whats_new.qbk +++ b/docs/whats_new.qbk @@ -11,6 +11,11 @@ [heading General Changes] +- We have started to add parallel algorithm overloads based on the C++ + Extensions for Ranges (__cpp17_n4560__) proposal. This also includes the + addition of projections to the existing algorithms. Please see [issue 1668] + for a list of algorithms which have been adapted to __cpp17_n4560__. + [heading Breaking Changes] - In order to move the dataflow facility to `namespace hpx` we added a @@ -20,7 +25,12 @@ `HPX_WITH_LOCAL_DATAFLOW_COMPATIBILITY` is defined at configuration time. Please explicitly qualify all uses of the dataflow facility if you enable this compatibility setting and encounter ambiguities. - +- The adaptation of the C++ Extensions for Ranges (__cpp17_n4560__) proposal + imposes some breaking changes related to the return types of some of the + parallel algorithms. Here is the list of algorithms we have changed so far: + `parallel::for_each`, `parallel::copy`, `parallel::rotate`, + `parallel::reverse` and `parallel::reverse_copy`, `parallel::remove` and + `parallel::remove_copy`. [heading Bug Fixes (Closed Tickets)] @@ -28,7 +38,8 @@ Here is a list of the important tickets we closed for this release. * [pr 1910] - Keep cmake_module_path * [pr 1909] - Fix mpirun with pbs -* [pr 1908] - Changing parallel::sort to return the last iterator as proposed by N4560 +* [pr 1908] - Changing parallel::sort to return the last iterator as proposed by + N4560 * [pr 1907] - Adding minimum version for Open MPI [endsect] diff --git a/hpx/include/parallel_remove_copy.hpp b/hpx/include/parallel_remove_copy.hpp index 92befa9e3da4..fff27d6b1b41 100644 --- a/hpx/include/parallel_remove_copy.hpp +++ b/hpx/include/parallel_remove_copy.hpp @@ -7,5 +7,6 @@ #define HPX_PARALLEL_REMOVE_COPY_FEB_25_2015_2131PM #include +#include #endif diff --git a/hpx/include/parallel_replace.hpp b/hpx/include/parallel_replace.hpp index 9c11071b2666..95991b0c389c 100644 --- a/hpx/include/parallel_replace.hpp +++ b/hpx/include/parallel_replace.hpp @@ -8,6 +8,7 @@ #define HPX_PARALLEL_REPLACE_AUG_18_2014_0148PM #include +#include #endif diff --git a/hpx/include/parallel_reverse.hpp b/hpx/include/parallel_reverse.hpp index 4b33d88a5c1a..9ebe39c52ffe 100644 --- a/hpx/include/parallel_reverse.hpp +++ b/hpx/include/parallel_reverse.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2015 Hartmut Kaiser // Copyright (c) 2014 Grant Mercer // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -8,5 +8,6 @@ #define HPX_PARALLEL_REVERSE_COPY_JUL_29_2014_0348PM #include +#include #endif diff --git a/hpx/include/parallel_rotate.hpp b/hpx/include/parallel_rotate.hpp index 69dc7149b132..498b50261b01 100644 --- a/hpx/include/parallel_rotate.hpp +++ b/hpx/include/parallel_rotate.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2015 Hartmut Kaiser // // 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) @@ -7,6 +7,7 @@ #define HPX_PARALLEL_ROTATE_AUG_05_2014_0136PM #include +#include #endif diff --git a/hpx/lcos/future.hpp b/hpx/lcos/future.hpp index 341f55e4ec1c..78f200a77d73 100644 --- a/hpx/lcos/future.hpp +++ b/hpx/lcos/future.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2013 Hartmut Kaiser +// Copyright (c) 2007-2015 Hartmut Kaiser // Copyright (c) 2013 Agustin Berge // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -11,16 +11,19 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -30,6 +33,7 @@ #include #include #include +#include #include #include @@ -1116,6 +1120,41 @@ namespace hpx { namespace lcos { return f; } + + // Allow to convert any future into any other future based on an + // existing conversion path U --> T. + template ::value)> + hpx::future make_future(hpx::future && f) + { + return f.then( + [](hpx::future && f) -> T + { + return f.get(); + }); + } + + template + hpx::future make_future(hpx::future && f) + { + return f; + } + + // Allow to convert any future into any other future based on a given + // conversion function: T f(U). + template ::value)> + hpx::future + make_future(hpx::future && f, Conv && conv) + { + return f.then( + [conv](hpx::future && f) -> R + { + return hpx::util::invoke(conv, f.get()); + }); + } }} HPX_REGISTER_TYPED_CONTINUATION_DECLARATION( diff --git a/hpx/parallel/algorithms/copy.hpp b/hpx/parallel/algorithms/copy.hpp index 9e87fc9fb4bd..b26642728575 100644 --- a/hpx/parallel/algorithms/copy.hpp +++ b/hpx/parallel/algorithms/copy.hpp @@ -9,7 +9,7 @@ #if !defined(HPX_PARALLEL_DETAIL_COPY_MAY_30_2014_0317PM) #define HPX_PARALLEL_DETAIL_COPY_MAY_30_2014_0317PM -#include +#include #include #include @@ -39,35 +39,48 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - template + + // sequential copy + template + inline std::pair + sequential_copy(InIter first, InIter last, OutIter dest) + { + while (first != last) + { + *dest++ = *first++; + } + return std::make_pair(first, dest); + } + + template struct copy - : public detail::algorithm, OutIter> + : public detail::algorithm, IterPair> { copy() : copy::algorithm("copy") {} - template - static OutIter_ - sequential(ExPolicy, InIter first, InIter last, OutIter_ dest) + template + static std::pair + sequential(ExPolicy, InIter first, InIter last, OutIter dest) { - return std::copy(first, last, dest); + return sequential_copy(first, last, dest); } - template + template static typename util::detail::algorithm_result< - ExPolicy, OutIter_ + ExPolicy, std::pair >::type parallel(ExPolicy policy, FwdIter first, FwdIter last, - OutIter_ dest) + OutIter dest) { - typedef hpx::util::zip_iterator zip_iterator; + typedef hpx::util::zip_iterator zip_iterator; typedef typename zip_iterator::reference reference; typedef typename util::detail::algorithm_result< - ExPolicy, OutIter_ + ExPolicy, std::pair >::type result_type; - return get_iter<1, result_type>( + return get_iter_pair( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator(first, dest), @@ -81,7 +94,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) }; template - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type copy_(ExPolicy && policy, InIter first, InIter last, OutIter dest, std::false_type) { @@ -96,14 +111,16 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::copy().call( + return detail::copy >().call( std::forward(policy), is_seq(), first, last, dest); } // forward declare the segmented version of this algorithm template - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type copy_(ExPolicy && policy, InIter first, InIter last, OutIter dest, std::true_type); @@ -145,12 +162,14 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a copy algorithm returns a \a hpx::future if the - /// execution policy is of type + /// \returns The \a copy algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and - /// returns \a OutIter otherwise. - /// The \a copy algorithm returns the output iterator to the + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// \a last and the output iterator to the /// element in the destination range, one past the last element /// copied. /// @@ -159,7 +178,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) is_execution_policy::value && traits::detail::is_iterator::value && traits::detail::is_iterator::value)> - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type copy(ExPolicy && policy, InIter first, InIter last, OutIter dest) { typedef typename std::iterator_traits::iterator_category @@ -194,40 +215,61 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - template - struct copy_n : public detail::algorithm, Iter> + + // sequential copy_n + template + inline std::pair + sequential_copy_n(InIter first, std::size_t count, OutIter dest) + { + if (count > 0) + { + *dest++ = *first; + for (std::size_t i = 1; i != count; ++i) + { + *dest++ = *++first; + } + } + return std::make_pair(first, dest); + } + + template + struct copy_n : public detail::algorithm, IterPair> { copy_n() : copy_n::algorithm("copy_n") {} - template - static Iter - sequential(ExPolicy, InIter first, std::size_t count, - Iter dest) + template + static std::pair + sequential(ExPolicy, InIter first, std::size_t count, OutIter dest) { - return std::copy_n(first, count, dest); + return sequential_copy_n(first, count, dest); } - template - static typename util::detail::algorithm_result::type + template + static typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type parallel(ExPolicy policy, FwdIter first, std::size_t count, - Iter dest) + OutIter dest) { - typedef hpx::util::zip_iterator zip_iterator; + typedef hpx::util::zip_iterator zip_iterator; typedef typename zip_iterator::reference reference; typedef typename util::detail::algorithm_result< - ExPolicy, Iter + ExPolicy, std::pair >::type result_type; - return get_iter<1, result_type>( + return get_iter_pair( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator(first, dest), count, - [](reference t) { - hpx::util::get<1>(t) = hpx::util::get<0>(t); //-V573 - })); + [](reference t) + { + using hpx::util::get; + get<1>(t) = get<0>(t); //-V573 + } + )); } }; /// \endcond @@ -272,12 +314,15 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a copy_n algorithm returns a \a hpx::future if - /// the execution policy is of type + /// \returns The \a copy_n algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and - /// returns \a OutIter otherwise. - /// The \a copy_n algorithm returns the output iterator to the + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the /// element in the destination range, one past the last element /// copied. /// @@ -287,7 +332,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) is_execution_policy::value && traits::detail::is_iterator::value && traits::detail::is_iterator::value)> - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type copy_n(ExPolicy && policy, InIter first, Size count, OutIter dest) { typedef typename std::iterator_traits::iterator_category @@ -312,8 +359,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) // if count is representing a negative value, we do nothing if (detail::is_negative::call(count)) { - return util::detail::algorithm_result::get( - std::move(dest)); + return util::detail::algorithm_result< + ExPolicy, std::pair + >::get(std::make_pair(first, dest)); } typedef typename boost::mpl::or_< @@ -322,7 +370,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::copy_n().call( + return detail::copy_n >().call( std::forward(policy), is_seq(), first, std::size_t(count), dest); } @@ -331,9 +379,11 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) // copy_if namespace detail { + /// \cond NOINTERNAL + // sequential copy_if with projection function template - inline OutIter + inline std::pair sequential_copy_if(InIter first, InIter last, OutIter dest, Pred && pred, Proj && proj) { @@ -343,40 +393,43 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) *dest++ = *first; first++; } - return dest; + return std::make_pair(first, dest); } - /// \cond NOINTERNAL - template - struct copy_if : public detail::algorithm, Iter> + template + struct copy_if : public detail::algorithm, IterPair> { copy_if() : copy_if::algorithm("copy_if") {} - template - static Iter - sequential(ExPolicy, InIter first, InIter last, Iter dest, + template + static std::pair + sequential(ExPolicy, InIter first, InIter last, OutIter dest, Pred && pred, Proj && proj = Proj()) { return sequential_copy_if(first, last, dest, std::forward(pred), std::forward(proj)); } - template - static typename util::detail::algorithm_result::type + template + static typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type parallel(ExPolicy policy, FwdIter first, FwdIter last, - Iter dest, Pred && pred, Proj && proj = Proj()) + OutIter dest, Pred && pred, Proj && proj = Proj()) { typedef hpx::util::zip_iterator zip_iterator; - typedef util::detail::algorithm_result result; + typedef util::detail::algorithm_result< + ExPolicy, std::pair + > result; typedef typename std::iterator_traits::difference_type difference_type; if (first == last) - return result::get(std::move(dest)); + return result::get(std::make_pair(last, dest)); difference_type count = std::distance(first, last); @@ -385,8 +438,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) using hpx::util::get; using hpx::util::make_zip_iterator; - typedef util::scan_partitioner - scan_partitioner_type; + typedef util::scan_partitioner< + ExPolicy, std::pair, std::size_t + > scan_partitioner_type; return scan_partitioner_type::call( policy, make_zip_iterator(first, flags.get()), count, init, @@ -397,7 +451,8 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) std::size_t curr = 0; // MSVC complains if proj is captured by ref below - util::loop_n(part_begin, part_size, + util::loop_n( + part_begin, part_size, [&pred, proj, &curr](zip_iterator it) mutable { bool f = hpx::util::invoke(pred, @@ -425,12 +480,13 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) }); }, // step 4 use this return value - [dest, flags]( + [last, dest, flags]( std::vector > && items, - std::vector > &&) mutable -> Iter + std::vector > &&) mutable + -> std::pair { std::advance(dest, items.back().get()); - return dest; + return std::make_pair(last, dest); }); } }; @@ -461,6 +517,8 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// (deduced). Unlike its sequential form, the parallel /// overload of \a copy_if 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. @@ -483,6 +541,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// it. The type \a Type must be such that an object of /// type \a InIter 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 assignments in the parallel \a copy_if algorithm invoked with /// an execution policy object of type \a sequential_execution_policy @@ -494,12 +556,15 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a copy_if algorithm returns a \a hpx::future if the - /// execution policy is of type + /// \returns The \a copy_if algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and - /// returns \a OutIter otherwise. - /// The \a copy_if algorithm returns the output iterator to the + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the /// element in the destination range, one past the last element /// copied. /// @@ -508,12 +573,14 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) HPX_CONCEPT_REQUIRES_( is_execution_policy::value && traits::detail::is_iterator::value && - traits::is_projected::value && traits::detail::is_iterator::value && + traits::is_projected::value && traits::is_indirect_callable< F, traits::projected >::value)> - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type copy_if(ExPolicy&& policy, InIter first, InIter last, OutIter dest, F && f, Proj && proj = Proj()) { @@ -542,7 +609,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::copy_if().call( + return detail::copy_if >().call( std::forward(policy), is_seq(), first, last, dest, std::forward(f), std::forward(proj)); } diff --git a/hpx/parallel/algorithms/detail/dispatch.hpp b/hpx/parallel/algorithms/detail/dispatch.hpp index 8d01485a9f0f..5bfe1a915584 100644 --- a/hpx/parallel/algorithms/detail/dispatch.hpp +++ b/hpx/parallel/algorithms/detail/dispatch.hpp @@ -34,6 +34,19 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail >::local_raw_iterator type; }; + template + struct local_algorithm_result > + { + typedef typename hpx::traits::segmented_local_iterator_traits< + Result1 + >::local_raw_iterator type1; + typedef typename hpx::traits::segmented_local_iterator_traits< + Result2 + >::local_raw_iterator type2; + + typedef std::pair type; + }; + template <> struct local_algorithm_result { diff --git a/hpx/parallel/algorithms/for_each.hpp b/hpx/parallel/algorithms/for_each.hpp index 7a23faf06f07..1b09649764ba 100644 --- a/hpx/parallel/algorithms/for_each.hpp +++ b/hpx/parallel/algorithms/for_each.hpp @@ -56,7 +56,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) return util::loop_n(first, count, [&f, &proj](Iter const& curr) { - f(hpx::util::invoke(proj, *curr)); + hpx::util::invoke(f, hpx::util::invoke(proj, *curr)); }); } @@ -72,11 +72,14 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) policy, first, count, [f, proj](Iter part_begin, std::size_t part_size) { - // VS2015 bails out when proj ot f are captured by ref - util::loop_n(part_begin, part_size, + // VS2015 bails out when proj or f are captured by + // ref + util::loop_n( + part_begin, part_size, [=](Iter const& curr) { - f(hpx::util::invoke(proj, *curr)); + hpx::util::invoke( + f, hpx::util::invoke(proj, *curr)); }); }); } diff --git a/hpx/parallel/algorithms/remove_copy.hpp b/hpx/parallel/algorithms/remove_copy.hpp index 24a8c138b574..2036d8078551 100644 --- a/hpx/parallel/algorithms/remove_copy.hpp +++ b/hpx/parallel/algorithms/remove_copy.hpp @@ -8,7 +8,10 @@ #if !defined(HPX_PARALLEL_DETAIL_REMOVE_COPY_FEB_25_2015_0137PM) #define HPX_PARALLEL_DETAIL_REMOVE_COPY_FEB_25_2015_0137PM -#include +#include +#include +#include + #include #include #include @@ -28,29 +31,56 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - template - struct remove_copy : public detail::algorithm, Iter> + + // sequential remove_copy + template + inline std::pair + sequential_remove_copy(InIter first, InIter last, OutIter dest, + T const& value, Proj && proj) + { + for (/* */; first != last; ++first) + { + if (!(hpx::util::invoke(proj, *first) == value)) + { + *dest++ = *first; + } + } + return std::make_pair(first, dest); + } + + template + struct remove_copy + : public detail::algorithm, IterPair> { remove_copy() : remove_copy::algorithm("remove_copy") {} - template - static Iter + template + static std::pair sequential(ExPolicy, InIter first, InIter last, - Iter dest, const T& val) + OutIter dest, const T& val, Proj && proj) { - return std::remove_copy(first, last, dest, val); + return sequential_remove_copy(first, last, dest, val, + std::forward(proj)); } - template - static typename util::detail::algorithm_result::type + template + static typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type parallel(ExPolicy policy, FwdIter first, FwdIter last, - Iter dest, const T& val) + OutIter dest, T const& val, Proj && proj) { - return copy_if().call( + return copy_if().call( policy, boost::mpl::false_(), first, last, dest, - [val](T const& a){ return a != val; }); + [val, proj](T const& a) + { + return !(a == val); + }, + std::forward(proj)); } }; /// \endcond @@ -61,6 +91,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// comparison operator returns false when compare to val. /// The order of the elements that are not removed is preserved. /// + /// Effects: Copies all the elements referred to by the iterator it in the + /// range [first,last) for which the following corresponding + /// conditions do not hold: INVOKE(proj, *it) == value + /// /// \note Complexity: Performs not more than \a last - \a first /// assignments, exactly \a last - \a first applications of the /// predicate \a f. @@ -76,7 +110,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// destination range (deduced). /// This iterator type must meet the requirements of an /// output iterator. - /// \tparam T The type that the derference fo InIter is compare to. + /// \tparam T The type that the result of dereferencing InIter is + /// compared to. + /// \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. @@ -86,6 +123,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// algorithm will be applied to. /// \param dest Refers to the beginning of the destination range. /// \param val Value to be removed. + /// \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 assignments in the parallel \a remove_copy algorithm invoked with /// an execution policy object of type \a sequential_execution_policy @@ -97,22 +138,35 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a remove_copy algorithm returns a \a hpx::future if the - /// execution policy is of type + /// \returns The \a remove_copy algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and - /// returns \a OutIter otherwise. - /// The \a remove_copy algorithm returns the output iterator to the + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the /// element in the destination range, one past the last element /// copied. /// - template - typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type + template ::value && + traits::detail::is_iterator::value && + traits::detail::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + std::equal_to<>, + traits::projected, + traits::projected + >::value)> + typename util::detail::algorithm_result< + ExPolicy, std::pair >::type remove_copy(ExPolicy && policy, InIter first, InIter last, OutIter dest, - const T& val) + T const& val, Proj && proj = Proj{}) { typedef typename std::iterator_traits::iterator_category input_iterator_category; @@ -139,9 +193,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::remove_copy().call( + return detail::remove_copy >().call( std::forward(policy), is_seq(), - first, last, dest, val); + first, last, dest, val, std::forward(proj)); } ///////////////////////////////////////////////////////////////////////////// @@ -149,31 +203,60 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - template - struct remove_copy_if : public detail::algorithm, Iter> + + // sequential remove_copy_if + template + inline std::pair + sequential_remove_copy_if(InIter first, InIter last, OutIter dest, F p, + Proj && proj) + { + for (/* */; first != last; ++first) + { + using hpx::util::invoke; + if (!invoke(p, invoke(proj, *first))) + { + *dest++ = *first; + } + } + return std::make_pair(first, dest); + } + + template + struct remove_copy_if + : public detail::algorithm, IterPair> { remove_copy_if() : remove_copy_if::algorithm("remove_copy_if") {} - template - static Iter + template + static std::pair sequential(ExPolicy, InIter first, InIter last, - Iter dest, F && f) + OutIter dest, F && f, Proj && proj) { - return std::remove_copy_if(first, last, dest, - std::forward(f)); + return sequential_remove_copy_if(first, last, dest, + std::forward(f), std::forward(proj)); } - template - static typename util::detail::algorithm_result::type + template + static typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type parallel(ExPolicy policy, FwdIter first, FwdIter last, - Iter dest, F && f) + OutIter dest, F && f, Proj && proj) { - typedef typename std::iterator_traits::value_type T; - return copy_if().call( + typedef typename std::iterator_traits::value_type + value_type; + + return copy_if().call( policy, boost::mpl::false_(), first, last, dest, - [f](T const& a){ return !f(a); }); + [f](value_type const& a) + { + return !hpx::util::invoke(f, a); + }, + std::forward(proj)); } }; /// \endcond @@ -184,6 +267,11 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// predicate \a f returns false. The order of the elements that are not /// removed is preserved. /// + /// Effects: Copies all the elements referred to by the iterator it in the + /// range [first,last) for which the following corresponding + /// conditions do not hold: + /// INVOKE(pred, INVOKE(proj, *it)) != false. + /// /// \note Complexity: Performs not more than \a last - \a first /// assignments, exactly \a last - \a first applications of the /// predicate \a f. @@ -203,6 +291,8 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// (deduced). Unlike its sequential form, the parallel /// overload of \a copy_if 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. @@ -225,6 +315,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// it. The type \a Type must be such that an object of /// type \a InIter 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 assignments in the parallel \a remove_copy_if algorithm invoked with /// an execution policy object of type \a sequential_execution_policy @@ -236,22 +330,33 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a remove_copy_if algorithm returns a \a hpx::future + /// \returns The \a remove_copy_if algorithm returns a + /// \a hpx::future > /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and - /// returns \a OutIter otherwise. - /// The \a remove_copy_if algorithm returns the output iterator to the + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the /// element in the destination range, one past the last element /// copied. /// - template - typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type + template ::value && + traits::detail::is_iterator::value && + traits::detail::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + F, traits::projected + >::value)> + typename util::detail::algorithm_result< + ExPolicy, std::pair >::type remove_copy_if(ExPolicy && policy, InIter first, InIter last, OutIter dest, - F && f) + F && f, Proj && proj = Proj{}) { typedef typename std::iterator_traits::iterator_category input_iterator_category; @@ -278,11 +383,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::remove_copy_if().call( + return detail::remove_copy_if >().call( std::forward(policy), is_seq(), - first, last, dest, std::forward(f)); + first, last, dest, std::forward(f), std::forward(proj)); } - }}} #endif diff --git a/hpx/parallel/algorithms/replace.hpp b/hpx/parallel/algorithms/replace.hpp index 8222ae94546b..4a1b23de3c08 100644 --- a/hpx/parallel/algorithms/replace.hpp +++ b/hpx/parallel/algorithms/replace.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014 Hartmut Kaiser +// Copyright (c) 2014-2015 Hartmut Kaiser // // 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) @@ -8,12 +8,14 @@ #if !defined(HPX_PARALLEL_DETAIL_REPLACE_AUG_18_2014_0136PM) #define HPX_PARALLEL_DETAIL_REPLACE_AUG_18_2014_0136PM -#include +#include +#include #include #include -#include +#include #include +#include #include #include #include @@ -33,38 +35,60 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - struct replace : public detail::algorithm + + // sequential replace + template + inline FwdIter + sequential_replace(FwdIter first, FwdIter last, T1 const& old_value, + T2 const& new_value, Proj && proj) + { + for (/* */; first != last; ++first) + { + if (hpx::util::invoke(proj, *first) == old_value) + { + *first = new_value; + } + } + return first; + } + + template + struct replace : public detail::algorithm, Iter> { replace() : replace::algorithm("replace") {} - template - static hpx::util::unused_type + template + static FwdIter sequential(ExPolicy, FwdIter first, FwdIter last, - T const& old_value, T const& new_value) + T1 const& old_value, T2 const& new_value, Proj && proj) { - std::replace(first, last, old_value, new_value); - return hpx::util::unused; + return sequential_replace(first, last, old_value, new_value, + std::forward(proj)); } - template - static typename util::detail::algorithm_result::type + template + static typename util::detail::algorithm_result< + ExPolicy, FwdIter + >::type parallel(ExPolicy policy, FwdIter first, FwdIter last, - T const& old_value, T const& new_value) + T1 const& old_value, T2 const& new_value, Proj && proj) { - typedef typename util::detail::algorithm_result::type - result_type; typedef typename std::iterator_traits::value_type type; - return hpx::util::void_guard(), - for_each_n().call( - policy, boost::mpl::false_(), - first, std::distance(first, last), - [old_value, new_value](type& t) { - if (t == old_value) - t = new_value; - }); + return for_each_n().call( + policy, boost::mpl::false_(), + first, std::distance(first, last), + [old_value, new_value, proj](type& t) + { + if (hpx::util::invoke(proj, t) == old_value) + { + t = new_value; + } + }); } }; /// \endcond @@ -73,6 +97,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// Replaces all elements satisfying specific criteria with \a new_value /// in the range [first, last). /// + /// Effects: Substitutes elements referred by the iterator it in the range + /// [first, last) with new_value, when the following corresponding + /// conditions hold: INVOKE(proj, *it) == old_value + /// /// \note Complexity: Performs exactly \a last - \a first assignments. /// /// \tparam ExPolicy The type of the execution policy to use (deduced). @@ -82,8 +110,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// \tparam FwdIter The type of the source iterators used (deduced). /// This iterator type must meet the requirements of a /// forward iterator. - /// \tparam T The type of the old and new values to replace - /// (deduced). + /// \tparam T1 The type of the old value to replace (deduced). + /// \tparam T2 The type of the new values to replace (deduced). + /// \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. @@ -93,6 +123,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// algorithm will be applied to. /// \param old_value Refers to the old value of the elements to replace. /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace algorithm invoked with an /// execution policy object of type \a sequential_execution_policy @@ -104,19 +138,27 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a replace algorithm returns a \a hpx::future if + /// \returns The \a replace algorithm returns a \a hpx::future if /// the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and /// returns \a void otherwise. + /// It returns \a last. /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type - >::type + template ::value && + traits::detail::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + std::equal_to<>, + traits::projected, + traits::projected + >::value)> + typename util::detail::algorithm_result::type replace(ExPolicy && policy, FwdIter first, FwdIter last, - T const& old_value, T const& new_value) + T1 const& old_value, T2 const& new_value, Proj && proj = Proj{}) { typedef typename std::iterator_traits::iterator_category iterator_category; @@ -128,9 +170,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) typedef typename is_sequential_execution_policy::type is_seq; - return detail::replace().call( + return detail::replace().call( std::forward(policy), is_seq(), - first, last, old_value, new_value); + first, last, old_value, new_value, std::forward(proj)); } /////////////////////////////////////////////////////////////////////////// @@ -138,38 +180,60 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - struct replace_if : public detail::algorithm + + // sequential replace_if + template + inline FwdIter + sequential_replace_if(FwdIter first, FwdIter last, F && f, + T const& new_value, Proj && proj) + { + for (/* */; first != last; ++first) + { + using hpx::util::invoke; + if (invoke(f, invoke(proj, *first))) + { + *first = new_value; + } + } + return first; + } + + template + struct replace_if : public detail::algorithm, Iter> { replace_if() : replace_if::algorithm("replace_if") {} - template - static hpx::util::unused_type + template + static FwdIter sequential(ExPolicy, FwdIter first, FwdIter last, F && f, - T const& new_value) + T const& new_value, Proj && proj) { - std::replace_if(first, last, std::forward(f), new_value); - return hpx::util::unused; + return sequential_replace_if(first, last, std::forward(f), + new_value, std::forward(proj)); } - template - static typename util::detail::algorithm_result::type + template + static typename util::detail::algorithm_result< + ExPolicy, FwdIter + >::type parallel(ExPolicy policy, FwdIter first, FwdIter last, - F && f, T const& new_value) + F && f, T const& new_value, Proj && proj) { - typedef typename util::detail::algorithm_result::type - result_type; typedef typename std::iterator_traits::value_type type; - return hpx::util::void_guard(), - for_each_n().call( - policy, boost::mpl::false_(), - first, std::distance(first, last), - [f, new_value](type& t) { - if (f(t)) - t = new_value; - }); + return for_each_n().call( + policy, boost::mpl::false_(), + first, std::distance(first, last), + [f, new_value, proj](type& t) + { + using hpx::util::invoke; + if (invoke(f, invoke(proj, t))) + t = new_value; + }); } }; /// \endcond @@ -178,6 +242,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// Replaces all elements satisfying specific criteria (for which predicate /// \a f returns true) with \a new_value in the range [first, last). /// + /// Effects: Substitutes elements referred by the iterator it in the range + /// [first, last) with new_value, when the following corresponding + /// conditions hold: INVOKE(f, INVOKE(proj, *it)) != false + /// /// \note Complexity: Performs exactly \a last - \a first applications of /// the predicate. /// @@ -194,6 +262,8 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// requirements of \a CopyConstructible. /// (deduced). /// \tparam T The type of the new values to replace (deduced). + /// \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. @@ -217,6 +287,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// type \a FwdIter can be dereferenced and then /// implicitly converted to \a Type. /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace_if algorithm invoked with an /// execution policy object of type \a sequential_execution_policy @@ -228,19 +302,25 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a replace_if algorithm returns a \a hpx::future + /// \returns The \a replace_if algorithm returns a \a hpx::future /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy /// and returns \a void otherwise. + /// It returns \a last. /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type - >::type + template ::value && + traits::detail::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + F, traits::projected + >::value)> + typename util::detail::algorithm_result::type replace_if(ExPolicy && policy, FwdIter first, FwdIter last, - F && f, T const& new_value) + F && f, T const& new_value, Proj && proj = Proj{}) { typedef typename std::iterator_traits::iterator_category iterator_category; @@ -252,9 +332,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) typedef typename is_sequential_execution_policy::type is_seq; - return detail::replace_if().call( + return detail::replace_if().call( std::forward(policy), is_seq(), - first, last, std::forward(f), new_value); + first, last, std::forward(f), new_value, + std::forward(proj)); } /////////////////////////////////////////////////////////////////////////// @@ -262,43 +343,61 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - template + + // sequential replace_copy + template + inline std::pair + sequential_replace_copy(InIter first, InIter last, OutIter dest, + T const& old_value, T const& new_value, Proj && proj) + { + for (/* */; first != last; ++first) + { + if (hpx::util::invoke(proj, *first) == old_value) + *dest++ = new_value; + else + *dest++ = *first; + } + return std::make_pair(first, dest); + } + + template struct replace_copy - : public detail::algorithm, OutIter> + : public detail::algorithm, IterPair> { replace_copy() : replace_copy::algorithm("replace_copy") {} - template - static OutIter - sequential(ExPolicy, InIter first, InIter last, - OutIter dest, T const& old_value, T const& new_value) + template + static std::pair + sequential(ExPolicy, InIter first, InIter last, OutIter dest, + T const& old_value, T const& new_value, Proj && proj) { - return std::replace_copy(first, last, dest, old_value, new_value); + return sequential_replace_copy(first, last, dest, + old_value, new_value, std::forward(proj)); } - template + template static typename util::detail::algorithm_result< - ExPolicy, OutIter + ExPolicy, std::pair >::type - parallel(ExPolicy policy, FwdIter first, FwdIter last, - OutIter dest, T const& old_value, T const& new_value) + parallel(ExPolicy policy, FwdIter first, FwdIter last, OutIter dest, + T const& old_value, T const& new_value, Proj && proj) { typedef hpx::util::zip_iterator zip_iterator; typedef typename zip_iterator::reference reference; - typedef typename util::detail::algorithm_result< - ExPolicy, OutIter - >::type result_type; - return get_iter<1, result_type>( + return get_iter_pair( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator(first, dest), std::distance(first, last), - [old_value, new_value](reference t) { + [old_value, new_value, proj](reference t) + { using hpx::util::get; - if (old_value == get<0>(t)) + if (hpx::util::invoke(proj, get<0>(t)) == old_value) get<1>(t) = new_value; else get<1>(t) = get<0>(t); //-V573 @@ -312,6 +411,12 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// beginning at \a dest replacing all elements satisfying a specific /// criteria with \a new_value. /// + /// Effects: Assigns to every iterator it in the range + /// [result, result + (last - first)) either new_value or + /// *(first + (it - result)) depending on whether the following + /// corresponding condition holds: + /// INVOKE(proj, *(first + (i - result))) == old_value + /// /// \note Complexity: Performs exactly \a last - \a first applications of /// the predicate. /// @@ -326,8 +431,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// destination range (deduced). /// This iterator type must meet the requirements of an /// output iterator. - /// \tparam T The type of the old and new values to replace - /// (deduced). + /// \tparam T1 The type of the old value to replace (deduced). + /// \tparam T2 The type of the new values to replace (deduced). + /// \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. @@ -338,6 +445,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// \param dest Refers to the beginning of the destination range. /// \param old_value Refers to the old value of the elements to replace. /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace_copy algorithm invoked /// with an execution policy object of type \a sequential_execution_policy @@ -349,22 +460,34 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a replace_copy algorithm returns a \a hpx::future + /// \returns The \a replace_copy algorithm returns a + /// \a hpx::future > /// if the execution policy is of type /// \a sequential_task_execution_policy or - /// \a parallel_task_execution_policy - /// and returns \a OutIter otherwise. - /// The \a replace_copy algorithm returns the output iterator - /// to the element in the destination range, one past the last - /// element copied. - /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type + /// \a parallel_task_execution_policy and + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// \a last and the output iterator to the + /// element in the destination range, one past the last element + /// copied. + /// + template ::value && + traits::detail::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + std::equal_to<>, + traits::projected, + traits::projected + >::value)> + typename util::detail::algorithm_result< + ExPolicy, std::pair >::type replace_copy(ExPolicy && policy, InIter first, InIter last, OutIter dest, - T const& old_value, T const& new_value) + T1 const& old_value, T2 const& new_value, Proj && proj = Proj{}) { typedef typename std::iterator_traits::iterator_category input_iterator_category; @@ -391,9 +514,9 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::replace_copy().call( + return detail::replace_copy >().call( std::forward(policy), is_seq(), - first, last, dest, old_value, new_value); + first, last, dest, old_value, new_value, std::forward(proj)); } /////////////////////////////////////////////////////////////////////////// @@ -401,44 +524,64 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - template + + // sequential replace_copy_if + template + inline std::pair + sequential_replace_copy_if(InIter first, InIter last, OutIter dest, + F && f, T const& new_value, Proj && proj) + { + for (/* */; first != last; ++first) + { + using hpx::util::invoke; + if (invoke(f, invoke(proj, *first))) + *dest++ = new_value; + else + *dest++ = *first; + } + return std::make_pair(first, dest); + } + + template struct replace_copy_if - : public detail::algorithm, OutIter> + : public detail::algorithm, IterPair> { replace_copy_if() : replace_copy_if::algorithm("replace_copy_if") {} - template - static OutIter + template + static std::pair sequential(ExPolicy, InIter first, InIter last, - OutIter dest, F && f, T const& new_value) + OutIter dest, F && f, T const& new_value, Proj && proj) { - return std::replace_copy_if(first, last, dest, - std::forward(f), new_value); + return sequential_replace_copy_if(first, last, dest, + std::forward(f), new_value, std::forward(proj)); } - template + template static typename util::detail::algorithm_result< - ExPolicy, OutIter + ExPolicy, std::pair >::type parallel(ExPolicy policy, FwdIter first, FwdIter last, - OutIter dest, F && f, T const& new_value) + OutIter dest, F && f, T const& new_value, Proj && proj) { typedef hpx::util::zip_iterator zip_iterator; typedef typename zip_iterator::reference reference; - typedef typename util::detail::algorithm_result< - ExPolicy, OutIter - >::type result_type; - return get_iter<1, result_type>( + return get_iter_pair( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator(first, dest), std::distance(first, last), - [f, new_value](reference t) { + [f, new_value, proj](reference t) + { using hpx::util::get; - if (f(get<0>(t))) + using hpx::util::invoke; + if (invoke(f, invoke(proj, get<0>(t)))) get<1>(t) = new_value; else get<1>(t) = get<0>(t); //-V573 @@ -452,6 +595,12 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// beginning at \a dest replacing all elements satisfying a specific /// criteria with \a new_value. /// + /// Effects: Assigns to every iterator it in the range + /// [result, result + (last - first)) either new_value or + /// *(first + (it - result)) depending on whether the following + /// corresponding condition holds: + /// INVOKE(f, INVOKE(proj, *(first + (i - result)))) != false + /// /// \note Complexity: Performs exactly \a last - \a first applications of /// the predicate. /// @@ -472,6 +621,8 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// requirements of \a CopyConstructible. /// (deduced). /// \tparam T The type of the new values to replace (deduced). + /// \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. @@ -496,6 +647,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// type \a FwdIter can be dereferenced and then /// implicitly converted to \a Type. /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace_copy_if algorithm invoked /// with an execution policy object of type \a sequential_execution_policy @@ -507,23 +662,32 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a replace_copy_if algorithm returns a \a hpx::future + /// \returns The \a replace_copy_if algorithm returns a + /// \a hpx::future > /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy /// and returns \a OutIter otherwise. - /// The \a replace_copy_if algorithm returns the output iterator - /// to the element in the destination range, one past the last - /// element copied. - /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type + /// The \a replace_copy_if algorithm returns the input iterator + /// \a last and the output iterator to the + /// element in the destination range, one past the last element + /// copied. + /// + template ::value && + traits::detail::is_iterator::value && + traits::is_projected::value && + traits::is_indirect_callable< + F, traits::projected + >::value)> + typename util::detail::algorithm_result< + ExPolicy, std::pair >::type replace_copy_if(ExPolicy && policy, InIter first, InIter last, OutIter dest, - F && f, T const& new_value) + F && f, T const& new_value, Proj && proj = Proj{}) { typedef typename std::iterator_traits::iterator_category input_iterator_category; @@ -550,9 +714,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::replace_copy_if().call( + return detail::replace_copy_if >().call( std::forward(policy), is_seq(), - first, last, dest, std::forward(f), new_value); + first, last, dest, std::forward(f), new_value, + std::forward(proj)); } }}} diff --git a/hpx/parallel/algorithms/reverse.hpp b/hpx/parallel/algorithms/reverse.hpp index d484c80f1851..6e3e763567cc 100644 --- a/hpx/parallel/algorithms/reverse.hpp +++ b/hpx/parallel/algorithms/reverse.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2015 Hartmut Kaiser // // 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) @@ -8,9 +8,9 @@ #if !defined(HPX_PARALLEL_DETAIL_REVERSE_JUL_29_2014_0432PM) #define HPX_PARALLEL_DETAIL_REVERSE_JUL_29_2014_0432PM -#include -#include -#include +#include +#include +#include #include #include @@ -34,41 +34,47 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - struct reverse : public detail::algorithm + template + struct reverse : public detail::algorithm, Iter> { reverse() : reverse::algorithm("reverse") {} template - static hpx::util::unused_type + static BidirIter sequential(ExPolicy, BidirIter first, BidirIter last) { std::reverse(first, last); - return hpx::util::unused; + return last; } template - static typename util::detail::algorithm_result::type + static typename util::detail::algorithm_result< + ExPolicy, BidirIter + >::type parallel(ExPolicy policy, BidirIter first, BidirIter last) { typedef std::reverse_iterator destination_iterator; typedef hpx::util::zip_iterator zip_iterator; typedef typename zip_iterator::reference reference; - typedef typename util::detail::algorithm_result::type - result_type; - return hpx::util::void_guard(), + return util::detail::convert_to_result( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator( first, destination_iterator(last)), std::distance(first, last) / 2, - [](reference t) { + [](reference t) + { using hpx::util::get; std::swap(get<0>(t), get<1>(t)); - }); + }), + [last](zip_iterator const&) -> BidirIter + { + return last; + }); } }; /// \endcond @@ -105,17 +111,18 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a reverse algorithm returns a \a hpx::future + /// \returns The \a reverse algorithm returns a \a hpx::future /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and - /// returns \a void otherwise. + /// returns \a BidirIter otherwise. + /// It returns \a last. /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type - >::type + template ::value && + traits::detail::is_iterator::value)> + typename util::detail::algorithm_result::type reverse(ExPolicy && policy, BidirIter first, BidirIter last) { typedef typename std::iterator_traits::iterator_category @@ -128,7 +135,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) typedef typename is_sequential_execution_policy::type is_seq; - return detail::reverse().call( + return detail::reverse().call( std::forward(policy), is_seq(), first, last); } @@ -137,34 +144,56 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL - template + + // sequential reverse_copy + template + inline std::pair + sequential_reverse_copy(BidirIt first, BidirIt last, OutIter dest) + { + BidirIt iter = last; + while (first != iter) + { + *dest++ = *--iter; + } + return std::make_pair(last, dest); + } + + template struct reverse_copy - : public detail::algorithm, OutputIter> + : public detail::algorithm, IterPair> { reverse_copy() : reverse_copy::algorithm("reverse_copy") {} - template - static OutputIter + template + static std::pair sequential(ExPolicy, BidirIter first, BidirIter last, - OutputIter dest_first) + OutIter dest_first) { - return std::reverse_copy(first, last, dest_first); + return sequential_reverse_copy(first, last, dest_first); } - template + template static typename util::detail::algorithm_result< - ExPolicy, OutputIter + ExPolicy, std::pair >::type parallel(ExPolicy policy, BidirIter first, BidirIter last, - OutputIter dest_first) + OutIter dest_first) { typedef std::reverse_iterator iterator; - return detail::copy().call( - policy, boost::mpl::false_(), - iterator(last), iterator(first), dest_first); + return util::detail::convert_to_result( + detail::copy >() + .call( + policy, boost::mpl::false_(), + iterator(last), iterator(first), dest_first + ), + [](std::pair const& p) + -> std::pair + { + return std::make_pair(p.first.base(), p.second); + }); } }; /// \endcond @@ -174,10 +203,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// beginning at dest_first in such a way that the elements in the new /// range are in reverse order. /// Behaves as if by executing the assignment - /// *(d_first + (last - first) - 1 - i) = *(first + i) once for each + /// *(dest_first + (last - first) - 1 - i) = *(first + i) once for each /// non-negative i < (last - first) /// If the source and destination ranges (that is, [first, last) and - /// [dest_first, ddest_first+(last-first)) respectively) overlap, the + /// [dest_first, dest_first+(last-first)) respectively) overlap, the /// behavior is undefined. /// /// \note Complexity: Performs exactly \a last - \a first assignments. @@ -186,7 +215,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// It describes the manner in which the execution /// of the algorithm may be parallelized and the manner /// in which it executes the assignments. - /// \tparam BidirIter The type of the source iterators used (deduced). + /// \tparam BidirIter The type of the source iterators used (deduced). /// This iterator type must meet the requirements of an /// bidirectional iterator. /// \tparam OutputIter The type of the iterator representing the @@ -212,25 +241,32 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a reverse_copy algorithm returns a \a hpx::future + /// \returns The \a reverse_copy algorithm returns a + /// \a hpx::future > /// if the execution policy is of type /// \a sequential_task_execution_policy or /// \a parallel_task_execution_policy and - /// returns \a OutputIter otherwise. - /// The \a reverse_copy algorithm returns the output iterator to the - /// element past the last element copied. + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the + /// element in the destination range, one past the last element + /// copied. /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type + template ::value && + traits::detail::is_iterator::value && + traits::detail::is_iterator::value)> + typename util::detail::algorithm_result< + ExPolicy, std::pair >::type reverse_copy(ExPolicy && policy, BidirIter first, BidirIter last, - OutputIter dest_first) + OutIter dest_first) { typedef typename std::iterator_traits::iterator_category input_iterator_category; - typedef typename std::iterator_traits::iterator_category + typedef typename std::iterator_traits::iterator_category output_iterator_category; static_assert( @@ -252,7 +288,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::reverse_copy().call( + return detail::reverse_copy >().call( std::forward(policy), is_seq(), first, last, dest_first); } diff --git a/hpx/parallel/algorithms/rotate.hpp b/hpx/parallel/algorithms/rotate.hpp index 5b81dc0af469..e4168523223a 100644 --- a/hpx/parallel/algorithms/rotate.hpp +++ b/hpx/parallel/algorithms/rotate.hpp @@ -8,7 +8,9 @@ #if !defined(HPX_PARALLEL_DETAIL_ROTATE_AUG_05_2014_0138PM) #define HPX_PARALLEL_DETAIL_ROTATE_AUG_05_2014_0138PM -#include +#include +#include +#include #include #include @@ -52,65 +54,71 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) } template - FwdIter sequential_rotate(FwdIter first, FwdIter new_first, FwdIter last) + inline std::pair + sequential_rotate(FwdIter first, FwdIter new_first, FwdIter last) { if (first != new_first && new_first != last) sequential_rotate_helper(first, new_first, last); std::advance(first, std::distance(new_first, last)); - return first; + return std::make_pair(first, last); } template - hpx::future + hpx::future > rotate_helper(ExPolicy policy, FwdIter first, FwdIter new_first, FwdIter last) { typedef boost::mpl::false_ non_seq; parallel_task_execution_policy p = - parallel_task_execution_policy().with(policy.parameters()); + parallel_task_execution_policy() + .on(policy.executor()) + .with(policy.parameters()); - detail::reverse r; + detail::reverse r; return dataflow( - hpx::util::unwrapped([=]() mutable -> hpx::future + [=](hpx::future&&, hpx::future&&) mutable + -> hpx::future > { - hpx::future f = r.call(p, non_seq(), first, last); - std::advance(first, std::distance(new_first, last)); + hpx::future f = r.call(p, non_seq(), first, last); return f.then( - [first] (hpx::future &&) -> FwdIter + [=] (hpx::future &&) mutable + -> std::pair { - return first; + std::advance(first, std::distance(new_first, last)); + return std::make_pair(first, last); }); - }), + }, r.call(p, non_seq(), first, new_first), r.call(p, non_seq(), new_first, last)); } - template - struct rotate : public detail::algorithm, FwdIter> + template + struct rotate : public detail::algorithm, IterPair> { rotate() : rotate::algorithm("rotate") {} - template - static FwdIter + template + static IterPair sequential(ExPolicy, FwdIter first, FwdIter new_first, FwdIter last) { return sequential_rotate(first, new_first, last); } - template + template static typename util::detail::algorithm_result< - ExPolicy, FwdIter + ExPolicy, IterPair >::type - parallel(ExPolicy policy, FwdIter first, - FwdIter new_first, FwdIter last) + parallel(ExPolicy policy, FwdIter first, FwdIter new_first, + FwdIter last) { - return util::detail::algorithm_result::get( - rotate_helper(policy, first, new_first, last)); + return util::detail::algorithm_result< + ExPolicy, IterPair + >::get(rotate_helper(policy, first, new_first, last)); } }; /// \endcond @@ -153,17 +161,20 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// \note The type of dereferenced \a FwdIter must meet the requirements /// of \a MoveAssignable and \a MoveConstructible. /// - /// \returns The \a rotate algorithm returns a \a hpx::future + /// \returns The \a rotate algorithm returns a + /// \a hpx::future > /// if the execution policy is of type /// \a parallel_task_execution_policy and /// returns \a FwdIter otherwise. /// The \a rotate algorithm returns the iterator equal to - /// first + (last - new_first). + /// pair(first + (last - new_first), last). /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type + template ::value && + traits::detail::is_iterator::value)> + typename util::detail::algorithm_result< + ExPolicy, std::pair >::type rotate(ExPolicy && policy, FwdIter first, FwdIter new_first, FwdIter last) { @@ -180,7 +191,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::rotate().call( + return detail::rotate >().call( std::forward(policy), is_seq(), first, new_first, last); } @@ -189,52 +200,71 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) namespace detail { /// \cond NOINTERNAL + + // sequential rotate_copy + template + inline std::pair + sequential_rotate_copy(FwdIter first, FwdIter new_first, FwdIter last, + OutIter dest_first) + { + std::pair p1 = + sequential_copy(new_first, last, dest_first); + std::pair p2 = + sequential_copy(first, new_first, std::move(p1.second)); + return std::make_pair(std::move(p1.first), std::move(p2.second)); + } + template - hpx::future + hpx::future > rotate_copy_helper(ExPolicy policy, FwdIter first, FwdIter new_first, FwdIter last, OutIter dest_first) { typedef boost::mpl::false_ non_seq; parallel_task_execution_policy p = - parallel_task_execution_policy().with(policy.parameters()); + parallel_task_execution_policy() + .on(policy.executor()) + .with(policy.parameters()); - hpx::future f = - detail::copy().call(p, non_seq(), + typedef std::pair copy_return_type; + + hpx::future f = + detail::copy().call(p, non_seq(), new_first, last, dest_first); return f.then( - [=](hpx::future && it) + [=](hpx::future && result) { - return detail::copy().call( - p, non_seq(), first, new_first, it.get()); + std::pair p1 = result.get(); + return detail::copy().call( + p, non_seq(), first, new_first, p1.second); }); } - template + template struct rotate_copy - : public detail::algorithm, OutIter> + : public detail::algorithm, IterPair> { rotate_copy() : rotate_copy::algorithm("rotate_copy") {} - template - static OutIter + template + static std::pair sequential(ExPolicy, FwdIter first, FwdIter new_first, FwdIter last, OutIter dest_first) { - return std::rotate_copy(first, new_first, last, dest_first); + return sequential_rotate_copy(first, new_first, last, dest_first); } - template + template static typename util::detail::algorithm_result< - ExPolicy, OutIter + ExPolicy, std::pair >::type parallel(ExPolicy policy, FwdIter first, FwdIter new_first, FwdIter last, OutIter dest_first) { - return util::detail::algorithm_result::get( + return util::detail::algorithm_result::get( rotate_copy_helper(policy, first, new_first, last, dest_first)); } }; @@ -280,17 +310,21 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /// fashion in unspecified threads, and indeterminately sequenced /// within each thread. /// - /// \returns The \a rotate_copy algorithm returns a \a hpx::future + /// \returns The \a rotate_copy algorithm returns a + /// \a hpx::future > /// if the execution policy is of type /// \a parallel_task_execution_policy and /// returns \a OutIter otherwise. /// The \a rotate_copy algorithm returns the output iterator to the /// element past the last element copied. /// - template - inline typename boost::enable_if< - is_execution_policy, - typename util::detail::algorithm_result::type + template ::value && + traits::detail::is_iterator::value && + traits::detail::is_iterator::value)> + typename util::detail::algorithm_result< + ExPolicy, std::pair >::type rotate_copy(ExPolicy && policy, FwdIter first, FwdIter new_first, FwdIter last, OutIter dest_first) @@ -319,7 +353,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) boost::is_same >::type is_seq; - return detail::rotate_copy().call( + return detail::rotate_copy >().call( std::forward(policy), is_seq(), first, new_first, last, dest_first); } diff --git a/hpx/parallel/algorithms/set_difference.hpp b/hpx/parallel/algorithms/set_difference.hpp index 0f8184060ab3..5a24cb74fcae 100644 --- a/hpx/parallel/algorithms/set_difference.hpp +++ b/hpx/parallel/algorithms/set_difference.hpp @@ -77,10 +77,19 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) > result; return result::get(std::move(dest)); } + if (first2 == last2) { - return detail::copy().call( - policy, boost::mpl::false_(), first1, last1, dest); + return util::detail::convert_to_result( + detail::copy >() + .call( + policy, boost::mpl::false_(), first1, last1, + dest + ), + [](std::pair const& p) -> OutIter + { + return p.second; + }); } typedef typename set_operations_buffer::type buffer_type; diff --git a/hpx/parallel/algorithms/set_symmetric_difference.hpp b/hpx/parallel/algorithms/set_symmetric_difference.hpp index 18df7619cb57..f9c650de205d 100644 --- a/hpx/parallel/algorithms/set_symmetric_difference.hpp +++ b/hpx/parallel/algorithms/set_symmetric_difference.hpp @@ -72,13 +72,30 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) if (first1 == last1) { - return detail::copy().call( - policy, boost::mpl::false_(), first2, last2, dest); + return util::detail::convert_to_result( + detail::copy >() + .call( + policy, boost::mpl::false_(), first2, last2, + dest + ), + [](std::pair const& p) -> OutIter + { + return p.second; + }); } + if (first2 == last2) { - return detail::copy().call( - policy, boost::mpl::false_(), first1, last1, dest); + return util::detail::convert_to_result( + detail::copy >() + .call( + policy, boost::mpl::false_(), first1, last1, + dest + ), + [](std::pair const& p) -> OutIter + { + return p.second; + }); } typedef typename set_operations_buffer::type buffer_type; diff --git a/hpx/parallel/algorithms/set_union.hpp b/hpx/parallel/algorithms/set_union.hpp index a7adb8fb4b63..df471d287209 100644 --- a/hpx/parallel/algorithms/set_union.hpp +++ b/hpx/parallel/algorithms/set_union.hpp @@ -71,13 +71,30 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) if (first1 == last1) { - return detail::copy().call( - policy, boost::mpl::false_(), first2, last2, dest); + return util::detail::convert_to_result( + detail::copy >() + .call( + policy, boost::mpl::false_(), first2, last2, + dest + ), + [](std::pair const& p) -> OutIter + { + return p.second; + }); } + if (first2 == last2) { - return detail::copy().call( - policy, boost::mpl::false_(), first1, last1, dest); + return util::detail::convert_to_result( + detail::copy >() + .call( + policy, boost::mpl::false_(), first1, last1, + dest + ), + [](std::pair const& p) -> OutIter + { + return p.second; + }); } typedef typename set_operations_buffer::type buffer_type; diff --git a/hpx/parallel/algorithms/transform.hpp b/hpx/parallel/algorithms/transform.hpp index 7a47b2ec61e4..a1b51109c410 100644 --- a/hpx/parallel/algorithms/transform.hpp +++ b/hpx/parallel/algorithms/transform.hpp @@ -84,7 +84,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) ExPolicy, hpx::util::tuple >::type result_type; - return get_iter_tuple( + return get_iter_tuple( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator(first, dest), @@ -260,7 +260,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) hpx::util::tuple >::type result_type; - return get_iter_tuple( + return get_iter_tuple( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator(first1, first2, dest), @@ -469,7 +469,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) hpx::util::tuple >::type result_type; - return get_iter_tuple( + return get_iter_tuple( for_each_n().call( policy, boost::mpl::false_(), hpx::util::make_zip_iterator(first1, first2, dest), diff --git a/hpx/parallel/container_algorithms.hpp b/hpx/parallel/container_algorithms.hpp index d986425b94df..32823d392b35 100644 --- a/hpx/parallel/container_algorithms.hpp +++ b/hpx/parallel/container_algorithms.hpp @@ -7,8 +7,13 @@ #define HPX_PARALLEL_CONTAINER_ALGORITHM_JUL_18_2015_0958AM #include + #include #include +#include +#include +#include +#include #include #include diff --git a/hpx/parallel/container_algorithms/copy.hpp b/hpx/parallel/container_algorithms/copy.hpp index 917a606b449c..427581707675 100644 --- a/hpx/parallel/container_algorithms/copy.hpp +++ b/hpx/parallel/container_algorithms/copy.hpp @@ -71,7 +71,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) is_execution_policy::value && traits::is_range::value && traits::detail::is_iterator::value)> - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, + std::pair::iterator_type, OutIter> + >::type copy(ExPolicy && policy, Rng && rng, OutIter dest) { return copy(std::forward(policy), @@ -158,7 +161,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) traits::is_indirect_callable< F, traits::projected_range >::value)> - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, + std::pair::iterator_type, OutIter> + >::type copy_if(ExPolicy && policy, Rng && rng, OutIter dest, F && f, Proj && proj = Proj()) { diff --git a/hpx/parallel/container_algorithms/remove_copy.hpp b/hpx/parallel/container_algorithms/remove_copy.hpp new file mode 100644 index 000000000000..fb0a1e84d5d6 --- /dev/null +++ b/hpx/parallel/container_algorithms/remove_copy.hpp @@ -0,0 +1,217 @@ +// Copyright (c) 2015 Hartmut Kaiser +// +// 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/remove_copy.hpp + +#if !defined(HPX_PARALLEL_CONTAINER_ALGORITHM_REMOVE_COPY_DEC_20_2015_0631AM) +#define HPX_PARALLEL_CONTAINER_ALGORITHM_REMOVE_COPY_DEC_20_2015_0631AM + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) +{ + /// Copies the elements in the range, defined by [first, last), to another + /// range beginning at \a dest. Copies only the elements for which the + /// comparison operator returns false when compare to val. + /// The order of the elements that are not removed is preserved. + /// + /// Effects: Copies all the elements referred to by the iterator it in the + /// range [first,last) for which the following corresponding + /// conditions do not hold: INVOKE(proj, *it) == value + /// + /// \note Complexity: Performs not more than \a last - \a first + /// assignments, exactly \a last - \a first 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 executes the assignments. + /// \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 OutIter The type of the iterator representing the + /// destination range (deduced). + /// This iterator type must meet the requirements of an + /// output iterator. + /// \tparam T The type that the result of dereferencing InIter is + /// compared to. + /// \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 dest Refers to the beginning of the destination range. + /// \param val Value to be removed. + /// \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 assignments in the parallel \a remove_copy algorithm invoked with + /// an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a remove_copy algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a remove_copy algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy and + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the + /// element in the destination range, one past the last element + /// copied. + /// + template ::value && + traits::is_range::value && + traits::detail::is_iterator::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + std::equal_to<>, + traits::projected_range, + traits::projected + >::value)> + typename util::detail::algorithm_result< + ExPolicy, + std::pair::iterator_type, OutIter> + >::type + remove_copy(ExPolicy && policy, Rng rng, OutIter dest, T const& val, + Proj && proj = Proj{}) + { + return remove_copy(std::forward(policy), + boost::begin(rng), boost::end(rng), dest, val, + std::forward(proj)); + } + + ///////////////////////////////////////////////////////////////////////////// + /// Copies the elements in the range, defined by [first, last), to another + /// range beginning at \a dest. Copies only the elements for which the + /// predicate \a f returns false. The order of the elements that are not + /// removed is preserved. + /// + /// Effects: Copies all the elements referred to by the iterator it in the + /// range [first,last) for which the following corresponding + /// conditions do not hold: + /// INVOKE(pred, INVOKE(proj, *it)) != false. + /// + /// \note Complexity: Performs not more than \a last - \a first + /// assignments, exactly \a last - \a first 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 executes the assignments. + /// \tparam InIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// input iterator. + /// \tparam OutIter The type of the iterator representing the + /// destination range (deduced). + /// This iterator type must meet the requirements of an + /// output iterator. + /// \tparam F The type of the function/function object to use + /// (deduced). Unlike its sequential form, the parallel + /// overload of \a copy_if 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 first Refers to the beginning of the sequence of elements + /// the algorithm will be applied to. + /// \param last Refers to the end of the sequence of elements the + /// algorithm will be applied to. + /// \param dest Refers to the beginning of the destination range. + /// \param f Specifies the function (or function object) which + /// will be invoked for each of the elements in the + /// sequence specified by [first, last).This is an + /// unary predicate which returns \a true for the + /// elements to be removed. 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 InIter 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 assignments in the parallel \a remove_copy_if algorithm invoked with + /// an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a remove_copy_if algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a remove_copy_if algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy and + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the + /// element in the destination range, one past the last element + /// copied. + /// + template ::value && + traits::is_range::value && + traits::detail::is_iterator::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + F, traits::projected_range + >::value)> + typename util::detail::algorithm_result< + ExPolicy, + std::pair::iterator_type, OutIter> + >::type + remove_copy_if(ExPolicy && policy, Rng rng, OutIter dest, F && f, + Proj && proj = Proj{}) + { + return remove_copy_if(std::forward(policy), + boost::begin(rng), boost::end(rng), dest, std::forward(f), + std::forward(proj)); + } +}}} + +#endif diff --git a/hpx/parallel/container_algorithms/replace.hpp b/hpx/parallel/container_algorithms/replace.hpp new file mode 100644 index 000000000000..9b8d8382f23d --- /dev/null +++ b/hpx/parallel/container_algorithms/replace.hpp @@ -0,0 +1,373 @@ +// Copyright (c) 2015 Hartmut Kaiser +// +// 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/replace.hpp + +#if !defined(HPX_PARALLEL_CONTAINER_ALGORITHM_REPLACE_DEC_18_2015_0103PM) +#define HPX_PARALLEL_CONTAINER_ALGORITHM_REPLACE_DEC_18_2015_0103PM + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) +{ + /// Replaces all elements satisfying specific criteria with \a new_value + /// in the range [first, last). + /// + /// \note Complexity: Performs exactly \a last - \a first assignments. + /// + /// Effects: Substitutes elements referred by the iterator it in the range + /// [first,last) with new_value, when the following corresponding + /// conditions hold: INVOKE(proj, *i) == old_value + /// + /// \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 executes the assignments. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of a forward iterator. + /// \tparam T1 The type of the old value to replace (deduced). + /// \tparam T2 The type of the new values to replace (deduced). + /// \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 old_value Refers to the old value of the elements to replace. + /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace algorithm invoked with an + /// execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a replace algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a replace algorithm returns a \a hpx::future if + /// the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy and + /// returns \a void otherwise. + /// + template ::value && + traits::is_range::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + std::equal_to<>, + traits::projected_range, + traits::projected + >::value)> + typename util::detail::algorithm_result< + ExPolicy, typename traits::range_traits::iterator_type + >::type + replace(ExPolicy && policy, Rng rng, T1 const& old_value, + T2 const& new_value, Proj && proj = Proj{}) + { + return replace(std::forward(policy), + boost::begin(rng), boost::end(rng), old_value, new_value, + std::forward(proj)); + } + + /// Replaces all elements satisfying specific criteria (for which predicate + /// \a f returns true) with \a new_value in the range [first, last). + /// + /// \note Complexity: Performs exactly \a last - \a first applications of + /// the predicate. + /// + /// Effects: Substitutes elements referred by the iterator it in the range + /// [first, last) with new_value, when the following corresponding + /// conditions hold: INVOKE(f, INVOKE(proj, *it)) != false + /// + /// \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 executes the assignments. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of a forward iterator. + /// \tparam F The type of the function/function object to use + /// (deduced). Unlike its sequential form, the parallel + /// overload of \a equal requires \a F to meet the + /// requirements of \a CopyConstructible. + /// (deduced). + /// \tparam T The type of the new values to replace (deduced). + /// \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).This is an + /// unary predicate which returns \a true for the + /// elements which need to replaced. 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 \a Type. + /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace_if algorithm invoked with an + /// execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a replace_if algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a replace_if algorithm returns a \a hpx::future + /// if the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy + /// and returns \a void otherwise. + /// It returns \a last. + /// + template ::value && + traits::is_range::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + F, traits::projected_range + >::value)> + typename util::detail::algorithm_result< + ExPolicy, typename traits::range_traits::iterator_type + >::type + replace_if(ExPolicy && policy, Rng rng, F && f, T const& new_value, + Proj && proj = Proj{}) + { + return replace_if(std::forward(policy), + boost::begin(rng), boost::end(rng), + std::forward(f), new_value, std::forward(proj)); + } + + /// Copies the all elements from the range [first, last) to another range + /// beginning at \a dest replacing all elements satisfying a specific + /// criteria with \a new_value. + /// + /// Effects: Assigns to every iterator it in the range + /// [result, result + (last - first)) either new_value or + /// *(first + (it - result)) depending on whether the following + /// corresponding condition holds: + /// INVOKE(proj, *(first + (i - result))) == old_value + /// + /// \note Complexity: Performs exactly \a last - \a first applications of + /// the predicate. + /// + /// \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 executes the assignments. + /// \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 OutIter The type of the iterator representing the + /// destination range (deduced). + /// This iterator type must meet the requirements of an + /// output iterator. + /// \tparam T1 The type of the old value to replace (deduced). + /// \tparam T2 The type of the new values to replace (deduced). + /// \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 dest Refers to the beginning of the destination range. + /// \param old_value Refers to the old value of the elements to replace. + /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace_copy algorithm invoked + /// with an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a replace_copy algorithm invoked + /// with an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a replace_copy algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy and + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// \a last and the output iterator to the + /// element in the destination range, one past the last element + /// copied. + /// + template ::value && + traits::is_range::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + std::equal_to<>, + traits::projected_range, + traits::projected + >::value)> + typename util::detail::algorithm_result< + ExPolicy, + std::pair::iterator_type, OutIter> + >::type + replace_copy(ExPolicy && policy, Rng rng, OutIter dest, + T1 const& old_value, T2 const& new_value, Proj && proj = Proj{}) + { + return replace_copy(std::forward(policy), + boost::begin(rng), boost::end(rng), dest, old_value, new_value, + std::forward(proj)); + } + + /// Copies the all elements from the range [first, last) to another range + /// beginning at \a dest replacing all elements satisfying a specific + /// criteria with \a new_value. + /// + /// Effects: Assigns to every iterator it in the range + /// [result, result + (last - first)) either new_value or + /// *(first + (it - result)) depending on whether the following + /// corresponding condition holds: + /// INVOKE(f, INVOKE(proj, *(first + (i - result)))) != false + /// + /// \note Complexity: Performs exactly \a last - \a first applications of + /// the predicate. + /// + /// \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 executes the assignments. + /// \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 OutIter The type of the iterator representing the + /// destination range (deduced). + /// This iterator type must meet the requirements of an + /// output iterator. + /// \tparam F The type of the function/function object to use + /// (deduced). Unlike its sequential form, the parallel + /// overload of \a equal requires \a F to meet the + /// requirements of \a CopyConstructible. + /// (deduced). + /// \tparam T The type of the new values to replace (deduced). + /// \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 dest Refers to the beginning of the destination range. + /// \param f Specifies the function (or function object) which + /// will be invoked for each of the elements in the + /// sequence specified by [first, last).This is an + /// unary predicate which returns \a true for the + /// elements which need to replaced. 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 \a Type. + /// \param new_value Refers to the new value to use as the replacement. + /// \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 assignments in the parallel \a replace_copy_if algorithm invoked + /// with an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a replace_copy_if algorithm invoked + /// with an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a replace_copy_if algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy + /// and returns \a OutIter otherwise. + /// The \a replace_copy_if algorithm returns the input iterator + /// \a last and the output iterator to the + /// element in the destination range, one past the last element + /// copied. + /// + template ::value && + traits::is_range::value && + traits::is_projected_range::value && + traits::is_indirect_callable< + F, traits::projected_range + >::value)> + typename util::detail::algorithm_result< + ExPolicy, + std::pair::iterator_type, OutIter> + >::type + replace_copy_if(ExPolicy && policy, Rng rng, OutIter dest, + F && f, T const& new_value, Proj && proj = Proj{}) + { + return replace_copy_if(std::forward(policy), + boost::begin(rng), boost::end(rng), dest, std::forward(f), + new_value, std::forward(proj)); + } +}}} + +#endif diff --git a/hpx/parallel/container_algorithms/reverse.hpp b/hpx/parallel/container_algorithms/reverse.hpp new file mode 100644 index 000000000000..6522ce5a045b --- /dev/null +++ b/hpx/parallel/container_algorithms/reverse.hpp @@ -0,0 +1,144 @@ +// Copyright (c) 2007-2015 Hartmut Kaiser +// +// 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/reverse.hpp + +#if !defined(HPX_PARALLEL_CONTAINER_ALGORITHMS_REVERSE_DEC_21_2015_0245PM) +#define HPX_PARALLEL_CONTAINER_ALGORITHMS_REVERSE_DEC_21_2015_0245PM + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) +{ + /// Reverses the order of the elements in the range [first, last). + /// Behaves as if applying std::iter_swap to every pair of iterators + /// first+i, (last-i) - 1 for each non-negative i < (last-first)/2. + /// + /// \note Complexity: Linear in the distance between \a first and \a last. + /// + /// \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 executes the assignments. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of a bidirectional iterator. + /// + /// \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. + /// + /// The assignments in the parallel \a reverse algorithm invoked + /// with an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a reverse algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a reverse algorithm returns a \a hpx::future + /// if the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy and + /// returns \a BidirIter otherwise. + /// It returns \a last. + /// + template ::value && + traits::is_range::value)> + typename util::detail::algorithm_result< + ExPolicy, typename traits::range_iterator::type + >::type + reverse(ExPolicy && policy, Rng rng) + { + return reverse(std::forward(policy), + boost::begin(rng), boost::end(rng)); + } + + /////////////////////////////////////////////////////////////////////////// + /// Copies the elements from the range [first, last) to another range + /// beginning at dest_first in such a way that the elements in the new + /// range are in reverse order. + /// Behaves as if by executing the assignment + /// *(dest_first + (last - first) - 1 - i) = *(first + i) once for each + /// non-negative i < (last - first) + /// If the source and destination ranges (that is, [first, last) and + /// [dest_first, dest_first+(last-first)) respectively) overlap, the + /// behavior is undefined. + /// + /// \note Complexity: Performs exactly \a last - \a first assignments. + /// + /// \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 executes the assignments. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of a bidirectional iterator. + /// \tparam OutputIter The type of the iterator representing the + /// destination range (deduced). + /// This iterator type must meet the requirements of an + /// output iterator. + /// + /// \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 dest_first Refers to the begin of the destination range. + /// + /// The assignments in the parallel \a reverse_copy algorithm invoked + /// with an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a reverse_copy algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a reverse_copy algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type + /// \a sequential_task_execution_policy or + /// \a parallel_task_execution_policy and + /// returns \a std::pair otherwise. + /// The \a copy algorithm returns the pair of the input iterator + /// forwarded to the first element after the last in the input + /// sequence and the output iterator to the + /// element in the destination range, one past the last element + /// copied. + /// + template ::value && + traits::is_range::value && + traits::detail::is_iterator::value)> + typename util::detail::algorithm_result< + ExPolicy, + std::pair::type, OutIter> + >::type + reverse_copy(ExPolicy && policy, Rng rng, OutIter dest_first) + { + return reverse_copy(std::forward(policy), + boost::begin(rng), boost::end(rng), dest_first); + } +}}} + +#endif diff --git a/hpx/parallel/container_algorithms/rotate.hpp b/hpx/parallel/container_algorithms/rotate.hpp new file mode 100644 index 000000000000..f708f52f5525 --- /dev/null +++ b/hpx/parallel/container_algorithms/rotate.hpp @@ -0,0 +1,150 @@ +// Copyright (c) 2007-2015 Hartmut Kaiser +// +// 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/rotate.hpp + +#if !defined(HPX_PARALLEL_CONTAINER_ALGORITHM_ROTATE_DEC_22_2015_0736PM) +#define HPX_PARALLEL_CONTAINER_ALGORITHM_ROTATE_DEC_22_2015_0736PM + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) +{ + /////////////////////////////////////////////////////////////////////////// + /// Performs a left rotation on a range of elements. Specifically, + /// \a rotate swaps the elements in the range [first, last) in such a way + /// that the element new_first becomes the first element of the new range + /// and new_first - 1 becomes the last element. + /// + /// \note Complexity: Linear in the distance between \a first and \a last. + /// + /// \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 executes the assignments. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of a forward iterator. + /// + /// \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 middle Refers to the element that should appear at the + /// beginning of the rotated range. + /// + /// The assignments in the parallel \a rotate algorithm invoked + /// with an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a rotate algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \note The type of dereferenced \a FwdIter must meet the requirements + /// of \a MoveAssignable and \a MoveConstructible. + /// + /// \returns The \a rotate algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type + /// \a parallel_task_execution_policy and + /// returns \a FwdIter otherwise. + /// The \a rotate algorithm returns the iterator equal to + /// pair(first + (last - new_first), last). + /// + template ::value && + traits::is_range::value)> + typename util::detail::algorithm_result< + ExPolicy, + std::pair< + typename traits::range_iterator::type, + typename traits::range_iterator::type> + >::type + rotate(ExPolicy && policy, Rng rng, + typename traits::range_iterator::type middle) + { + return rotate(std::forward(policy), + boost::begin(rng), middle, boost::end(rng)); + } + + /////////////////////////////////////////////////////////////////////////// + /// Copies the elements from the range [first, last), to another range + /// beginning at \a dest_first in such a way, that the element + /// \a new_first becomes the first element of the new range and + /// \a new_first - 1 becomes the last element. + /// + /// \note Complexity: Performs exactly \a last - \a first assignments. + /// + /// \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 executes the assignments. + /// \tparam Rng The type of the source range used (deduced). + /// The iterators extracted from this range type must + /// meet the requirements of a forward iterator. + /// \tparam OutIter The type of the iterator representing the + /// destination range (deduced). + /// This iterator type must meet the requirements of an + /// output iterator. + /// + /// \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 middle Refers to the element that should appear at the + /// beginning of the rotated range. + /// \param dest_first Refers to the begin of the destination range. + /// + /// The assignments in the parallel \a rotate_copy algorithm invoked + /// with an execution policy object of type \a sequential_execution_policy + /// execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a rotate_copy algorithm invoked with + /// an execution policy object of type \a parallel_execution_policy or + /// \a parallel_task_execution_policy are permitted to execute in an unordered + /// fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a rotate_copy algorithm returns a + /// \a hpx::future > + /// if the execution policy is of type + /// \a parallel_task_execution_policy and + /// returns \a OutIter otherwise. + /// The \a rotate_copy algorithm returns the output iterator to the + /// element past the last element copied. + /// + template ::value && + traits::is_range::value && + traits::detail::is_iterator::value)> + typename util::detail::algorithm_result< + ExPolicy, + std::pair::type, OutIter> + >::type + rotate_copy(ExPolicy && policy, Rng rng, + typename traits::range_iterator::type middle, OutIter dest_first) + { + return rotate_copy(std::forward(policy), + boost::begin(rng), middle, boost::end(rng), dest_first); + } +}}} + +#endif diff --git a/hpx/parallel/segmented_algorithms/copy.hpp b/hpx/parallel/segmented_algorithms/copy.hpp index 3e62f3673c4c..9e96a88653d8 100644 --- a/hpx/parallel/segmented_algorithms/copy.hpp +++ b/hpx/parallel/segmented_algorithms/copy.hpp @@ -38,7 +38,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) template static typename util::detail::algorithm_result< - ExPolicy, SegOutIter + ExPolicy, std::pair >::type segmented_copy(Algo && algo, ExPolicy const& policy, boost::mpl::true_, SegIter first, SegIter last, SegOutIter dest) @@ -54,6 +54,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) typedef typename output_traits::local_iterator local_output_iterator_type; + typedef std::pair< + local_iterator_type, local_output_iterator_type + > local_iterator_pair; + segment_iterator sit = traits::segment(first); segment_iterator send = traits::segment(last); @@ -69,12 +73,12 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) if (beg != end) { - local_output_iterator_type out = dispatch( - traits::get_id(sit), - algo, policy, true_(), - beg, end, traits::local(dest)); + local_iterator_pair p = dispatch( + traits::get_id(sit), + algo, policy, true_(), + beg, end, traits::local(dest)); - dest = output_traits::compose(sdest, out); + dest = output_traits::compose(sdest, p.second); } } else { @@ -85,8 +89,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) if (beg != end) { - out = dispatch(traits::get_id(sit), + local_iterator_pair p = dispatch( + traits::get_id(sit), algo, policy, true_(), beg, end, out); + out = p.second; } // handle all of the full partitions @@ -98,8 +104,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) if (beg != end) { - out = dispatch(traits::get_id(sit), + local_iterator_pair p = dispatch( + traits::get_id(sit), algo, policy, true_(), beg, end, out); + out = p.second; } } @@ -108,22 +116,25 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) end = traits::local(last); if (beg != end) { - out = dispatch(traits::get_id(sit), + local_iterator_pair p = dispatch( + traits::get_id(sit), algo, policy, true_(), beg, end, traits::begin(sdest)); + out = p.second; } dest = output_traits::compose(sdest, out); } - return util::detail::algorithm_result::get( - std::move(dest)); + return util::detail::algorithm_result< + ExPolicy, std::pair + >::get(std::make_pair(last, dest)); } // parallel remote implementation template static typename util::detail::algorithm_result< - ExPolicy, SegOutIter + ExPolicy, std::pair >::type segmented_copy(Algo && algo, ExPolicy const& policy, boost::mpl::false_, SegIter first, SegIter last, SegOutIter dest) @@ -139,6 +150,10 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) typedef typename output_traits::local_iterator local_output_iterator_type; + typedef std::pair< + local_iterator_type, local_output_iterator_type + > local_iterator_pair; + typedef typename std::iterator_traits::iterator_category iterator_category; typedef typename boost::mpl::bool_ > segments; + std::vector > segments; segments.reserve(std::distance(sit, send)); if (sit == send) @@ -205,17 +220,23 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) } HPX_ASSERT(!segments.empty()); - return util::detail::algorithm_result::get( - dataflow( - [=](std::vector > && r) - -> SegOutIter + return util::detail::algorithm_result< + ExPolicy, std::pair >::get( + lcos::local::dataflow( + [=](std::vector > && r) + -> std::pair { // handle any remote exceptions, will throw on error std::list errors; parallel::util::detail::handle_remote_exceptions< ExPolicy >::call(r, errors); - return output_traits::compose(sdest, r.back().get()); + + local_iterator_pair p = r.back().get(); + return std::make_pair( + output_traits::compose(sdest, p.first), + output_traits::compose(sdest, p.second) + ); }, std::move(segments))); } @@ -223,31 +244,44 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) /////////////////////////////////////////////////////////////////////// // segmented implementation template - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type copy_(ExPolicy&& policy, InIter first, InIter last, OutIter dest, std::true_type) { if (first == last) { - return util::detail::algorithm_result::get( - std::move(dest)); + return util::detail::algorithm_result< + ExPolicy, std::pair + >::get(std::make_pair(last, dest)); } typedef typename parallel::is_sequential_execution_policy< ExPolicy >::type is_seq; + + typedef hpx::traits::segmented_iterator_traits + input_iterator_traits; typedef hpx::traits::segmented_iterator_traits output_iterator_traits; + typedef std::pair< + typename input_iterator_traits::local_iterator, + typename output_iterator_traits::local_iterator + > result_iterator_pair; + return segmented_copy( - copy(), + copy(), std::forward(policy), is_seq(), first, last, dest); } // forward declare the non-segmented version of this algorithm template - typename util::detail::algorithm_result::type + typename util::detail::algorithm_result< + ExPolicy, std::pair + >::type copy_(ExPolicy&& policy, InIter first, InIter last, OutIter dest, std::false_type); diff --git a/hpx/parallel/segmented_algorithms/detail/dispatch.hpp b/hpx/parallel/segmented_algorithms/detail/dispatch.hpp index b93039e2f986..b30bf250ecd2 100644 --- a/hpx/parallel/segmented_algorithms/detail/dispatch.hpp +++ b/hpx/parallel/segmented_algorithms/detail/dispatch.hpp @@ -27,12 +27,21 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail struct algorithm_result_helper { template - static HPX_FORCEINLINE T_ call(T_&& val) + static BOOST_FORCEINLINE T_ call(T_&& val) { return std::forward(val); } }; + template <> + struct algorithm_result_helper > + { + static BOOST_FORCEINLINE future call(future&& f) + { + return std::move(f); + } + }; + template struct algorithm_result_helper< Iterator, @@ -45,13 +54,47 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail typedef hpx::traits::segmented_local_iterator_traits traits; - static HPX_FORCEINLINE Iterator + static BOOST_FORCEINLINE Iterator call(typename traits::local_raw_iterator&& it) { return traits::remote(std::move(it)); } }; + template + struct algorithm_result_helper< + std::pair, + typename boost::enable_if< + typename boost::mpl::or_< + typename hpx::traits::segmented_local_iterator_traits< + Iterator1 + >::is_segmented_local_iterator, + typename hpx::traits::segmented_local_iterator_traits< + Iterator2 + >::is_segmented_local_iterator + >::type + >::type> + { + typedef hpx::traits::segmented_local_iterator_traits + traits1; + typedef hpx::traits::segmented_local_iterator_traits + traits2; + + static BOOST_FORCEINLINE + std::pair< + typename traits1::local_iterator, typename traits2::local_iterator + > + call(std::pair< + typename traits1::local_raw_iterator, + typename traits2::local_raw_iterator + > && p) + { + return std::make_pair( + traits1::remote(std::move(p.first)), + traits2::remote(std::move(p.second))); + } + }; + template struct algorithm_result_helper< future, @@ -63,20 +106,56 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail { typedef hpx::traits::segmented_local_iterator_traits traits; - static HPX_FORCEINLINE future + static BOOST_FORCEINLINE future call(future&& f) { typedef future argtype; - return f.then([](argtype&& f) { return traits::remote(f.get()); }); + return f.then( + [](argtype&& f) + { + return traits::remote(f.get()); + }); } }; - template <> - struct algorithm_result_helper > + template + struct algorithm_result_helper< + future >, + typename boost::enable_if< + typename boost::mpl::or_< + typename hpx::traits::segmented_local_iterator_traits< + Iterator1 + >::is_segmented_local_iterator, + typename hpx::traits::segmented_local_iterator_traits< + Iterator2 + >::is_segmented_local_iterator + >::type + >::type> { - static HPX_FORCEINLINE future call(future&& f) + typedef hpx::traits::segmented_local_iterator_traits + traits1; + typedef hpx::traits::segmented_local_iterator_traits + traits2; + + typedef std::pair< + typename traits1::local_raw_iterator, + typename traits2::local_raw_iterator + > arg_type; + + static BOOST_FORCEINLINE + future > + call(future && f) { - return std::move(f); + return f.then( + [](future && f) + { + auto p = f.get(); + return std::make_pair( + traits1::remote(p.first), + traits2::remote(p.second)); + }); } }; @@ -84,7 +163,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail template struct dispatcher_helper { - static HPX_FORCEINLINE R sequential(Algo const& algo, + static BOOST_FORCEINLINE R sequential(Algo const& algo, ExPolicy const& policy, Args const&... args) { using hpx::traits::segmented_local_iterator_traits; @@ -96,7 +175,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail ); } - static HPX_FORCEINLINE R parallel(Algo const& algo, + static BOOST_FORCEINLINE R parallel(Algo const& algo, ExPolicy const& policy, Args const&... args) { using hpx::traits::segmented_local_iterator_traits; @@ -112,7 +191,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail template struct dispatcher_helper { - static HPX_FORCEINLINE + static BOOST_FORCEINLINE typename parallel::util::detail::algorithm_result::type sequential(Algo const& algo, ExPolicy const& policy, Args const&... args) { @@ -122,7 +201,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail ); } - static HPX_FORCEINLINE + static BOOST_FORCEINLINE typename parallel::util::detail::algorithm_result::type parallel(Algo const& algo, ExPolicy const& policy, Args const&... args) { @@ -145,13 +224,13 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail result_type, Algo, ExPolicy, Args... > base_dispatcher; - static HPX_FORCEINLINE result_type sequential(Algo const& algo, + static BOOST_FORCEINLINE result_type sequential(Algo const& algo, ExPolicy const& policy, Args const&... args) { return base_dispatcher::sequential(algo, policy, args...); } - static HPX_FORCEINLINE result_type parallel(Algo const& algo, + static BOOST_FORCEINLINE result_type parallel(Algo const& algo, ExPolicy const& policy, Args const&... args) { return base_dispatcher::sequential(algo, policy, args...); @@ -188,7 +267,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail /////////////////////////////////////////////////////////////////////////// template - HPX_FORCEINLINE + BOOST_FORCEINLINE future::type::result_type> dispatch_async(id_type const& id, Algo && algo, ExPolicy const& policy, IsSeq, Args&&... args) @@ -208,7 +287,7 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail } template - HPX_FORCEINLINE + BOOST_FORCEINLINE typename hpx::util::decay::type::result_type dispatch(id_type const& id, Algo && algo, ExPolicy const& policy, IsSeq is_seq, Args&&... args) diff --git a/hpx/parallel/util/detail/algorithm_result.hpp b/hpx/parallel/util/detail/algorithm_result.hpp index 04e3caf4c5e5..1f9f6ce25bff 100644 --- a/hpx/parallel/util/detail/algorithm_result.hpp +++ b/hpx/parallel/util/detail/algorithm_result.hpp @@ -6,10 +6,12 @@ #if !defined(HPX_PARALLEL_DETAIL_ALGORITHM_RESULT_MAY_28_2014_1020PM) #define HPX_PARALLEL_DETAIL_ALGORITHM_RESULT_MAY_28_2014_1020PM -#include +#include +#include #include -#include #include +#include +#include #include @@ -184,6 +186,29 @@ namespace hpx { namespace parallel { namespace util { namespace detail static_assert(!boost::is_lvalue_reference::value, "T shouldn't be a lvalue reference"); }; + + /////////////////////////////////////////////////////////////////////////// + template ::value)> + typename hpx::util::result_of::type + convert_to_result(U && val, Conv && conv) + { + return hpx::util::invoke(conv, val); + } + + template ::value)> + hpx::future::type> + convert_to_result(hpx::future && f, Conv && conv) + { + typedef typename hpx::util::result_of::type result_type; + + return lcos::make_future( + std::move(f), std::forward(conv) + ); + } }}}} #endif diff --git a/hpx/parallel/util/zip_iterator.hpp b/hpx/parallel/util/zip_iterator.hpp index 8e83b340c705..4dd0d0b241de 100644 --- a/hpx/parallel/util/zip_iterator.hpp +++ b/hpx/parallel/util/zip_iterator.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2015 Hartmut Kaiser // Copyright (c) 2014 Agustin Berge // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -7,7 +7,9 @@ #if !defined(HPX_PARALLEL_UTIL_ZIP_ITERATOR_MAY_29_2014_0852PM) #define HPX_PARALLEL_UTIL_ZIP_ITERATOR_MAY_29_2014_0852PM -#include +#include +#include +#include #include #include #include @@ -16,41 +18,85 @@ namespace hpx { namespace parallel { HPX_INLINE_NAMESPACE(v1) { namespace detail { /////////////////////////////////////////////////////////////////////////// template - R get_iter(ZipIter&& zipiter) + R get_iter(ZipIter && zipiter) { return hpx::util::get(zipiter.get_iterator_tuple()); } template - R get_iter(hpx::future&& zipiter) + R get_iter(hpx::future && zipiter) { typedef typename hpx::util::tuple_element< N, typename ZipIter::iterator_tuple_type >::type result_type; - return zipiter.then( - [](hpx::future&& f) -> result_type + return lcos::make_future(std::move(zipiter), + [](ZipIter zipiter) { - return hpx::util::get(f.get().get_iterator_tuple()); + return get_iter(std::move(zipiter)); }); } /////////////////////////////////////////////////////////////////////////// - template - R get_iter_tuple(ZipIter&& zipiter) + template + typename ZipIter::iterator_tuple_type + get_iter_tuple(ZipIter && zipiter) { return zipiter.get_iterator_tuple(); } - template - R get_iter_tuple(hpx::future&& zipiter) + template + hpx::future + get_iter_tuple(hpx::future && zipiter) { typedef typename ZipIter::iterator_tuple_type result_type; + return lcos::make_future(std::move(zipiter), + [](ZipIter zipiter) + { + return get_iter_tuple(std::move(zipiter)); + }); + } + + /////////////////////////////////////////////////////////////////////////// + template + std::pair< + typename hpx::util::tuple_element< + 0, typename ZipIter::iterator_tuple_type + >::type, + typename hpx::util::tuple_element< + 1, typename ZipIter::iterator_tuple_type + >::type + > + get_iter_pair(ZipIter && zipiter) + { + typedef typename ZipIter::iterator_tuple_type iterator_tuple_type; + + iterator_tuple_type const& t = zipiter.get_iterator_tuple(); + return std::make_pair(hpx::util::get<0>(t), hpx::util::get<1>(t)); + } + + template + hpx::future::type, + typename hpx::util::tuple_element< + 1, typename ZipIter::iterator_tuple_type + >::type + > > + get_iter_pair(hpx::future && zipiter) + { + typedef typename ZipIter::iterator_tuple_type iterator_tuple_type; + + typedef std::pair< + typename hpx::util::tuple_element<0, iterator_tuple_type>::type, + typename hpx::util::tuple_element<1, iterator_tuple_type>::type + > result_type; - return zipiter.then( - [](hpx::future&& f) -> result_type + return lcos::make_future(std::move(zipiter), + [](ZipIter zipiter) { - return f.get().get_iterator_tuple(); + return get_iter_pair(std::move(zipiter)); }); } }}}} diff --git a/hpx/runtime/threads/policies/hwloc_topology.hpp b/hpx/runtime/threads/policies/hwloc_topology.hpp index b16bbf4c13c5..c781d6e6b9cc 100644 --- a/hpx/runtime/threads/policies/hwloc_topology.hpp +++ b/hpx/runtime/threads/policies/hwloc_topology.hpp @@ -30,6 +30,8 @@ #error On Intel Xeon/Phi coprosessors HPX cannot be use with a HWLOC version earlier than V1.6. #endif +#include + namespace hpx { namespace threads { struct HPX_EXPORT hwloc_topology : topology diff --git a/hpx/runtime/threads/topology.hpp b/hpx/runtime/threads/topology.hpp index 581b85ca78ac..980ef752b64c 100644 --- a/hpx/runtime/threads/topology.hpp +++ b/hpx/runtime/threads/topology.hpp @@ -214,7 +214,7 @@ namespace hpx { namespace threads #endif /// \endcond - struct topology + struct HPX_EXPORT topology { virtual ~topology() {} diff --git a/tests/regressions/parallel/scan_shortlength.cpp b/tests/regressions/parallel/scan_shortlength.cpp index 83624e80368a..67a357ba4317 100644 --- a/tests/regressions/parallel/scan_shortlength.cpp +++ b/tests/regressions/parallel/scan_shortlength.cpp @@ -18,13 +18,13 @@ void test_zero() std::vector a; std::vector b, c, d; - Iter i_copy_if = + std::pair p_copy_if = copy_if(par, a.begin(), a.end(), b.begin(), [](int bar){ return bar % 2 == 1; }); - Iter i_remove_copy_if = + std::pair p_remove_copy_if = remove_copy_if(par, a.begin(), a.end(), c.begin(), [](int bar){ return bar % 2 != 1; }); - Iter i_remove_copy = + std::pair p_remove_copy = remove_copy(par, a.begin(), a.end(), d.begin(), 0); Iter ans_copy_if = std::copy_if(a.begin(), a.end(), b.begin(), @@ -33,16 +33,16 @@ void test_zero() [](int bar){ return bar % 2 != 1; }); Iter ans_remove_copy = std::remove_copy(a.begin(), a.end(), d.begin(), 0); - HPX_TEST(i_copy_if == ans_copy_if); - HPX_TEST(i_remove_copy_if == ans_remove_copy_if); - HPX_TEST(i_remove_copy == ans_remove_copy); + HPX_TEST(p_copy_if.second == ans_copy_if); + HPX_TEST(p_remove_copy_if.second == ans_remove_copy_if); + HPX_TEST(p_remove_copy.second == ans_remove_copy); } void test_async_zero() { using namespace hpx::parallel; typedef std::vector::iterator Iter; - typedef hpx::future Fut_Iter; + typedef hpx::future > Fut_Iter; std::vector a; std::vector b, c, d; @@ -61,9 +61,9 @@ void test_async_zero() [](int bar){ return bar % 2 != 1; }); Iter ans_remove_copy = std::remove_copy(a.begin(), a.end(), d.begin(), 0); - HPX_TEST(f_copy_if.get() == ans_copy_if); - HPX_TEST(f_remove_copy_if.get() == ans_remove_copy_if); - HPX_TEST(f_remove_copy.get() == ans_remove_copy); + HPX_TEST(f_copy_if.get().second == ans_copy_if); + HPX_TEST(f_remove_copy_if.get().second == ans_remove_copy_if); + HPX_TEST(f_remove_copy.get().second == ans_remove_copy); } void test_one(std::vector a) @@ -74,18 +74,18 @@ void test_one(std::vector a) std::vector b(n), c(n), d(n); std::vector b_ans(n), c_ans(n), d_ans(n); - Iter i_copy_if = + std::pair p_copy_if = copy_if(par, a.begin(), a.end(), b.begin(), [](int bar){ return bar % 2 == 1; }); - Iter i_remove_copy_if = + std::pair p_remove_copy_if = remove_copy_if(par, a.begin(), a.end(), c.begin(), [](int bar){ return bar % 2 != 1; }); - Iter i_remove_copy = + std::pair p_remove_copy = remove_copy(par, a.begin(), a.end(), d.begin(), 0); - HPX_UNUSED(i_copy_if); - HPX_UNUSED(i_remove_copy_if); - HPX_UNUSED(i_remove_copy); + HPX_UNUSED(p_copy_if); + HPX_UNUSED(p_remove_copy_if); + HPX_UNUSED(p_remove_copy); std::copy_if(a.begin(), a.end(), b_ans.begin(), [](int bar){ return bar % 2 == 1; }); @@ -106,11 +106,11 @@ void print(std::vector const& result, std::vector const& correct) std::cout << i << ": " << result[i] << " == " << correct[i] << std::endl; } -void test_async_one(std::vector const& a) +void test_async_one(std::vector a) { using namespace hpx::parallel; typedef std::vector::iterator Iter; - typedef hpx::future Fut_Iter; + typedef hpx::future > Fut_Iter; std::size_t n = a.size(); std::vector b(n), c(n), d(n); std::vector b_ans(n), c_ans(n), d_ans(n); diff --git a/tests/unit/component/partitioned_vector_copy.cpp b/tests/unit/component/partitioned_vector_copy.cpp index a807dd7b7407..3ee77cd971de 100644 --- a/tests/unit/component/partitioned_vector_copy.cpp +++ b/tests/unit/component/partitioned_vector_copy.cpp @@ -73,9 +73,8 @@ void copy_algo_tests_with_policy(std::size_t size, std::size_t localities, fill_vector(v1, T(43)); hpx::partitioned_vector v2(size, policy); - typename hpx::partitioned_vector::iterator it = - hpx::parallel::copy(copy_policy, v1.begin(), v1.end(), v2.begin()); - HPX_TEST(it == v2.end()); + auto p = hpx::parallel::copy(copy_policy, v1.begin(), v1.end(), v2.begin()); + HPX_TEST(p.second == v2.end()); compare_vectors(v1, v2); } @@ -89,10 +88,9 @@ void copy_algo_tests_with_policy_async(std::size_t size, std::size_t localities, using hpx::parallel::task; hpx::partitioned_vector v2(size, policy); - hpx::future::iterator> f = - hpx::parallel::copy(copy_policy(task), v1.begin(), v1.end(), v2.begin()); + auto f = hpx::parallel::copy(copy_policy(task), v1.begin(), v1.end(), v2.begin()); - HPX_TEST(f.get() == v2.end()); + HPX_TEST(f.get().second == v2.end()); compare_vectors(v1, v2); } diff --git a/tests/unit/parallel/algorithms/copy.cpp b/tests/unit/parallel/algorithms/copy.cpp index 4c59d21ae001..c4ce913f04fa 100644 --- a/tests/unit/parallel/algorithms/copy.cpp +++ b/tests/unit/parallel/algorithms/copy.cpp @@ -49,7 +49,7 @@ void test_copy_async(ExPolicy p, IteratorTag) std::vector d(c.size()); std::iota(boost::begin(c), boost::end(c), std::rand()); - hpx::future f = + auto f = hpx::parallel::copy(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d)); @@ -209,7 +209,7 @@ void test_copy_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy(p, decorated_iterator( boost::begin(c), @@ -311,7 +311,7 @@ void test_copy_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy(p, decorated_iterator( boost::begin(c), diff --git a/tests/unit/parallel/algorithms/copyif_bad_alloc.cpp b/tests/unit/parallel/algorithms/copyif_bad_alloc.cpp index 0989ff257d79..57e0c0edd52f 100644 --- a/tests/unit/parallel/algorithms/copyif_bad_alloc.cpp +++ b/tests/unit/parallel/algorithms/copyif_bad_alloc.cpp @@ -60,13 +60,13 @@ void test_copy_if_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy_if(p, - iterator(boost::begin(c)), iterator(boost::end(c)), - boost::begin(d), - [](std::size_t v) { - return throw std::bad_alloc(), v != 0; - }); + iterator(boost::begin(c)), iterator(boost::end(c)), + boost::begin(d), + [](std::size_t v) { + return throw std::bad_alloc(), v != 0; + }); returned_from_algorithm = true; f.get(); diff --git a/tests/unit/parallel/algorithms/copyif_exception.cpp b/tests/unit/parallel/algorithms/copyif_exception.cpp index acf7b85b4825..bafdb8041955 100644 --- a/tests/unit/parallel/algorithms/copyif_exception.cpp +++ b/tests/unit/parallel/algorithms/copyif_exception.cpp @@ -60,7 +60,7 @@ void test_copy_if_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), diff --git a/tests/unit/parallel/algorithms/copyif_forward.cpp b/tests/unit/parallel/algorithms/copyif_forward.cpp index e7cac660fde5..7281c3597f55 100644 --- a/tests/unit/parallel/algorithms/copyif_forward.cpp +++ b/tests/unit/parallel/algorithms/copyif_forward.cpp @@ -64,7 +64,7 @@ void test_copy_if_async(ExPolicy p) std::iota(boost::begin(c), middle, std::rand()); std::fill(middle, boost::end(c), -1); - hpx::future f = + auto f = hpx::parallel::copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), [](int i){ return !(i < 0); }); diff --git a/tests/unit/parallel/algorithms/copyif_input.cpp b/tests/unit/parallel/algorithms/copyif_input.cpp index 12ec341153cf..f832d7b322ab 100644 --- a/tests/unit/parallel/algorithms/copyif_input.cpp +++ b/tests/unit/parallel/algorithms/copyif_input.cpp @@ -64,7 +64,7 @@ void test_copy_if_async(ExPolicy p) std::iota(boost::begin(c), middle, std::rand()); std::fill(middle, boost::end(c), -1); - hpx::future f = + auto f = hpx::parallel::copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), [](int i){ return !(i < 0); }); diff --git a/tests/unit/parallel/algorithms/copyif_random.cpp b/tests/unit/parallel/algorithms/copyif_random.cpp index 974e3fabff64..79444c16c410 100644 --- a/tests/unit/parallel/algorithms/copyif_random.cpp +++ b/tests/unit/parallel/algorithms/copyif_random.cpp @@ -21,7 +21,8 @@ void test_copy_if(ExPolicy policy) "hpx::parallel::is_execution_policy::value"); typedef std::vector::iterator base_iterator; - typedef test::test_iterator iterator; + typedef test::test_iterator + iterator; std::vector c(10007); std::vector d(c.size()); @@ -56,7 +57,8 @@ template void test_copy_if_async(ExPolicy p) { typedef std::vector::iterator base_iterator; - typedef test::test_iterator iterator; + typedef test::test_iterator + iterator; std::vector c(10007); std::vector d(c.size()); @@ -64,7 +66,7 @@ void test_copy_if_async(ExPolicy p) std::iota(boost::begin(c), middle, std::rand()); std::fill(middle, boost::end(c), -1); - hpx::future f = + auto f = hpx::parallel::copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), [](int i){ return !(i < 0); }); @@ -97,7 +99,8 @@ void test_copy_if_outiter(ExPolicy policy) "hpx::parallel::is_execution_policy::value"); typedef std::vector::iterator base_iterator; - typedef test::test_iterator iterator; + typedef test::test_iterator + iterator; std::vector c(10007); std::vector d(0); @@ -123,7 +126,8 @@ template void test_copy_if_outiter_async(ExPolicy p) { typedef std::vector::iterator base_iterator; - typedef test::test_iterator iterator; + typedef test::test_iterator + iterator; std::vector c(10007); std::vector d(0); diff --git a/tests/unit/parallel/algorithms/copyn.cpp b/tests/unit/parallel/algorithms/copyn.cpp index abc1389a43c7..032203479ba4 100644 --- a/tests/unit/parallel/algorithms/copyn.cpp +++ b/tests/unit/parallel/algorithms/copyn.cpp @@ -50,7 +50,7 @@ void test_copy_n_async(ExPolicy p, IteratorTag) std::vector d(c.size()); std::iota(boost::begin(c), boost::end(c), std::rand()); - hpx::future f = + auto f = hpx::parallel::copy_n(p, iterator(boost::begin(c)), c.size(), boost::begin(d)); f.wait(); @@ -212,7 +212,7 @@ void test_copy_n_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy_n(p, decorated_iterator( boost::begin(c), @@ -318,11 +318,11 @@ void test_copy_n_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy_n(p, decorated_iterator( boost::begin(c), - [](){throw std::bad_alloc();} + [](){ throw std::bad_alloc(); } ), c.size(), boost::begin(d)); diff --git a/tests/unit/parallel/algorithms/remove_copy.cpp b/tests/unit/parallel/algorithms/remove_copy.cpp index 2d47429e7e67..9b0950fd6fe1 100644 --- a/tests/unit/parallel/algorithms/remove_copy.cpp +++ b/tests/unit/parallel/algorithms/remove_copy.cpp @@ -56,7 +56,7 @@ void test_remove_copy_async(ExPolicy p, IteratorTag) std::fill(boost::begin(c), middle, 1); std::fill(middle, boost::end(c), 2); - hpx::future f = + auto f = hpx::parallel::remove_copy(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), std::size_t(2)); @@ -232,7 +232,7 @@ void test_remove_copy_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::remove_copy(p, decorated_iterator( boost::begin(c), @@ -334,7 +334,7 @@ void test_remove_copy_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::remove_copy(p, decorated_iterator( boost::begin(c), @@ -422,5 +422,4 @@ int main(int argc, char* argv[]) "HPX main exited with non-zero status"); return hpx::util::report_errors(); - } diff --git a/tests/unit/parallel/algorithms/remove_copy_if.cpp b/tests/unit/parallel/algorithms/remove_copy_if.cpp index 0754e7955f8c..30ce82ee3772 100644 --- a/tests/unit/parallel/algorithms/remove_copy_if.cpp +++ b/tests/unit/parallel/algorithms/remove_copy_if.cpp @@ -66,7 +66,7 @@ void test_remove_copy_if_async(ExPolicy p, IteratorTag) std::iota(boost::begin(c), middle, static_cast(std::rand() % c.size())); std::fill(middle, boost::end(c), -1); - hpx::future f = + auto f = hpx::parallel::remove_copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), [](int i){ return i < 0; }); @@ -238,7 +238,7 @@ void test_remove_copy_if_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::remove_copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), @@ -339,7 +339,7 @@ void test_remove_copy_if_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::remove_copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d), diff --git a/tests/unit/parallel/algorithms/replace.cpp b/tests/unit/parallel/algorithms/replace.cpp index cde031227b68..11192295d37c 100644 --- a/tests/unit/parallel/algorithms/replace.cpp +++ b/tests/unit/parallel/algorithms/replace.cpp @@ -12,7 +12,7 @@ #include "test_utils.hpp" -//////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// template void test_replace(ExPolicy policy, IteratorTag) { diff --git a/tests/unit/parallel/algorithms/replace_copy.cpp b/tests/unit/parallel/algorithms/replace_copy.cpp index ac654313c6c6..0ff3c9253fe8 100644 --- a/tests/unit/parallel/algorithms/replace_copy.cpp +++ b/tests/unit/parallel/algorithms/replace_copy.cpp @@ -62,7 +62,7 @@ void test_replace_copy_async(ExPolicy p, IteratorTag) std::size_t idx = std::rand() % c.size(); //-V104 - hpx::future f = + auto f = hpx::parallel::replace_copy(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d1), c[idx], c[idx]+1); @@ -158,7 +158,7 @@ void test_replace_copy_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::replace_copy(p, decorated_iterator( boost::begin(c), @@ -260,7 +260,7 @@ void test_replace_copy_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::replace_copy(p, decorated_iterator( boost::begin(c), diff --git a/tests/unit/parallel/algorithms/replace_copy_if.cpp b/tests/unit/parallel/algorithms/replace_copy_if.cpp index 5bec9afe3601..8c72b462970c 100644 --- a/tests/unit/parallel/algorithms/replace_copy_if.cpp +++ b/tests/unit/parallel/algorithms/replace_copy_if.cpp @@ -74,7 +74,7 @@ void test_replace_copy_if_async(ExPolicy p, IteratorTag) std::size_t idx = std::rand() % c.size(); //-V104 - hpx::future f = + auto f = hpx::parallel::replace_copy_if(p, iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d1), equal_f(c[idx]), c[idx]+1); @@ -170,7 +170,7 @@ void test_replace_copy_if_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::replace_copy_if(p, decorated_iterator( boost::begin(c), @@ -272,7 +272,7 @@ void test_replace_copy_if_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::replace_copy_if(p, decorated_iterator( boost::begin(c), diff --git a/tests/unit/parallel/algorithms/reverse_copy.cpp b/tests/unit/parallel/algorithms/reverse_copy.cpp index cc329b04938a..c4f5a36f39ac 100644 --- a/tests/unit/parallel/algorithms/reverse_copy.cpp +++ b/tests/unit/parallel/algorithms/reverse_copy.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2015 Hartmut Kaiser // // 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) @@ -151,7 +151,7 @@ void test_reverse_copy_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::reverse_copy(p, decorated_iterator(boost::begin(c)), decorated_iterator( @@ -254,7 +254,7 @@ void test_reverse_copy_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::reverse_copy(p, decorated_iterator(boost::begin(c)), decorated_iterator( diff --git a/tests/unit/parallel/algorithms/rotate_copy.cpp b/tests/unit/parallel/algorithms/rotate_copy.cpp index 2daf9f60a022..5ae5498154ba 100644 --- a/tests/unit/parallel/algorithms/rotate_copy.cpp +++ b/tests/unit/parallel/algorithms/rotate_copy.cpp @@ -170,7 +170,7 @@ void test_rotate_copy_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::rotate_copy(p, decorated_iterator( boost::begin(c), @@ -285,7 +285,7 @@ void test_rotate_copy_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::rotate_copy(p, decorated_iterator( boost::begin(c), diff --git a/tests/unit/parallel/container_algorithms/CMakeLists.txt b/tests/unit/parallel/container_algorithms/CMakeLists.txt index 75d6c18934cf..82ee71e72a88 100644 --- a/tests/unit/parallel/container_algorithms/CMakeLists.txt +++ b/tests/unit/parallel/container_algorithms/CMakeLists.txt @@ -8,6 +8,16 @@ set(tests copyif_range foreach_range foreach_range_projection + remove_copy_range + remove_copy_if_range + replace_range + replace_copy_range + replace_copy_if_range + replace_if_range + reverse_range + reverse_copy_range + rotate_range + rotate_copy_range sort_range transform_range transform_range_binary diff --git a/tests/unit/parallel/container_algorithms/copy_range.cpp b/tests/unit/parallel/container_algorithms/copy_range.cpp index 55b9ed72b8e1..483086c91e0b 100644 --- a/tests/unit/parallel/container_algorithms/copy_range.cpp +++ b/tests/unit/parallel/container_algorithms/copy_range.cpp @@ -49,8 +49,7 @@ void test_copy_async(ExPolicy p, IteratorTag) std::vector d(c.size()); std::iota(boost::begin(c), boost::end(c), std::rand()); - hpx::future f = - hpx::parallel::copy(p, c, boost::begin(d)); + auto f = hpx::parallel::copy(p, c, boost::begin(d)); f.wait(); std::size_t count = 0; @@ -204,7 +203,7 @@ void test_copy_exception_async(ExPolicy p, IteratorTag) bool caught_exception = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy(p, boost::make_iterator_range( decorated_iterator( @@ -308,7 +307,7 @@ void test_copy_bad_alloc_async(ExPolicy p, IteratorTag) bool caught_bad_alloc = false; bool returned_from_algorithm = false; try { - hpx::future f = + auto f = hpx::parallel::copy(p, boost::make_iterator_range( decorated_iterator( diff --git a/tests/unit/parallel/container_algorithms/copyif_range.cpp b/tests/unit/parallel/container_algorithms/copyif_range.cpp index db545f156aba..920845e755e3 100644 --- a/tests/unit/parallel/container_algorithms/copyif_range.cpp +++ b/tests/unit/parallel/container_algorithms/copyif_range.cpp @@ -64,7 +64,7 @@ void test_copy_if_async(ExPolicy p) std::iota(boost::begin(c), middle, std::rand()); std::fill(middle, boost::end(c), -1); - hpx::future f = + auto f = hpx::parallel::copy_if(p, c, boost::begin(d), [](int i){ return !(i < 0); }); f.wait(); diff --git a/tests/unit/parallel/container_algorithms/remove_copy_if_range.cpp b/tests/unit/parallel/container_algorithms/remove_copy_if_range.cpp new file mode 100644 index 000000000000..5bf52b30533f --- /dev/null +++ b/tests/unit/parallel/container_algorithms/remove_copy_if_range.cpp @@ -0,0 +1,434 @@ +// Copyright (c) 2015 Daniel Bourgeois +// +// 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 "test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +template +void test_remove_copy_if(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()); + std::size_t middle_idx = std::rand() % (c.size()/2); + auto middle = hpx::parallel::v1::detail::next(boost::begin(c), middle_idx); + std::iota(boost::begin(c), middle, static_cast(std::rand() % c.size())); + std::fill(middle, boost::end(c), -1); + + hpx::parallel::remove_copy_if(policy, c, boost::begin(d), + [](int i){ return i < 0; }); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), middle, boost::begin(d), + [&count](int v1, int v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + + HPX_TEST(std::equal(middle, boost::end(c), + boost::begin(d) + middle_idx, + [&count](int v1, int v2) -> bool { + HPX_TEST_NEQ(v1, v2); + ++count; + return v1 != v2; + })); + + HPX_TEST_EQ(count, d.size()); +} + +template +void test_remove_copy_if_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()); + std::size_t middle_idx = std::rand() % (c.size()/2); + auto middle = hpx::parallel::v1::detail::next(boost::begin(c), middle_idx); + std::iota(boost::begin(c), middle, static_cast(std::rand() % c.size())); + std::fill(middle, boost::end(c), -1); + + auto f = + hpx::parallel::remove_copy_if(p, c, + boost::begin(d), [](int i){ return i < 0; }); + f.wait(); + + std::size_t count = 0; + HPX_TEST(std::equal( + boost::begin(c), middle, boost::begin(d), + [&count](int v1, int v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + + HPX_TEST(std::equal(middle, boost::end(c), + boost::begin(d) + middle_idx, + [&count](int v1, int v2) -> bool { + HPX_TEST_NEQ(v1, v2); + ++count; + return v1!=v2; + })); + + HPX_TEST_EQ(count, d.size()); +} + +template +void test_remove_copy_if_outiter(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(0); + std::size_t middle_idx = std::rand() % (c.size()/2); + auto middle = hpx::parallel::v1::detail::next(boost::begin(c), middle_idx); + std::iota(boost::begin(c), middle, static_cast(std::rand() % c.size())); + std::fill(middle, boost::end(c), -1); + + hpx::parallel::remove_copy_if(policy, c, + std::back_inserter(d), [](int i){ return i < 0; }); + + HPX_TEST(std::equal(boost::begin(c), middle, boost::begin(d), + [](int v1, int v2) -> bool { + HPX_TEST_EQ(v1, v2); + return v1 == v2; + })); + + HPX_TEST_EQ(middle_idx, d.size()); +} + +template +void test_remove_copy_if_outiter_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(0); + std::size_t middle_idx = std::rand() % (c.size()/2); + auto middle = hpx::parallel::v1::detail::next(boost::begin(c), middle_idx); + std::iota(boost::begin(c), middle, static_cast(std::rand() % c.size())); + std::fill(middle, boost::end(c), -1); + + auto f = + hpx::parallel::remove_copy_if(p, c, + std::back_inserter(d), [](int i){ return i < 0; }); + f.wait(); + + HPX_TEST(std::equal(boost::begin(c), middle, boost::begin(d), + [](int v1, int v2) -> bool { + HPX_TEST_EQ(v1, v2); + return v1 == v2; + })); + + HPX_TEST_EQ(middle_idx, d.size()); +} + +template +void test_remove_copy_if() +{ + using namespace hpx::parallel; + + test_remove_copy_if(seq, IteratorTag()); + test_remove_copy_if(par, IteratorTag()); + test_remove_copy_if(par_vec, IteratorTag()); + + test_remove_copy_if_async(seq(task), IteratorTag()); + test_remove_copy_if_async(par(task), IteratorTag()); + + test_remove_copy_if(execution_policy(seq), IteratorTag()); + test_remove_copy_if(execution_policy(par), IteratorTag()); + test_remove_copy_if(execution_policy(par_vec), IteratorTag()); + + test_remove_copy_if(execution_policy(seq(task)), IteratorTag()); + test_remove_copy_if(execution_policy(par(task)), IteratorTag()); + + test_remove_copy_if_outiter(seq, IteratorTag()); + test_remove_copy_if_outiter(par, IteratorTag()); + test_remove_copy_if_outiter(par_vec, IteratorTag()); + + test_remove_copy_if_outiter_async(seq(task), IteratorTag()); + test_remove_copy_if_outiter_async(par(task), IteratorTag()); + + test_remove_copy_if_outiter(execution_policy(seq), IteratorTag()); + test_remove_copy_if_outiter(execution_policy(par), IteratorTag()); + test_remove_copy_if_outiter(execution_policy(par_vec), IteratorTag()); + + test_remove_copy_if_outiter(execution_policy(seq(task)), IteratorTag()); + test_remove_copy_if_outiter(execution_policy(par(task)), IteratorTag()); +} + +void remove_copy_if_test() +{ + test_remove_copy_if(); + test_remove_copy_if(); + test_remove_copy_if(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_remove_copy_if_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + try { + hpx::parallel::remove_copy_if(policy, + c, boost::begin(d), + [](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_remove_copy_if_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::remove_copy_if(p, c, + boost::begin(d), + [](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_remove_copy_if_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_remove_copy_if_exception(seq, IteratorTag()); + test_remove_copy_if_exception(par, IteratorTag()); + + test_remove_copy_if_exception_async(seq(task), IteratorTag()); + test_remove_copy_if_exception_async(par(task), IteratorTag()); + + test_remove_copy_if_exception(execution_policy(seq), IteratorTag()); + test_remove_copy_if_exception(execution_policy(par), IteratorTag()); + + test_remove_copy_if_exception(execution_policy(seq(task)), IteratorTag()); + test_remove_copy_if_exception(execution_policy(par(task)), IteratorTag()); +} + +void remove_copy_if_exception_test() +{ + test_remove_copy_if_exception(); + test_remove_copy_if_exception(); + test_remove_copy_if_exception(); +} + +//////////////////////////////////////////////////////////////////////////////// +template +void test_remove_copy_if_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + try { + hpx::parallel::remove_copy_if(policy, + c, boost::begin(d), + [](std::size_t v) { + return throw std::bad_alloc(), v; + }); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_remove_copy_if_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::remove_copy_if(p, c, + boost::begin(d), + [](std::size_t v) { + return throw std::bad_alloc(), v; + }); + + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_remove_copy_if_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_remove_copy_if_bad_alloc(seq, IteratorTag()); + test_remove_copy_if_bad_alloc(par, IteratorTag()); + + test_remove_copy_if_bad_alloc_async(seq(task), IteratorTag()); + test_remove_copy_if_bad_alloc_async(par(task), IteratorTag()); + + test_remove_copy_if_bad_alloc(execution_policy(seq), IteratorTag()); + test_remove_copy_if_bad_alloc(execution_policy(par), IteratorTag()); + + test_remove_copy_if_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_remove_copy_if_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void remove_copy_if_bad_alloc_test() +{ + test_remove_copy_if_bad_alloc(); + test_remove_copy_if_bad_alloc(); + test_remove_copy_if_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + remove_copy_if_test(); + remove_copy_if_exception_test(); + remove_copy_if_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/remove_copy_range.cpp b/tests/unit/parallel/container_algorithms/remove_copy_range.cpp new file mode 100644 index 000000000000..341c603a0f9a --- /dev/null +++ b/tests/unit/parallel/container_algorithms/remove_copy_range.cpp @@ -0,0 +1,437 @@ +// Copyright (c) 2015 Daniel Bourgeois +// +// 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 "test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////////// +template +void test_remove_copy(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()/2); + std::size_t middle_idx =std::rand() % (c.size()/2); + auto middle = hpx::parallel::v1::detail::next(boost::begin(c), middle_idx); + std::fill(boost::begin(c), middle, 1); + std::fill(middle, boost::end(c), 2); + + hpx::parallel::remove_copy(policy, c, boost::begin(d), std::size_t(2)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), middle, boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, middle_idx); +} + +template +void test_remove_copy_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()/2); + std::size_t middle_idx = std::rand() % (c.size()/2); + auto middle = hpx::parallel::v1::detail::next(boost::begin(c), middle_idx); + std::fill(boost::begin(c), middle, 1); + std::fill(middle, boost::end(c), 2); + + auto f = hpx::parallel::remove_copy(p, c, boost::begin(d), std::size_t(2)); + f.wait(); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), middle, boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, middle_idx); +} + +template +void test_remove_copy_outiter(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(0); + std::iota(boost::begin(c), boost::end(c), 0); + + hpx::parallel::remove_copy(policy, c, + std::back_inserter(d), std::size_t(3000)); + + std::size_t count = 0; + HPX_TEST(std::equal( + boost::begin(c.base()), boost::begin(c.base()) + 3000, + boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST(std::equal( + boost::begin(c.base())+3001, boost::end(c.base()), + boost::begin(d) + 3000, + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_remove_copy_outiter_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(0); + std::iota(boost::begin(c), boost::end(c), 0); + + auto f = + hpx::parallel::remove_copy(p, c, + std::back_inserter(d), std::size_t(3000)); + f.wait(); + + std::size_t count = 0; + HPX_TEST( + std::equal(boost::begin(c.base()), boost::begin(c.base()) + 3000, + boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST(std::equal( + boost::begin(c.base())+3001, boost::end(c.base()), + boost::begin(d) + 3000, + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_remove_copy() +{ + using namespace hpx::parallel; + test_remove_copy(seq, IteratorTag()); + test_remove_copy(par, IteratorTag()); + test_remove_copy(par_vec, IteratorTag()); + + test_remove_copy_async(seq(task), IteratorTag()); + test_remove_copy_async(par(task), IteratorTag()); + + test_remove_copy(execution_policy(seq), IteratorTag()); + test_remove_copy(execution_policy(par), IteratorTag()); + test_remove_copy(execution_policy(par_vec), IteratorTag()); + + test_remove_copy(execution_policy(seq(task)), IteratorTag()); + test_remove_copy(execution_policy(par(task)), IteratorTag()); + + //assure output iterator will work + test_remove_copy_outiter(seq, IteratorTag()); + test_remove_copy_outiter(par, IteratorTag()); + test_remove_copy_outiter(par_vec, IteratorTag()); + + test_remove_copy_outiter_async(seq(task), IteratorTag()); + test_remove_copy_outiter_async(par(task), IteratorTag()); + + test_remove_copy_outiter(execution_policy(seq), IteratorTag()); + test_remove_copy_outiter(execution_policy(par), IteratorTag()); + test_remove_copy_outiter(execution_policy(par_vec), IteratorTag()); + + test_remove_copy_outiter(execution_policy(seq(task)), IteratorTag()); + test_remove_copy_outiter(execution_policy(par(task)), IteratorTag()); +} + +void remove_copy_test() +{ + test_remove_copy(); + test_remove_copy(); + test_remove_copy(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_remove_copy_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), 0); + + bool caught_exception = false; + try { + hpx::parallel::remove_copy(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(3000)); + 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_remove_copy_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), 0); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::remove_copy(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(3000)); + 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_remove_copy_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_remove_copy_exception(seq, IteratorTag()); + test_remove_copy_exception(par, IteratorTag()); + + test_remove_copy_exception_async(seq(task), IteratorTag()); + test_remove_copy_exception_async(par(task), IteratorTag()); + + test_remove_copy_exception(execution_policy(seq), IteratorTag()); + test_remove_copy_exception(execution_policy(par), IteratorTag()); + + test_remove_copy_exception(execution_policy(seq(task)), IteratorTag()); + test_remove_copy_exception(execution_policy(par(task)), IteratorTag()); +} + +void remove_copy_exception_test() +{ + test_remove_copy_exception(); + test_remove_copy_exception(); + test_remove_copy_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_remove_copy_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), 0); + + bool caught_bad_alloc = false; + try { + hpx::parallel::remove_copy(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(3000)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_remove_copy_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), 0); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::remove_copy(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(3000)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_remove_copy_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_remove_copy_bad_alloc(seq, IteratorTag()); + test_remove_copy_bad_alloc(par, IteratorTag()); + + test_remove_copy_bad_alloc_async(seq(task), IteratorTag()); + test_remove_copy_bad_alloc_async(par(task), IteratorTag()); + + test_remove_copy_bad_alloc(execution_policy(seq), IteratorTag()); + test_remove_copy_bad_alloc(execution_policy(par), IteratorTag()); + + test_remove_copy_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_remove_copy_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void remove_copy_bad_alloc_test() +{ + test_remove_copy_bad_alloc(); + test_remove_copy_bad_alloc(); + test_remove_copy_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + remove_copy_test(); + remove_copy_exception_test(); + remove_copy_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/replace_copy_if_range.cpp b/tests/unit/parallel/container_algorithms/replace_copy_if_range.cpp new file mode 100644 index 000000000000..15e0939f8bad --- /dev/null +++ b/tests/unit/parallel/container_algorithms/replace_copy_if_range.cpp @@ -0,0 +1,368 @@ +// Copyright (c) 2014-2015 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +struct equal_f +{ + equal_f(std::size_t val) : val_(val) {} + + bool operator()(std::size_t lhs) const + { + return lhs == val_; + } + + std::size_t val_; +}; + +template +void test_replace_copy_if(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::parallel::replace_copy_if(policy, c, boost::begin(d1), + equal_f(c[idx]), c[idx]+1); + + std::replace_copy_if(boost::begin(c), boost::end(c), boost::begin(d2), + equal_f(c[idx]), c[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy_if_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + auto f = + hpx::parallel::replace_copy_if(p, c, + boost::begin(d1), equal_f(c[idx]), c[idx]+1); + f.wait(); + + std::replace_copy_if(boost::begin(c), boost::end(c), + boost::begin(d2), equal_f(c[idx]), c[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy_if() +{ + using namespace hpx::parallel; + test_replace_copy_if(seq, IteratorTag()); + test_replace_copy_if(par, IteratorTag()); + test_replace_copy_if(par_vec, IteratorTag()); + + test_replace_copy_if_async(seq(task), IteratorTag()); + test_replace_copy_if_async(par(task), IteratorTag()); + + test_replace_copy_if(execution_policy(seq), IteratorTag()); + test_replace_copy_if(execution_policy(par), IteratorTag()); + test_replace_copy_if(execution_policy(par_vec), IteratorTag()); + + test_replace_copy_if(execution_policy(seq(task)), IteratorTag()); + test_replace_copy_if(execution_policy(par(task)), IteratorTag()); +} + +void replace_copy_if_test() +{ + test_replace_copy_if(); + test_replace_copy_if(); + test_replace_copy_if(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_replace_copy_if_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + try { + hpx::parallel::replace_copy_if(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + boost::begin(d), equal_f(42), std::size_t(43)); + 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_replace_copy_if_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace_copy_if(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + boost::begin(d), equal_f(42), std::size_t(43)); + 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_replace_copy_if_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_replace_copy_if_exception(seq, IteratorTag()); + test_replace_copy_if_exception(par, IteratorTag()); + + test_replace_copy_if_exception_async(seq(task), IteratorTag()); + test_replace_copy_if_exception_async(par(task), IteratorTag()); + + test_replace_copy_if_exception(execution_policy(seq), IteratorTag()); + test_replace_copy_if_exception(execution_policy(par), IteratorTag()); + + test_replace_copy_if_exception(execution_policy(seq(task)), IteratorTag()); + test_replace_copy_if_exception(execution_policy(par(task)), IteratorTag()); +} + +void replace_copy_if_exception_test() +{ + test_replace_copy_if_exception(); + test_replace_copy_if_exception(); + test_replace_copy_if_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_replace_copy_if_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + try { + hpx::parallel::replace_copy_if(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + boost::begin(d), equal_f(42), std::size_t(43)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_replace_copy_if_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace_copy_if(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + boost::begin(d), equal_f(42), std::size_t(43)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_replace_copy_if_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_replace_copy_if_bad_alloc(seq, IteratorTag()); + test_replace_copy_if_bad_alloc(par, IteratorTag()); + + test_replace_copy_if_bad_alloc_async(seq(task), IteratorTag()); + test_replace_copy_if_bad_alloc_async(par(task), IteratorTag()); + + test_replace_copy_if_bad_alloc(execution_policy(seq), IteratorTag()); + test_replace_copy_if_bad_alloc(execution_policy(par), IteratorTag()); + + test_replace_copy_if_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_replace_copy_if_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void replace_copy_if_bad_alloc_test() +{ + test_replace_copy_if_bad_alloc(); + test_replace_copy_if_bad_alloc(); + test_replace_copy_if_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_copy_if_test(); + replace_copy_if_exception_test(); + replace_copy_if_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/replace_copy_range.cpp b/tests/unit/parallel/container_algorithms/replace_copy_range.cpp new file mode 100644 index 000000000000..072ea6859564 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/replace_copy_range.cpp @@ -0,0 +1,354 @@ +// Copyright (c) 2014-2015 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +template +void test_replace_copy(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::parallel::replace_copy(policy, c, boost::begin(d1), c[idx], c[idx]+1); + + std::replace_copy(boost::begin(c), boost::end(c), + boost::begin(d2), c[idx], c[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + std::size_t idx = std::rand() % c.size(); //-V104 + + auto f = hpx::parallel::replace_copy(p, c, boost::begin(d1), c[idx], c[idx]+1); + f.wait(); + + std::replace_copy(boost::begin(c), boost::end(c), + boost::begin(d2), c[idx], c[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_replace_copy() +{ + using namespace hpx::parallel; + test_replace_copy(seq, IteratorTag()); + test_replace_copy(par, IteratorTag()); + test_replace_copy(par_vec, IteratorTag()); + + test_replace_copy_async(seq(task), IteratorTag()); + test_replace_copy_async(par(task), IteratorTag()); + + test_replace_copy(execution_policy(seq), IteratorTag()); + test_replace_copy(execution_policy(par), IteratorTag()); + test_replace_copy(execution_policy(par_vec), IteratorTag()); + + test_replace_copy(execution_policy(seq(task)), IteratorTag()); + test_replace_copy(execution_policy(par(task)), IteratorTag()); +} + +void replace_copy_test() +{ + test_replace_copy(); + test_replace_copy(); + test_replace_copy(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_replace_copy_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + try { + hpx::parallel::replace_copy(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(42), std::size_t(43)); + 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_replace_copy_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace_copy(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(42), std::size_t(43)); + 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_replace_copy_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_replace_copy_exception(seq, IteratorTag()); + test_replace_copy_exception(par, IteratorTag()); + + test_replace_copy_exception_async(seq(task), IteratorTag()); + test_replace_copy_exception_async(par(task), IteratorTag()); + + test_replace_copy_exception(execution_policy(seq), IteratorTag()); + test_replace_copy_exception(execution_policy(par), IteratorTag()); + + test_replace_copy_exception(execution_policy(seq(task)), IteratorTag()); + test_replace_copy_exception(execution_policy(par(task)), IteratorTag()); +} + +void replace_copy_exception_test() +{ + test_replace_copy_exception(); + test_replace_copy_exception(); + test_replace_copy_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_replace_copy_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + try { + hpx::parallel::replace_copy(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(42), std::size_t(43)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_replace_copy_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace_copy(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + boost::begin(d), std::size_t(42), std::size_t(43)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_replace_copy_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_replace_copy_bad_alloc(seq, IteratorTag()); + test_replace_copy_bad_alloc(par, IteratorTag()); + + test_replace_copy_bad_alloc_async(seq(task), IteratorTag()); + test_replace_copy_bad_alloc_async(par(task), IteratorTag()); + + test_replace_copy_bad_alloc(execution_policy(seq), IteratorTag()); + test_replace_copy_bad_alloc(execution_policy(par), IteratorTag()); + + test_replace_copy_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_replace_copy_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void replace_copy_bad_alloc_test() +{ + test_replace_copy_bad_alloc(); + test_replace_copy_bad_alloc(); + test_replace_copy_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_copy_test(); + replace_copy_exception_test(); + replace_copy_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/replace_if_range.cpp b/tests/unit/parallel/container_algorithms/replace_if_range.cpp new file mode 100644 index 000000000000..7ffd3b72d272 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/replace_if_range.cpp @@ -0,0 +1,355 @@ +// Copyright (c) 2014-2015 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +struct equal_f +{ + equal_f(std::size_t val) : val_(val) {} + + bool operator()(std::size_t lhs) const + { + return lhs == val_; + } + + std::size_t val_; +}; + +template +void test_replace_if(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), boost::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::parallel::replace_if(policy, c, equal_f(c[idx]), c[idx]+1); + + std::replace_if(boost::begin(d), boost::end(d), equal_f(d[idx]), d[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace_if_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), boost::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + auto f = hpx::parallel::replace_if(p, c, equal_f(c[idx]), c[idx]+1); + f.wait(); + + std::replace_if(boost::begin(d), boost::end(d), equal_f(d[idx]), d[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace_if() +{ + using namespace hpx::parallel; + test_replace_if(seq, IteratorTag()); + test_replace_if(par, IteratorTag()); + test_replace_if(par_vec, IteratorTag()); + + test_replace_if_async(seq(task), IteratorTag()); + test_replace_if_async(par(task), IteratorTag()); + + test_replace_if(execution_policy(seq), IteratorTag()); + test_replace_if(execution_policy(par), IteratorTag()); + test_replace_if(execution_policy(par_vec), IteratorTag()); + + test_replace_if(execution_policy(seq(task)), IteratorTag()); + test_replace_if(execution_policy(par(task)), IteratorTag()); +} + +void replace_if_test() +{ + test_replace_if(); + test_replace_if(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_replace_if_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + try { + hpx::parallel::replace_if(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + equal_f(42), std::size_t(43)); + 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_replace_if_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace_if(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + equal_f(42), std::size_t(43)); + 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_replace_if_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_replace_if_exception(seq, IteratorTag()); + test_replace_if_exception(par, IteratorTag()); + + test_replace_if_exception_async(seq(task), IteratorTag()); + test_replace_if_exception_async(par(task), IteratorTag()); + + test_replace_if_exception(execution_policy(seq), IteratorTag()); + test_replace_if_exception(execution_policy(par), IteratorTag()); + + test_replace_if_exception(execution_policy(seq(task)), IteratorTag()); + test_replace_if_exception(execution_policy(par(task)), IteratorTag()); +} + +void replace_if_exception_test() +{ + test_replace_if_exception(); + test_replace_if_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_replace_if_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + try { + hpx::parallel::replace_if(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + equal_f(42), std::size_t(43)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_replace_if_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace_if(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + equal_f(42), std::size_t(43)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_replace_if_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_replace_if_bad_alloc(seq, IteratorTag()); + test_replace_if_bad_alloc(par, IteratorTag()); + + test_replace_if_bad_alloc_async(seq(task), IteratorTag()); + test_replace_if_bad_alloc_async(par(task), IteratorTag()); + + test_replace_if_bad_alloc(execution_policy(seq), IteratorTag()); + test_replace_if_bad_alloc(execution_policy(par), IteratorTag()); + + test_replace_if_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_replace_if_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void replace_if_bad_alloc_test() +{ + test_replace_if_bad_alloc(); + test_replace_if_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_if_test(); + replace_if_exception_test(); + replace_if_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/replace_range.cpp b/tests/unit/parallel/container_algorithms/replace_range.cpp new file mode 100644 index 000000000000..a6a55cdd7bba --- /dev/null +++ b/tests/unit/parallel/container_algorithms/replace_range.cpp @@ -0,0 +1,343 @@ +// Copyright (c) 2014-2015 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_replace(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), boost::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + hpx::parallel::replace(policy, c, c[idx], c[idx]+1); + + std::replace(boost::begin(d), boost::end(d), d[idx], d[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), boost::begin(d)); + + std::size_t idx = std::rand() % c.size(); //-V104 + + auto f = hpx::parallel::replace(p, c, c[idx], c[idx]+1); + f.wait(); + + std::replace(boost::begin(d), boost::end(d), d[idx], d[idx]+1); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d.size()); +} + +template +void test_replace() +{ + using namespace hpx::parallel; + test_replace(seq, IteratorTag()); + test_replace(par, IteratorTag()); + test_replace(par_vec, IteratorTag()); + + test_replace_async(seq(task), IteratorTag()); + test_replace_async(par(task), IteratorTag()); + + test_replace(execution_policy(seq), IteratorTag()); + test_replace(execution_policy(par), IteratorTag()); + test_replace(execution_policy(par_vec), IteratorTag()); + + test_replace(execution_policy(seq(task)), IteratorTag()); + test_replace(execution_policy(par(task)), IteratorTag()); +} + +void replace_test() +{ + test_replace(); + test_replace(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_replace_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + try { + hpx::parallel::replace(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + std::size_t(42), std::size_t(43)); + 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_replace_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + std::size_t(42), std::size_t(43)); + 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_replace_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_replace_exception(seq, IteratorTag()); + test_replace_exception(par, IteratorTag()); + + test_replace_exception_async(seq(task), IteratorTag()); + test_replace_exception_async(par(task), IteratorTag()); + + test_replace_exception(execution_policy(seq), IteratorTag()); + test_replace_exception(execution_policy(par), IteratorTag()); + + test_replace_exception(execution_policy(seq(task)), IteratorTag()); + test_replace_exception(execution_policy(par(task)), IteratorTag()); +} + +void replace_exception_test() +{ + test_replace_exception(); + test_replace_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_replace_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + try { + hpx::parallel::replace(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + std::size_t(42), std::size_t(43)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_replace_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::replace(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + std::size_t(42), std::size_t(43)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_replace_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_replace_bad_alloc(seq, IteratorTag()); + test_replace_bad_alloc(par, IteratorTag()); + + test_replace_bad_alloc_async(seq(task), IteratorTag()); + test_replace_bad_alloc_async(par(task), IteratorTag()); + + test_replace_bad_alloc(execution_policy(seq), IteratorTag()); + test_replace_bad_alloc(execution_policy(par), IteratorTag()); + + test_replace_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_replace_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void replace_bad_alloc_test() +{ + test_replace_bad_alloc(); + test_replace_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + replace_test(); + replace_exception_test(); + replace_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/reverse_copy_range.cpp b/tests/unit/parallel/container_algorithms/reverse_copy_range.cpp new file mode 100644 index 000000000000..e74754ca8d66 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/reverse_copy_range.cpp @@ -0,0 +1,350 @@ +// Copyright (c) 2007-2015 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_reverse_copy(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + hpx::parallel::reverse_copy(policy, + iterator(boost::begin(c)), iterator(boost::end(c)), boost::begin(d1)); + + std::reverse_copy(boost::begin(c), boost::end(c), boost::begin(d2)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_reverse_copy_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + auto f = hpx::parallel::reverse_copy(p, c, boost::begin(d1)); + f.wait(); + + std::reverse_copy(boost::begin(c), boost::end(c), boost::begin(d2)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_reverse_copy() +{ + using namespace hpx::parallel; + test_reverse_copy(seq, IteratorTag()); + test_reverse_copy(par, IteratorTag()); + test_reverse_copy(par_vec, IteratorTag()); + + test_reverse_copy_async(seq(task), IteratorTag()); + test_reverse_copy_async(par(task), IteratorTag()); + + test_reverse_copy(execution_policy(seq), IteratorTag()); + test_reverse_copy(execution_policy(par), IteratorTag()); + test_reverse_copy(execution_policy(par_vec), IteratorTag()); + + test_reverse_copy(execution_policy(seq(task)), IteratorTag()); + test_reverse_copy(execution_policy(par(task)), IteratorTag()); +} + +void reverse_copy_test() +{ + test_reverse_copy(); + test_reverse_copy(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_reverse_copy_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + try { + hpx::parallel::reverse_copy(policy, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::runtime_error("test"); } + )), + boost::begin(d)); + 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_reverse_copy_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::reverse_copy(p, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::runtime_error("test"); } + )), + boost::begin(d)); + 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_reverse_copy_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_reverse_copy_exception(seq, IteratorTag()); + test_reverse_copy_exception(par, IteratorTag()); + + test_reverse_copy_exception_async(seq(task), IteratorTag()); + test_reverse_copy_exception_async(par(task), IteratorTag()); + + test_reverse_copy_exception(execution_policy(seq), IteratorTag()); + test_reverse_copy_exception(execution_policy(par), IteratorTag()); + + test_reverse_copy_exception(execution_policy(seq(task)), IteratorTag()); + test_reverse_copy_exception(execution_policy(par(task)), IteratorTag()); +} + +void reverse_copy_exception_test() +{ + test_reverse_copy_exception(); + test_reverse_copy_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_reverse_copy_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + try { + hpx::parallel::reverse_copy(policy, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::bad_alloc(); } + )), + boost::begin(d)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_reverse_copy_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::reverse_copy(p, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::bad_alloc(); } + )), + boost::begin(d)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_reverse_copy_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_reverse_copy_bad_alloc(seq, IteratorTag()); + test_reverse_copy_bad_alloc(par, IteratorTag()); + + test_reverse_copy_bad_alloc_async(seq(task), IteratorTag()); + test_reverse_copy_bad_alloc_async(par(task), IteratorTag()); + + test_reverse_copy_bad_alloc(execution_policy(seq), IteratorTag()); + test_reverse_copy_bad_alloc(execution_policy(par), IteratorTag()); + + test_reverse_copy_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_reverse_copy_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void reverse_copy_bad_alloc_test() +{ + test_reverse_copy_bad_alloc(); + test_reverse_copy_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + reverse_copy_test(); + reverse_copy_exception_test(); + reverse_copy_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/reverse_range.cpp b/tests/unit/parallel/container_algorithms/reverse_range.cpp new file mode 100644 index 000000000000..03f5d03fc286 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/reverse_range.cpp @@ -0,0 +1,342 @@ +// Copyright (c) 2007-2014 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_reverse(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1; + + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), std::back_inserter(d1)); + + hpx::parallel::reverse(policy, c); + + std::reverse(boost::begin(d1), boost::end(d1)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d1), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_reverse_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1; + + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), std::back_inserter(d1)); + + auto f = hpx::parallel::reverse(p, c); + f.wait(); + + std::reverse(boost::begin(d1), boost::end(d1)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d1), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_reverse() +{ + using namespace hpx::parallel; + test_reverse(seq, IteratorTag()); + test_reverse(par, IteratorTag()); + test_reverse(par_vec, IteratorTag()); + + test_reverse_async(seq(task), IteratorTag()); + test_reverse_async(par(task), IteratorTag()); + + test_reverse(execution_policy(seq), IteratorTag()); + test_reverse(execution_policy(par), IteratorTag()); + test_reverse(execution_policy(par_vec), IteratorTag()); + + test_reverse(execution_policy(seq(task)), IteratorTag()); + test_reverse(execution_policy(par(task)), IteratorTag()); +} + +void reverse_test() +{ + test_reverse(); + test_reverse(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_reverse_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + try { + hpx::parallel::reverse(policy, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::runtime_error("test"); } + ))); + 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_reverse_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::reverse(p, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::runtime_error("test"); } + ))); + 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_reverse_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_reverse_exception(seq, IteratorTag()); + test_reverse_exception(par, IteratorTag()); + + test_reverse_exception_async(seq(task), IteratorTag()); + test_reverse_exception_async(par(task), IteratorTag()); + + test_reverse_exception(execution_policy(seq), IteratorTag()); + test_reverse_exception(execution_policy(par), IteratorTag()); + + test_reverse_exception(execution_policy(seq(task)), IteratorTag()); + test_reverse_exception(execution_policy(par(task)), IteratorTag()); +} + +void reverse_exception_test() +{ + test_reverse_exception(); + test_reverse_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_reverse_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + try { + hpx::parallel::reverse(policy, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::bad_alloc(); } + ))); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_reverse_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::reverse(p, + boost::make_iterator_range( + decorated_iterator(boost::begin(c)), + decorated_iterator( + boost::end(c), + [](){ throw std::bad_alloc(); } + ))); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_reverse_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_reverse_bad_alloc(seq, IteratorTag()); + test_reverse_bad_alloc(par, IteratorTag()); + + test_reverse_bad_alloc_async(seq(task), IteratorTag()); + test_reverse_bad_alloc_async(par(task), IteratorTag()); + + test_reverse_bad_alloc(execution_policy(seq), IteratorTag()); + test_reverse_bad_alloc(execution_policy(par), IteratorTag()); + + test_reverse_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_reverse_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void reverse_bad_alloc_test() +{ + test_reverse_bad_alloc(); + test_reverse_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + reverse_test(); + reverse_exception_test(); + reverse_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/rotate_copy_range.cpp b/tests/unit/parallel/container_algorithms/rotate_copy_range.cpp new file mode 100644 index 000000000000..e9a653fceb54 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/rotate_copy_range.cpp @@ -0,0 +1,380 @@ +// Copyright (c) 2007-2015 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_rotate_copy(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + auto mid = boost::begin(c); + std::advance(mid, std::rand() % c.size()); //-V104 + + hpx::parallel::rotate_copy(policy, c, iterator(mid), boost::begin(d1)); + + std::rotate_copy(boost::begin(c), mid, boost::end(c), boost::begin(d2)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_rotate_copy_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1(c.size()); + std::vector d2(c.size()); //-V656 + + std::iota(boost::begin(c), boost::end(c), std::rand()); + + auto mid = boost::begin(c); + std::advance(mid, std::rand() % c.size()); //-V104 + + auto f = hpx::parallel::rotate_copy(p, c, iterator(mid), boost::begin(d1)); + f.wait(); + + std::rotate_copy(boost::begin(c), mid, boost::end(c), boost::begin(d2)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(d1), boost::end(d1), boost::begin(d2), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_rotate_copy() +{ + using namespace hpx::parallel; + test_rotate_copy(seq, IteratorTag()); + test_rotate_copy(par, IteratorTag()); + test_rotate_copy(par_vec, IteratorTag()); + + test_rotate_copy_async(seq(task), IteratorTag()); + test_rotate_copy_async(par(task), IteratorTag()); + + test_rotate_copy(execution_policy(seq), IteratorTag()); + test_rotate_copy(execution_policy(par), IteratorTag()); + test_rotate_copy(execution_policy(par_vec), IteratorTag()); + + test_rotate_copy(execution_policy(seq(task)), IteratorTag()); + test_rotate_copy(execution_policy(par(task)), IteratorTag()); +} + +void rotate_copy_test() +{ + test_rotate_copy(); + test_rotate_copy(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_rotate_copy_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(1)); //-V104 + std::advance(mid, delta); + + bool caught_exception = false; + try { + hpx::parallel::rotate_copy(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid), + boost::begin(d)); + 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_rotate_copy_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(1)); //-V104 + std::advance(mid, delta); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::rotate_copy(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid), + boost::begin(d)); + 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_rotate_copy_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_rotate_copy_exception(seq, IteratorTag()); + test_rotate_copy_exception(par, IteratorTag()); + + test_rotate_copy_exception_async(seq(task), IteratorTag()); + test_rotate_copy_exception_async(par(task), IteratorTag()); + + test_rotate_copy_exception(execution_policy(seq), IteratorTag()); + test_rotate_copy_exception(execution_policy(par), IteratorTag()); + + test_rotate_copy_exception(execution_policy(seq(task)), IteratorTag()); + test_rotate_copy_exception(execution_policy(par(task)), IteratorTag()); +} + +void rotate_copy_exception_test() +{ + test_rotate_copy_exception(); + test_rotate_copy_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_rotate_copy_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(1)); //-V104 + std::advance(mid, delta); + + bool caught_bad_alloc = false; + try { + hpx::parallel::rotate_copy(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid), + boost::begin(d)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_rotate_copy_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::vector d(c.size()); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(1)); //-V104 + std::advance(mid, delta); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::rotate_copy(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid), + boost::begin(d)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_rotate_copy_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_rotate_copy_bad_alloc(seq, IteratorTag()); + test_rotate_copy_bad_alloc(par, IteratorTag()); + + test_rotate_copy_bad_alloc_async(seq(task), IteratorTag()); + test_rotate_copy_bad_alloc_async(par(task), IteratorTag()); + + test_rotate_copy_bad_alloc(execution_policy(seq), IteratorTag()); + test_rotate_copy_bad_alloc(execution_policy(par), IteratorTag()); + + test_rotate_copy_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_rotate_copy_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void rotate_copy_bad_alloc_test() +{ + test_rotate_copy_bad_alloc(); + test_rotate_copy_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + rotate_copy_test(); + rotate_copy_exception_test(); + rotate_copy_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/rotate_range.cpp b/tests/unit/parallel/container_algorithms/rotate_range.cpp new file mode 100644 index 000000000000..eafadcc02041 --- /dev/null +++ b/tests/unit/parallel/container_algorithms/rotate_range.cpp @@ -0,0 +1,379 @@ +// Copyright (c) 2007-2014 Hartmut Kaiser +// +// 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 "test_utils.hpp" + +/////////////////////////////////////////////////////////////////////////////// +template +void test_rotate(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1; + + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), std::back_inserter(d1)); + + std::size_t mid_pos = std::rand() % c.size(); //-V104 + auto mid = boost::begin(c); + std::advance(mid, mid_pos); + + hpx::parallel::rotate(policy, c, iterator(mid)); + + base_iterator mid1 = boost::begin(d1); + std::advance(mid1, mid_pos); + std::rotate(boost::begin(d1), mid1, boost::end(d1)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d1), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_rotate_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::test_iterator iterator; + + typedef test::test_container, IteratorTag> test_vector; + + test_vector c(10007); + std::vector d1; + + std::iota(boost::begin(c), boost::end(c), std::rand()); + std::copy(boost::begin(c), boost::end(c), std::back_inserter(d1)); + + std::size_t mid_pos = std::rand() % c.size(); //-V104 + + auto mid = boost::begin(c); + std::advance(mid, mid_pos); + + auto f = hpx::parallel::rotate(p, c, iterator(mid)); + f.wait(); + + base_iterator mid1 = boost::begin(d1); + std::advance(mid1, mid_pos); + std::rotate(boost::begin(d1), mid1, boost::end(d1)); + + std::size_t count = 0; + HPX_TEST(std::equal(boost::begin(c), boost::end(c), boost::begin(d1), + [&count](std::size_t v1, std::size_t v2) -> bool { + HPX_TEST_EQ(v1, v2); + ++count; + return v1 == v2; + })); + HPX_TEST_EQ(count, d1.size()); +} + +template +void test_rotate() +{ + using namespace hpx::parallel; + test_rotate(seq, IteratorTag()); + test_rotate(par, IteratorTag()); + test_rotate(par_vec, IteratorTag()); + + test_rotate_async(seq(task), IteratorTag()); + test_rotate_async(par(task), IteratorTag()); + + test_rotate(execution_policy(seq), IteratorTag()); + test_rotate(execution_policy(par), IteratorTag()); + test_rotate(execution_policy(par_vec), IteratorTag()); + + test_rotate(execution_policy(seq(task)), IteratorTag()); + test_rotate(execution_policy(par(task)), IteratorTag()); +} + +void rotate_test() +{ + test_rotate(); + test_rotate(); +} + +/////////////////////////////////////////////////////////////////////////////// +template +void test_rotate_exception(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104 + std::advance(mid, delta); + + bool caught_exception = false; + try { + hpx::parallel::rotate(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid)); + 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_rotate_exception_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104 + std::advance(mid, delta); + + bool caught_exception = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::rotate(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::runtime_error("test"); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid)); + 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_rotate_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_rotate_exception(seq, IteratorTag()); + test_rotate_exception(par, IteratorTag()); + + test_rotate_exception_async(seq(task), IteratorTag()); + test_rotate_exception_async(par(task), IteratorTag()); + + test_rotate_exception(execution_policy(seq), IteratorTag()); + test_rotate_exception(execution_policy(par), IteratorTag()); + + test_rotate_exception(execution_policy(seq(task)), IteratorTag()); + test_rotate_exception(execution_policy(par(task)), IteratorTag()); +} + +void rotate_exception_test() +{ + test_rotate_exception(); + test_rotate_exception(); +} + +////////////////////////////////////////////////////////////////////////////// +template +void test_rotate_bad_alloc(ExPolicy policy, IteratorTag) +{ + static_assert( + hpx::parallel::is_execution_policy::value, + "hpx::parallel::is_execution_policy::value"); + + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104 + std::advance(mid, delta); + + bool caught_bad_alloc = false; + try { + hpx::parallel::rotate(policy, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid)); + HPX_TEST(false); + } + catch (std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch (...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); +} + +template +void test_rotate_bad_alloc_async(ExPolicy p, IteratorTag) +{ + typedef std::vector::iterator base_iterator; + typedef test::decorated_iterator + decorated_iterator; + + std::vector c(10007); + std::iota(boost::begin(c), boost::end(c), std::rand()); + + base_iterator mid = boost::begin(c); + + // move at least one element to guarantee an exception to be thrown + std::size_t delta = (std::max)(std::rand() % c.size(), std::size_t(2)); //-V104 + std::advance(mid, delta); + + bool caught_bad_alloc = false; + bool returned_from_algorithm = false; + try { + auto f = + hpx::parallel::rotate(p, + boost::make_iterator_range( + decorated_iterator( + boost::begin(c), + [](){ throw std::bad_alloc(); }), + decorated_iterator(boost::end(c))), + decorated_iterator(mid)); + returned_from_algorithm = true; + f.get(); + + HPX_TEST(false); + } + catch(std::bad_alloc const&) { + caught_bad_alloc = true; + } + catch(...) { + HPX_TEST(false); + } + + HPX_TEST(caught_bad_alloc); + HPX_TEST(returned_from_algorithm); +} + +template +void test_rotate_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_rotate_bad_alloc(seq, IteratorTag()); + test_rotate_bad_alloc(par, IteratorTag()); + + test_rotate_bad_alloc_async(seq(task), IteratorTag()); + test_rotate_bad_alloc_async(par(task), IteratorTag()); + + test_rotate_bad_alloc(execution_policy(seq), IteratorTag()); + test_rotate_bad_alloc(execution_policy(par), IteratorTag()); + + test_rotate_bad_alloc(execution_policy(seq(task)), IteratorTag()); + test_rotate_bad_alloc(execution_policy(par(task)), IteratorTag()); +} + +void rotate_bad_alloc_test() +{ + test_rotate_bad_alloc(); + test_rotate_bad_alloc(); +} + +int hpx_main(boost::program_options::variables_map& vm) +{ + unsigned int seed = (unsigned int)std::time(0); + if (vm.count("seed")) + seed = vm["seed"].as(); + + std::cout << "using seed: " << seed << std::endl; + std::srand(seed); + + rotate_test(); + rotate_exception_test(); + rotate_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 cfg; + cfg.push_back("hpx.os_threads=" + + boost::lexical_cast(hpx::threads::hardware_concurrency())); + + // 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/test_utils.hpp b/tests/unit/parallel/container_algorithms/test_utils.hpp index cd9f89d6a8fd..51e11c633460 100644 --- a/tests/unit/parallel/container_algorithms/test_utils.hpp +++ b/tests/unit/parallel/container_algorithms/test_utils.hpp @@ -32,6 +32,52 @@ namespace test test_iterator(BaseIterator base) : base_type(base) {} }; + /////////////////////////////////////////////////////////////////////////// + template + struct test_container : BaseContainer + { + template + test_container(Ts && ...ts) + : BaseContainer(std::forward(ts)...) + {} + + BaseContainer& base() { return *this; } + BaseContainer const& base() const { return *this; } + + typedef test_iterator< + typename BaseContainer::iterator, IteratorTag + > iterator; + typedef test_iterator< + typename BaseContainer::const_iterator, IteratorTag + > const_iterator; + + iterator begin() + { + return iterator(this->BaseContainer::begin()); + } + const_iterator begin() const + { + return const_iterator(this->BaseContainer::begin()); + } + const_iterator cbegin() const + { + return const_iterator(this->BaseContainer::cbegin()); + } + + iterator end() + { + return iterator(this->BaseContainer::end()); + } + const_iterator end() const + { + return const_iterator(this->BaseContainer::end()); + } + const_iterator cend() const + { + return const_iterator(this->BaseContainer::cend()); + } + }; + /////////////////////////////////////////////////////////////////////////// template struct decorated_iterator