diff --git a/cmake/HPX_Documentation.cmake b/cmake/HPX_Documentation.cmake
index aaac29a32c32..fe9b38887fcb 100644
--- a/cmake/HPX_Documentation.cmake
+++ b/cmake/HPX_Documentation.cmake
@@ -5,6 +5,7 @@
# 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)
+# find required packages
if(HPX_WITH_DOCUMENTATION)
find_package(Doxygen)
find_package(Sphinx)
@@ -27,22 +28,3 @@ if(HPX_WITH_DOCUMENTATION)
set(HPX_WITH_DOCUMENTATION OFF)
endif()
endif()
-
-# C++ Source -> Doxygen XML
-function(hpx_source_to_doxygen name)
- set(options)
- set(one_value_args)
- set(multi_value_args DEPENDENCIES DOXYGEN_ARGS)
- cmake_parse_arguments(
- ${name} "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}
- )
-
- add_custom_command(
- OUTPUT "${name}/index.xml"
- COMMAND "${DOXYGEN_EXECUTABLE}" ${${name}_DOXYGEN_ARGS}
- "${CMAKE_CURRENT_BINARY_DIR}/${name}.doxy"
- COMMENT "Generating Doxygen."
- DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}.doxy" ${${name}_DEPENDENCIES}
- VERBATIM
- )
-endfunction()
diff --git a/cmake/templates/autodoc.doxy.in b/cmake/templates/autodoc.doxy.in
deleted file mode 100644
index 94113e0f146d..000000000000
--- a/cmake/templates/autodoc.doxy.in
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright (c) 2012 Bryce Adelstein-Lelbach
-#
-# SPDX-License-Identifier: BSL-1.0
-# 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)
-
-EXTRACT_ALL = YES
-EXPAND_ONLY_PREDEF = YES
-GENERATE_HTML = NO
-GENERATE_XML = YES
-MACRO_EXPANSION = YES
-PREDEFINED = @doxygen_definitions@
-XML_OUTPUT = @doxygen_output_file@
-OUTPUT_DIRECTORY = @doxygen_output_dir@
-GENERATE_LATEX = NO
-INPUT = @doxygen_inputs@
-EXCLUDE_SYMBOLS = detail
-EXTRACT_PRIVATE = NO
diff --git a/cmake/templates/conf.py.in b/cmake/templates/conf.py.in
index 65ab8d053d5c..4f004259e689 100644
--- a/cmake/templates/conf.py.in
+++ b/cmake/templates/conf.py.in
@@ -208,8 +208,13 @@ breathe_doxygen_config_options = {
'PREDEFINED': '@doxygen_definitions@',
'STRIP_FROM_PATH': hpx_source_dir,
'EXTRACT_PRIVATE': 'NO'
+ 'ALIASES': r'namedrequirement{1}="\1"'
}
+# ! this should work but doesn't. check after updating breathe version.
+# breathe_doxygen_aliases = {
+# }
+
numfig = True
primary_domain = 'cpp'
highlight_language = 'cpp'
@@ -496,6 +501,10 @@ rst_prolog += '''
.. _cpp20_p0075r1: http://wg21.link/p0075r1
.. |cpp20_p0443| replace:: P0443
.. _cpp20_p0443: https://github.com/executors/issaquah_2016
+.. |p0792| replace:: P0792
+.. _p0792: http://wg21.link/p0792
+.. |p0159| replace:: P0159
+.. _p0159: http://wg21.link/p0159
.. |p1393| replace:: P1393
.. _p1393: http://wg21.link/p1393
.. |p2220| replace:: P2220
diff --git a/cmake/templates/hpxcxx.in b/cmake/templates/hpxcxx.in
index 81f38f89367d..9a0196e0d4eb 100755
--- a/cmake/templates/hpxcxx.in
+++ b/cmake/templates/hpxcxx.in
@@ -126,12 +126,14 @@ if pkg in os.environ:
else:
os.environ[pkg] = pkgconf
+args += ["-Wl,--start-group"]
if application:
args += ["`pkg-config --cflags --libs hpx_application" + pkgconf_suffix + "`"]
elif component:
args += ["`pkg-config --cflags --libs hpx_component" + pkgconf_suffix + "`"]
else:
args += ["`pkg-config --cflags hpx_application" + pkgconf_suffix + "`"]
+args += ["-Wl,--end-group"]
if not component and not application and not minusc:
usage()
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index b2b06a9347a9..437aa6671b00 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -4,20 +4,7 @@
# 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)
-# Add all files here which should be passed to doxygen
-set(doxygen_dependencies
- "${PROJECT_SOURCE_DIR}/components/component_storage/include/hpx/components/component_storage/migrate_from_storage.hpp"
- "${PROJECT_SOURCE_DIR}/components/component_storage/include/hpx/components/component_storage/migrate_to_storage.hpp"
-)
-
-# Definitions for autodoc.doxy.in
-foreach(doxygen_input ${doxygen_dependencies})
- set(doxygen_inputs "${doxygen_inputs} ${doxygen_input}")
-endforeach()
-
-set(doxygen_output_file "${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc")
-set(doxygen_output_dir "${CMAKE_CURRENT_BINARY_DIR}/doxygen")
-
+# used while generating sphinx config file
set(doxygen_definition_list
"DOXYGEN:=1"
"BOOST_SYSTEM_NOEXCEPT="
@@ -36,12 +23,6 @@ foreach(doxygen_predef ${doxygen_definition_list})
set(doxygen_definitions "${doxygen_definitions} \"${doxygen_predef}\"")
endforeach()
-hpx_info("Creating Doxyfile: ${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc.doxy")
-configure_file(
- "${PROJECT_SOURCE_DIR}/cmake/templates/autodoc.doxy.in"
- "${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc.doxy" @ONLY
-)
-
# Generate rst files with CMake variables and toolchains
set(HPX_CMAKE_OPTIONS_RST "")
foreach(_cat ${HPX_OPTION_CATEGORIES})
@@ -215,8 +196,6 @@ create_symbolic_link(
"${PROJECT_SOURCE_DIR}/libs" "${CMAKE_CURRENT_BINARY_DIR}/libs"
)
-hpx_source_to_doxygen(hpx_autodoc DEPENDENCIES ${doxygen_dependencies})
-
add_custom_target(docs)
add_custom_target(docs-html)
add_custom_target(docs-singlehtml)
@@ -258,7 +237,6 @@ foreach(output_format ${HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS})
add_custom_command(
OUTPUT "${SPHINX_DOCS_OUTPUT_FILE}"
DEPENDS "${sphinx_source_files_build}"
- "${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc/index.xml"
COMMAND ${SPHINX_DOCS_BUILD_COMMAND}
)
diff --git a/docs/sphinx/api/public_api.rst b/docs/sphinx/api/public_api.rst
index 400d0c008ec7..e4cd170e5e07 100644
--- a/docs/sphinx/api/public_api.rst
+++ b/docs/sphinx/api/public_api.rst
@@ -459,7 +459,7 @@ Classes
Class C++ standard
============================================= =============================================================
:cpp:class:`hpx::function` :cppreference-generic:`utility/functional,function`
- :cpp:class:`hpx::function_ref`
+ :cpp:class:`hpx::function_ref` |p0792|_
:cpp:class:`hpx::move_only_function` :cppreference-generic:`utility/functional,move_only_function`
:cpp:struct:`hpx::traits::is_bind_expression` :cppreference-generic:`utility/functional,is_bind_expression`
:cpp:struct:`hpx::traits::is_placeholder` :cppreference-generic:`utility/functional,is_placeholder`
@@ -541,13 +541,13 @@ Functions
:cpp:func:`hpx::dataflow`
:cpp:func:`hpx::make_future`
:cpp:func:`hpx::make_shared_future`
- :cpp:func:`hpx::make_ready_future`
+ :cpp:func:`hpx::make_ready_future` |p0159|_
:cpp:func:`hpx::make_ready_future_alloc`
:cpp:func:`hpx::make_ready_future_at`
:cpp:func:`hpx::make_ready_future_after`
- :cpp:func:`hpx::make_exceptional_future`
- :cpp:func:`hpx::when_all`
- :cpp:func:`hpx::when_any`
+ :cpp:func:`hpx::make_exceptional_future` |p0159|_
+ :cpp:func:`hpx::when_all` |p0159|_
+ :cpp:func:`hpx::when_any` |p0159|_
:cpp:func:`hpx::when_some`
:cpp:func:`hpx::when_each`
:cpp:func:`hpx::wait_all`
diff --git a/docs/sphinx/manual/building_hpx.rst b/docs/sphinx/manual/building_hpx.rst
index 4df46bdae228..ccc33a9560be 100644
--- a/docs/sphinx/manual/building_hpx.rst
+++ b/docs/sphinx/manual/building_hpx.rst
@@ -253,14 +253,14 @@ To build |hpx| under Windows 10 x64 with Visual Studio 2015:
.. code-block:: bash
- bootstrap.bat
+ .\bootstrap.bat
This batch file will set up everything needed to create a successful build.
Now execute:
.. code-block:: bash
- b2.exe link=shared variant=release,debug architecture=x86 address-model=64 threading=multi --build-type=complete install
+ .\b2.exe link=shared variant=release,debug architecture=x86 address-model=64 threading=multi --build-type=complete install
This command will start a (very long) build of all available Boost libraries.
Please, be patient.
@@ -285,12 +285,14 @@ To build |hpx| under Windows 10 x64 with Visual Studio 2015:
will build |hpx| packages out of the |hpx| source tree.
* Set three new environment variables (in CMake, not in Windows environment):
- ``BOOST_ROOT``, ``HWLOC_ROOT``, ``CMAKE_INSTALL_PREFIX``. The meaning of
+ ``BOOST_ROOT``, ``HWLOC_ROOT``, ``ASIO_ROOT``, ``CMAKE_INSTALL_PREFIX``. The meaning of
these variables is as follows:
* ``BOOST_ROOT`` the |hpx| root directory of the unpacked Boost headers/cpp files.
* ``HWLOC_ROOT`` the |hpx| root directory of the unpacked Portable Hardware Locality
files.
+ * ``ASIO_ROOT`` the |hpx| root directory of the unpacked ASIO files. Alternatively use
+ ``HPX_WITH_FETCH_ASIO`` with value ``True``.
* ``CMAKE_INSTALL_PREFIX`` the |hpx| root directory where the future builds of |hpx|
should be installed.
diff --git a/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst b/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst
index 01de5595f226..1151c731fade 100644
--- a/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst
+++ b/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst
@@ -1461,6 +1461,13 @@ The predefined command line options for any application using
Sed-style search and replace (``s/search/replace/``) used to transform host
names to the proper network interconnect.
+.. option:: --hpx:force_ipv4
+
+ Network hostnames will be resolved to ipv4 adresses instead of using the
+ first resolved endpoint. This is especially useful on Windows where the
+ local hostname will resolve to an ipv6 adress while remote network hostnames
+ are commonly resolved to ipv4 adresses.
+
.. option:: --hpx:localities arg
The number of localities to wait for at application startup (default: ``1``).
diff --git a/libs/core/algorithms/CMakeLists.txt b/libs/core/algorithms/CMakeLists.txt
index 573e3d74035f..260dbd7f5505 100644
--- a/libs/core/algorithms/CMakeLists.txt
+++ b/libs/core/algorithms/CMakeLists.txt
@@ -35,6 +35,7 @@ set(algorithms_headers
hpx/parallel/algorithms/detail/parallel_stable_sort.hpp
hpx/parallel/algorithms/detail/pivot.hpp
hpx/parallel/algorithms/detail/reduce.hpp
+ hpx/parallel/algorithms/detail/replace.hpp
hpx/parallel/algorithms/detail/rotate.hpp
hpx/parallel/algorithms/detail/sample_sort.hpp
hpx/parallel/algorithms/detail/search.hpp
@@ -168,6 +169,7 @@ set(algorithms_headers
hpx/parallel/datapar/loop.hpp
hpx/parallel/datapar/mismatch.hpp
hpx/parallel/datapar/reduce.hpp
+ hpx/parallel/datapar/replace.hpp
hpx/parallel/datapar/transfer.hpp
hpx/parallel/datapar/transform_loop.hpp
hpx/parallel/datapar/zip_iterator.hpp
diff --git a/libs/core/algorithms/include/hpx/parallel/algorithms/detail/replace.hpp b/libs/core/algorithms/include/hpx/parallel/algorithms/detail/replace.hpp
new file mode 100644
index 000000000000..246bbb72f426
--- /dev/null
+++ b/libs/core/algorithms/include/hpx/parallel/algorithms/detail/replace.hpp
@@ -0,0 +1,265 @@
+// Copyright (c) 2022 Srinivas Yadav
+//
+// SPDX-License-Identifier: BSL-1.0
+// 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)
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+namespace hpx { namespace parallel { inline namespace v1 { namespace detail {
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct sequential_replace_t final
+ : hpx::functional::detail::tag_fallback>
+ {
+ private:
+ template
+ friend inline constexpr auto tag_fallback_invoke(sequential_replace_t,
+ ExPolicy&& policy, InIter first, InIter last, T1 const& old_value,
+ T2 const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ return util::loop(HPX_FORWARD(ExPolicy, policy), first, last,
+ [old_value, new_value, &proj](auto& v) {
+ if (HPX_INVOKE(proj, *v) == old_value)
+ {
+ *v = new_value;
+ }
+ });
+ }
+ else
+ {
+ typedef typename std::iterator_traits::value_type type;
+
+ return for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy), first,
+ std::distance(first, last),
+ [old_value, new_value, proj = HPX_FORWARD(Proj, proj)](
+ type& t) -> void {
+ if (HPX_INVOKE(proj, t) == old_value)
+ {
+ t = new_value;
+ }
+ },
+ util::projection_identity());
+ }
+ }
+ };
+
+#if !defined(HPX_COMPUTE_DEVICE_CODE)
+ template
+ inline constexpr sequential_replace_t sequential_replace =
+ sequential_replace_t{};
+#else
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace(Args&&... args)
+ {
+ return sequential_replace_t{}(std::forward(args)...);
+ }
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct sequential_replace_if_t final
+ : hpx::functional::detail::tag_fallback>
+ {
+ private:
+ template
+ friend inline constexpr auto tag_fallback_invoke(
+ sequential_replace_if_t, ExPolicy&& policy, InIter first, Sent last,
+ F&& f, T const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ return util::loop(HPX_FORWARD(ExPolicy, policy), first, last,
+ [&f, new_value, &proj](auto& v) {
+ if (HPX_INVOKE(f, HPX_INVOKE(proj, *v)))
+ {
+ *v = new_value;
+ }
+ });
+ }
+ else
+ {
+ typedef typename std::iterator_traits::value_type type;
+
+ return for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy), first,
+ detail::distance(first, last),
+ [new_value, f = HPX_FORWARD(F, f),
+ proj = HPX_FORWARD(Proj, proj)](
+ type& t) mutable -> void {
+ if (HPX_INVOKE(f, HPX_INVOKE(proj, t)))
+ {
+ t = new_value;
+ }
+ },
+ util::projection_identity());
+ }
+ }
+ };
+
+#if !defined(HPX_COMPUTE_DEVICE_CODE)
+ template
+ inline constexpr sequential_replace_if_t sequential_replace_if =
+ sequential_replace_if_t{};
+#else
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace_if(Args&&... args)
+ {
+ return sequential_replace_if_t{}(std::forward(args)...);
+ }
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct sequential_replace_copy_t final
+ : hpx::functional::detail::tag_fallback<
+ sequential_replace_copy_t>
+ {
+ private:
+ template
+ friend inline constexpr auto tag_fallback_invoke(
+ sequential_replace_copy_t, ExPolicy&& policy, InIter first,
+ Sent sent, OutIter dest, T const& old_value, T const& new_value,
+ Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ for (/* */; first != sent; ++first)
+ {
+ if (HPX_INVOKE(proj, *first) == old_value)
+ *dest++ = new_value;
+ else
+ *dest++ = *first;
+ }
+ return util::in_out_result(first, dest);
+ }
+ else
+ {
+ typedef hpx::util::zip_iterator zip_iterator;
+ typedef typename zip_iterator::reference reference;
+
+ return util::detail::get_in_out_result(
+ for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy),
+ hpx::util::make_zip_iterator(first, dest),
+ detail::distance(first, sent),
+ [old_value, new_value, proj = HPX_FORWARD(Proj, proj)](
+ reference t) -> void {
+ using hpx::get;
+ if (HPX_INVOKE(proj, get<0>(t)) == old_value)
+ get<1>(t) = new_value;
+ else
+ get<1>(t) = get<0>(t); //-V573
+ },
+ util::projection_identity()));
+ }
+ }
+ };
+
+#if !defined(HPX_COMPUTE_DEVICE_CODE)
+ template
+ inline constexpr sequential_replace_copy_t
+ sequential_replace_copy = sequential_replace_copy_t{};
+#else
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace_copy(Args&&... args)
+ {
+ return sequential_replace_copy_t{}(
+ std::forward(args)...);
+ }
+#endif
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct sequential_replace_copy_if_t final
+ : hpx::functional::detail::tag_fallback<
+ sequential_replace_copy_if_t>
+ {
+ private:
+ template
+ friend inline constexpr auto tag_fallback_invoke(
+ sequential_replace_copy_if_t, ExPolicy&& policy, InIter first,
+ Sent sent, OutIter dest, F&& f, T const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ for (/* */; first != sent; ++first)
+ {
+ if (HPX_INVOKE(f, HPX_INVOKE(proj, *first)))
+ {
+ *dest++ = new_value;
+ }
+ else
+ {
+ *dest++ = *first;
+ }
+ }
+ return util::in_out_result{first, dest};
+ }
+ else
+ {
+ typedef hpx::util::zip_iterator zip_iterator;
+ typedef typename zip_iterator::reference reference;
+
+ return util::detail::get_in_out_result(
+ for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy),
+ hpx::util::make_zip_iterator(first, dest),
+ detail::distance(first, sent),
+ [new_value, f = HPX_FORWARD(F, f),
+ proj = HPX_FORWARD(Proj, proj)](
+ reference t) mutable -> void {
+ using hpx::get;
+ if (HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(t))))
+ {
+ get<1>(t) = new_value;
+ }
+ else
+ {
+ get<1>(t) = get<0>(t); //-V573
+ }
+ },
+ util::projection_identity()));
+ }
+ }
+ };
+
+#if !defined(HPX_COMPUTE_DEVICE_CODE)
+ template
+ inline constexpr sequential_replace_copy_if_t
+ sequential_replace_copy_if = sequential_replace_copy_if_t{};
+#else
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto sequential_replace_copy_if(
+ Args&&... args)
+ {
+ return sequential_replace_copy_if_t{}(
+ std::forward(args)...);
+ }
+#endif
+
+}}}} // namespace hpx::parallel::v1::detail
diff --git a/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp b/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp
index 47d78e8a8444..04197914a9f5 100644
--- a/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp
+++ b/libs/core/algorithms/include/hpx/parallel/algorithms/replace.hpp
@@ -481,6 +481,7 @@ namespace hpx {
#include
#include
#include
+#include
#include
#include
#include
@@ -497,21 +498,6 @@ namespace hpx { namespace parallel { inline namespace v1 {
namespace detail {
/// \cond NOINTERNAL
- // sequential replace
- template
- inline InIter sequential_replace(InIter first, InIter last,
- T1 const& old_value, T2 const& new_value, Proj&& proj)
- {
- for (/* */; first != last; ++first)
- {
- if (HPX_INVOKE(proj, *first) == old_value)
- {
- *first = new_value;
- }
- }
- return first;
- }
-
template
struct replace : public detail::algorithm, Iter>
{
@@ -522,11 +508,13 @@ namespace hpx { namespace parallel { inline namespace v1 {
template
- static InIter sequential(ExPolicy, InIter first, InIter last,
- T1 const& old_value, T2 const& new_value, Proj&& proj)
+ static InIter sequential(ExPolicy&& policy, InIter first,
+ InIter last, T1 const& old_value, T2 const& new_value,
+ Proj&& proj)
{
- return sequential_replace(
- first, last, old_value, new_value, HPX_FORWARD(Proj, proj));
+ return sequential_replace(
+ HPX_FORWARD(ExPolicy, policy), first, last, old_value,
+ new_value, HPX_FORWARD(Proj, proj));
}
template ::value_type type;
-
- return for_each_n().call(
- HPX_FORWARD(ExPolicy, policy), first,
- std::distance(first, last),
- [old_value, new_value, proj = HPX_FORWARD(Proj, proj)](
- type& t) -> void {
- if (HPX_INVOKE(proj, t) == old_value)
- {
- t = new_value;
- }
- },
- util::projection_identity());
+ return sequential_replace(
+ HPX_FORWARD(ExPolicy, policy), first, last, old_value,
+ new_value, HPX_FORWARD(Proj, proj));
}
};
/// \endcond
@@ -585,22 +563,6 @@ namespace hpx { namespace parallel { inline namespace v1 {
namespace detail {
/// \cond NOINTERNAL
- // sequential replace_if
- template
- inline InIter sequential_replace_if(
- InIter first, Sent sent, F&& f, T const& new_value, Proj&& proj)
- {
- for (/* */; first != sent; ++first)
- {
- if (HPX_INVOKE(f, HPX_INVOKE(proj, *first)))
- {
- *first = new_value;
- }
- }
- return first;
- }
-
template
struct replace_if : public detail::algorithm, Iter>
{
@@ -611,11 +573,12 @@ namespace hpx { namespace parallel { inline namespace v1 {
template
- static InIter sequential(ExPolicy, InIter first, Sent last, F&& f,
- T const& new_value, Proj&& proj)
+ static InIter sequential(ExPolicy&& policy, InIter first, Sent last,
+ F&& f, T const& new_value, Proj&& proj)
{
- return sequential_replace_if(first, last, HPX_FORWARD(F, f),
- new_value, HPX_FORWARD(Proj, proj));
+ return sequential_replace_if(
+ HPX_FORWARD(ExPolicy, policy), first, last,
+ HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj));
}
template ::value_type type;
-
- return for_each_n().call(
- HPX_FORWARD(ExPolicy, policy), first,
- detail::distance(first, last),
- [new_value, f = HPX_FORWARD(F, f),
- proj = HPX_FORWARD(Proj, proj)](
- type& t) mutable -> void {
- if (HPX_INVOKE(f, HPX_INVOKE(proj, t)))
- {
- t = new_value;
- }
- },
- util::projection_identity());
+ return sequential_replace_if(
+ HPX_FORWARD(ExPolicy, policy), first, last,
+ HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj));
}
};
/// \endcond
@@ -673,23 +625,6 @@ namespace hpx { namespace parallel { inline namespace v1 {
namespace detail {
/// \cond NOINTERNAL
- // sequential replace_copy
- template
- inline util::in_out_result sequential_replace_copy(
- InIter first, Sent sent, OutIter dest, T const& old_value,
- T const& new_value, Proj&& proj)
- {
- for (/* */; first != sent; ++first)
- {
- if (HPX_INVOKE(proj, *first) == old_value)
- *dest++ = new_value;
- else
- *dest++ = *first;
- }
- return util::in_out_result(first, dest);
- }
-
template
struct replace_copy
: public detail::algorithm, IterPair>
@@ -701,11 +636,12 @@ namespace hpx { namespace parallel { inline namespace v1 {
template
- static util::in_out_result sequential(ExPolicy,
- InIter first, Sent sent, OutIter dest, T const& old_value,
- T const& new_value, Proj&& proj)
+ static util::in_out_result sequential(
+ ExPolicy&& policy, InIter first, Sent sent, OutIter dest,
+ T const& old_value, T const& new_value, Proj&& proj)
{
- return sequential_replace_copy(first, sent, dest, old_value,
+ return sequential_replace_copy(
+ HPX_FORWARD(ExPolicy, policy), first, sent, dest, old_value,
new_value, HPX_FORWARD(Proj, proj));
}
@@ -717,24 +653,9 @@ namespace hpx { namespace parallel { inline namespace v1 {
FwdIter2 dest, T const& old_value, T const& new_value,
Proj&& proj)
{
- typedef hpx::util::zip_iterator
- zip_iterator;
- typedef typename zip_iterator::reference reference;
-
- return util::detail::get_in_out_result(
- for_each_n().call(
- HPX_FORWARD(ExPolicy, policy),
- hpx::util::make_zip_iterator(first, dest),
- detail::distance(first, sent),
- [old_value, new_value, proj = HPX_FORWARD(Proj, proj)](
- reference t) -> void {
- using hpx::get;
- if (HPX_INVOKE(proj, get<0>(t)) == old_value)
- get<1>(t) = new_value;
- else
- get<1>(t) = get<0>(t); //-V573
- },
- util::projection_identity()));
+ return sequential_replace_copy(
+ HPX_FORWARD(ExPolicy, policy), first, sent, dest, old_value,
+ new_value, HPX_FORWARD(Proj, proj));
}
};
/// \endcond
@@ -777,27 +698,6 @@ namespace hpx { namespace parallel { inline namespace v1 {
namespace detail {
/// \cond NOINTERNAL
- // sequential replace_copy_if
- template
- inline util::in_out_result sequential_replace_copy_if(
- InIter first, Sent sent, OutIter dest, F&& f, T const& new_value,
- Proj&& proj)
- {
- for (/* */; first != sent; ++first)
- {
- if (HPX_INVOKE(f, HPX_INVOKE(proj, *first)))
- {
- *dest++ = new_value;
- }
- else
- {
- *dest++ = *first;
- }
- }
- return util::in_out_result{first, dest};
- }
-
template
struct replace_copy_if
: public detail::algorithm, IterPair>
@@ -809,11 +709,12 @@ namespace hpx { namespace parallel { inline namespace v1 {
template
- static util::in_out_result sequential(ExPolicy,
- InIter first, Sent sent, OutIter dest, F&& f,
+ static util::in_out_result sequential(
+ ExPolicy&& policy, InIter first, Sent sent, OutIter dest, F&& f,
T const& new_value, Proj&& proj)
{
- return sequential_replace_copy_if(first, sent, dest,
+ return sequential_replace_copy_if(
+ HPX_FORWARD(ExPolicy, policy), first, sent, dest,
HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj));
}
@@ -824,29 +725,9 @@ namespace hpx { namespace parallel { inline namespace v1 {
parallel(ExPolicy&& policy, FwdIter1 first, Sent sent,
FwdIter2 dest, F&& f, T const& new_value, Proj&& proj)
{
- typedef hpx::util::zip_iterator
- zip_iterator;
- typedef typename zip_iterator::reference reference;
-
- return util::detail::get_in_out_result(
- for_each_n().call(
- HPX_FORWARD(ExPolicy, policy),
- hpx::util::make_zip_iterator(first, dest),
- detail::distance(first, sent),
- [new_value, f = HPX_FORWARD(F, f),
- proj = HPX_FORWARD(Proj, proj)](
- reference t) mutable -> void {
- using hpx::get;
- if (HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(t))))
- {
- get<1>(t) = new_value;
- }
- else
- {
- get<1>(t) = get<0>(t); //-V573
- }
- },
- util::projection_identity()));
+ return sequential_replace_copy_if(
+ HPX_FORWARD(ExPolicy, policy), first, sent, dest,
+ HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj));
}
};
/// \endcond
@@ -984,11 +865,9 @@ namespace hpx {
static_assert((hpx::traits::is_forward_iterator::value),
"Required at least forward iterator.");
- typedef typename std::iterator_traits::value_type Type;
-
return hpx::replace_if(
HPX_FORWARD(ExPolicy, policy), first, last,
- [old_value](Type const& a) -> bool { return old_value == a; },
+ [old_value](auto const& a) { return old_value == a; },
new_value);
}
} replace{};
@@ -1114,11 +993,9 @@ namespace hpx {
static_assert((hpx::traits::is_forward_iterator::value),
"Required at least forward iterator.");
- typedef typename std::iterator_traits::value_type Type;
-
return hpx::replace_copy_if(
HPX_FORWARD(ExPolicy, policy), first, last, dest,
- [old_value](Type const& a) -> bool { return old_value == a; },
+ [old_value](auto const& a) { return old_value == a; },
new_value);
}
} replace_copy{};
diff --git a/libs/core/algorithms/include/hpx/parallel/datapar.hpp b/libs/core/algorithms/include/hpx/parallel/datapar.hpp
index 1d2b67c916bd..f4973727628b 100644
--- a/libs/core/algorithms/include/hpx/parallel/datapar.hpp
+++ b/libs/core/algorithms/include/hpx/parallel/datapar.hpp
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libs/core/algorithms/include/hpx/parallel/datapar/replace.hpp b/libs/core/algorithms/include/hpx/parallel/datapar/replace.hpp
new file mode 100644
index 000000000000..888fa1e5f4f3
--- /dev/null
+++ b/libs/core/algorithms/include/hpx/parallel/datapar/replace.hpp
@@ -0,0 +1,306 @@
+// Copyright (c) 2022 Srinivas Yadav
+//
+// SPDX-License-Identifier: BSL-1.0
+// 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)
+
+#pragma once
+
+#include
+
+#if defined(HPX_HAVE_DATAPAR)
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace hpx { namespace parallel { inline namespace v1 { namespace detail {
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct datapar_replace
+ {
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy,
+ InIter first, InIter last, T1 const& old_value, T2 const& new_value,
+ Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ return util::loop_ind(HPX_FORWARD(ExPolicy, policy), first,
+ last, [old_value, new_value, &proj](auto& v) {
+ using var_type = std::decay_t;
+ traits::mask_assign(
+ HPX_INVOKE(proj, v) == var_type(old_value), v,
+ var_type(new_value));
+ });
+ }
+ else
+ {
+ return for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy), first,
+ std::distance(first, last),
+ [old_value, new_value, proj = HPX_FORWARD(Proj, proj)](
+ auto& v) -> void {
+ traits::mask_assign(
+ HPX_INVOKE(proj, v) == var_type(old_value), v,
+ var_type(new_value));
+ },
+ util::projection_identity());
+ }
+ }
+ };
+
+ template ::value)>
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke(
+ sequential_replace_t, ExPolicy&& policy, InIter first,
+ InIter last, T1 const& old_value, T2 const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible<
+ InIter>::value)
+ {
+ return datapar_replace::call(
+ HPX_FORWARD(ExPolicy, policy), first, last, old_value,
+ new_value, HPX_FORWARD(Proj, proj));
+ }
+ else
+ {
+ using base_policy_type =
+ decltype((hpx::execution::experimental::to_non_simd(
+ std::declval())));
+ return sequential_replace(
+ hpx::execution::experimental::to_non_simd(policy), first, last,
+ old_value, new_value, HPX_FORWARD(Proj, proj));
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct datapar_replace_if
+ {
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy,
+ InIter first, Sent last, F&& f, T const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ return util::loop_ind(HPX_FORWARD(ExPolicy, policy), first,
+ last, [&f, new_value, &proj](auto& v) {
+ using var_type = std::decay_t;
+ traits::mask_assign(HPX_INVOKE(f, HPX_INVOKE(proj, v)),
+ v, var_type(new_value));
+ });
+ }
+ else
+ {
+ return for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy), first,
+ detail::distance(first, last),
+ [new_value, f = HPX_FORWARD(F, f),
+ proj = HPX_FORWARD(Proj, proj)](
+ auto& v) mutable -> void {
+ using var_type = std::decay_t;
+ traits::mask_assign(
+ HPX_INVOKE(f, (HPX_INVOKE(proj, v))), v,
+ var_type(new_value));
+ },
+ util::projection_identity());
+ }
+ }
+ };
+
+ template ::value)>
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke(
+ sequential_replace_if_t, ExPolicy&& policy, InIter first,
+ Sent last, F&& f, T const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible<
+ InIter>::value)
+ {
+ return datapar_replace_if::call(
+ HPX_FORWARD(ExPolicy, policy), first, last, HPX_FORWARD(F, f),
+ new_value, HPX_FORWARD(Proj, proj));
+ }
+ else
+ {
+ using base_policy_type =
+ decltype((hpx::execution::experimental::to_non_simd(
+ std::declval())));
+ return sequential_replace_if(
+ hpx::execution::experimental::to_non_simd(policy), first, last,
+ HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj));
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct datapar_replace_copy
+ {
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy,
+ InIter first, Sent sent, OutIter dest, T const& old_value,
+ T const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ std::size_t n = detail::distance(first, sent);
+
+ util::loop_n_ind(
+ hpx::util::make_zip_iterator(first, dest), sent,
+ [old_value, new_value, proj = HPX_FORWARD(Proj, proj)](
+ auto& v) {
+ using var_type = std::decay_t(v))>;
+ get<1>(v) = traits::choose(
+ HPX_INVOKE(proj, get<0>(v)) == var_type(old_value),
+ var_type(new_value), get<0>(v));
+ });
+
+ return util::in_out_result(
+ first + n, dest + n);
+ }
+ else
+ {
+ typedef hpx::util::zip_iterator zip_iterator;
+
+ return util::detail::get_in_out_result(
+ for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy),
+ hpx::util::make_zip_iterator(first, dest),
+ detail::distance(first, sent),
+ [old_value, new_value, proj = HPX_FORWARD(Proj, proj)](
+ auto& v) -> void {
+ using hpx::get;
+ using var_type = std::decay_t(v))>;
+ get<1>(v) =
+ traits::choose(HPX_INVOKE(proj, get<0>(v)) ==
+ var_type(old_value),
+ var_type(new_value), get<0>(v));
+ },
+ util::projection_identity()));
+ }
+ }
+ };
+
+ template ::value)>
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke(
+ sequential_replace_copy_t, ExPolicy&& policy, InIter first,
+ Sent sent, OutIter dest, T const& old_value, T const& new_value,
+ Proj&& proj)
+ {
+ if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible<
+ InIter>::value)
+ {
+ return datapar_replace_copy::call(
+ (HPX_FORWARD(ExPolicy, policy), first, sent, dest, old_value,
+ new_value, HPX_FORWARD(Proj, proj)));
+ }
+ else
+ {
+ using base_policy_type =
+ decltype((hpx::execution::experimental::to_non_simd(
+ std::declval())));
+ return sequential_replace_copy(
+ hpx::execution::experimental::to_non_simd(policy), first, sent,
+ dest, old_value, new_value, HPX_FORWARD(Proj, proj));
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ template
+ struct datapar_replace_copy_if
+ {
+ template
+ HPX_HOST_DEVICE HPX_FORCEINLINE static auto call(ExPolicy&& policy,
+ InIter first, Sent last, OutIter dest, F&& f, T const& new_value,
+ Proj&& proj)
+ {
+ if constexpr (hpx::is_sequenced_execution_policy_v)
+ {
+ std::size_t n = detail::distance(first, last);
+
+ util::loop_n_ind(
+ hpx::util::make_zip_iterator(first, dest), n,
+ [new_value, f = HPX_FORWARD(F, f),
+ proj = HPX_FORWARD(Proj, proj)](
+ auto& v) mutable -> void {
+ using hpx::get;
+ using var_type = std::decay_t(v))>;
+ get<1>(v) = traits::choose(
+ HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(v))),
+ var_type(new_value), get<0>(v));
+ });
+ return util::in_out_result(
+ first + n, dest + n);
+ }
+ else
+ {
+ typedef hpx::util::zip_iterator zip_iterator;
+
+ return util::detail::get_in_out_result(
+ for_each_n().call(
+ HPX_FORWARD(ExPolicy, policy),
+ hpx::util::make_zip_iterator(first, dest),
+ detail::distance(first, last),
+ [new_value, f = HPX_FORWARD(F, f),
+ proj = HPX_FORWARD(Proj, proj)](
+ auto& v) mutable -> void {
+ using hpx::get;
+ using var_type = std::decay_t(v))>;
+ get<1>(v) = traits::choose(
+ HPX_INVOKE(f, HPX_INVOKE(proj, get<0>(v))),
+ var_type(new_value), get<0>(v));
+ },
+ util::projection_identity()));
+ }
+ }
+ };
+
+ template ::value)>
+ HPX_HOST_DEVICE HPX_FORCEINLINE auto tag_invoke(
+ sequential_replace_copy_if_t, ExPolicy&& policy, InIter first,
+ Sent last, OutIter dest, F&& f, T const& new_value, Proj&& proj)
+ {
+ if constexpr (hpx::parallel::util::detail::iterator_datapar_compatible<
+ InIter>::value)
+ {
+ return datapar_replace_copy_if::call(
+ HPX_FORWARD(ExPolicy, policy), first, last, dest,
+ HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj));
+ }
+ else
+ {
+ using base_policy_type =
+ decltype((hpx::execution::experimental::to_non_simd(
+ std::declval())));
+ return sequential_replace_copy_if(
+ hpx::execution::experimental::to_non_simd(policy), first, last,
+ dest, HPX_FORWARD(F, f), new_value, HPX_FORWARD(Proj, proj));
+ }
+ }
+}}}} // namespace hpx::parallel::v1::detail
+#endif
diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt b/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt
index 9cc59a8fa4bb..cd15949a449c 100644
--- a/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt
+++ b/libs/core/algorithms/tests/unit/datapar_algorithms/CMakeLists.txt
@@ -35,6 +35,10 @@ if(HPX_WITH_DATAPAR)
mismatch_datapar
none_of_datapar
reduce_datapar
+ replace_copy_if_datapar
+ replace_copy_datapar
+ replace_datapar
+ replace_if_datapar
transform_binary_datapar
transform_binary2_datapar
transform_datapar
diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_datapar.cpp b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_datapar.cpp
new file mode 100644
index 000000000000..03fdd259cc6f
--- /dev/null
+++ b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_datapar.cpp
@@ -0,0 +1,138 @@
+// Copyright (c) 2022 Srinivas Yadav
+//
+// SPDX-License-Identifier: BSL-1.0
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../algorithms/test_utils.hpp"
+
+////////////////////////////////////////////////////////////////////////////
+template
+void test_replace_copy(ExPolicy policy, IteratorTag)
+{
+ static_assert(hpx::is_execution_policy::value,
+ "hpx::is_execution_policy::value");
+
+ typedef std::vector::iterator base_iterator;
+ typedef test::test_iterator iterator;
+
+ std::vector c(10007);
+ std::vector d1(c.size());
+ std::vector d2(c.size()); //-V656
+
+ std::iota(std::begin(c), std::end(c), std::rand());
+
+ std::size_t idx = std::rand() % c.size(); //-V104
+
+ hpx::replace_copy(policy, iterator(std::begin(c)), iterator(std::end(c)),
+ std::begin(d1), c[idx], c[idx] + 1);
+
+ std::replace_copy(
+ std::begin(c), std::end(c), std::begin(d2), c[idx], c[idx] + 1);
+
+ std::size_t count = 0;
+ HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::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;
+
+ std::vector c(10007);
+ std::vector d1(c.size());
+ std::vector d2(c.size()); //-V656
+
+ std::iota(std::begin(c), std::end(c), std::rand());
+
+ std::size_t idx = std::rand() % c.size(); //-V104
+
+ auto f = hpx::replace_copy(p, iterator(std::begin(c)),
+ iterator(std::end(c)), std::begin(d1), c[idx], c[idx] + 1);
+ f.wait();
+
+ std::replace_copy(
+ std::begin(c), std::end(c), std::begin(d2), c[idx], c[idx] + 1);
+
+ std::size_t count = 0;
+ HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::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::execution;
+ test_replace_copy(simd, IteratorTag());
+ test_replace_copy(par_simd, IteratorTag());
+
+ test_replace_copy_async(simd(task), IteratorTag());
+ test_replace_copy_async(par_simd(task), IteratorTag());
+}
+
+void replace_copy_test()
+{
+ test_replace_copy();
+ test_replace_copy();
+}
+
+int hpx_main(hpx::program_options::variables_map& vm)
+{
+ unsigned int seed = (unsigned int) std::time(nullptr);
+ if (vm.count("seed"))
+ seed = vm["seed"].as();
+
+ std::cout << "using seed: " << seed << std::endl;
+ std::srand(seed);
+
+ replace_copy_test();
+ return hpx::local::finalize();
+}
+
+int main(int argc, char* argv[])
+{
+ // add command line option which controls the random number generator seed
+ using namespace hpx::program_options;
+ options_description desc_commandline(
+ "Usage: " HPX_APPLICATION_STRING " [options]");
+
+ desc_commandline.add_options()("seed,s", value(),
+ "the random number generator seed to use for this run");
+
+ // By default this test should run on all available cores
+ std::vector const cfg = {"hpx.os_threads=all"};
+
+ // Initialize and run HPX
+ hpx::local::init_params init_args;
+ init_args.desc_cmdline = desc_commandline;
+ init_args.cfg = cfg;
+
+ HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv, init_args), 0,
+ "HPX main exited with non-zero status");
+
+ return hpx::util::report_errors();
+}
diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_if_datapar.cpp b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_if_datapar.cpp
new file mode 100644
index 000000000000..5410e0c8b011
--- /dev/null
+++ b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_copy_if_datapar.cpp
@@ -0,0 +1,153 @@
+// Copyright (c) 2022 Srinivas Yadav
+//
+// SPDX-License-Identifier: BSL-1.0
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../algorithms/test_utils.hpp"
+
+////////////////////////////////////////////////////////////////////////////
+struct equal_f
+{
+ equal_f(int val)
+ : val_(val)
+ {
+ }
+
+ template
+ auto operator()(T lhs) const
+ {
+ return lhs == val_;
+ }
+
+ int val_;
+};
+
+template
+void test_replace_copy_if(ExPolicy policy, IteratorTag)
+{
+ static_assert(hpx::is_execution_policy::value,
+ "hpx::is_execution_policy::value");
+
+ typedef std::vector::iterator base_iterator;
+ typedef test::test_iterator iterator;
+
+ std::vector c(10007);
+ std::vector d1(c.size());
+ std::vector d2(c.size()); //-V656
+
+ std::iota(std::begin(c), std::end(c), std::rand());
+
+ std::size_t idx = std::rand() % c.size(); //-V104
+
+ hpx::replace_copy_if(policy, iterator(std::begin(c)), iterator(std::end(c)),
+ std::begin(d1), equal_f(c[idx]), c[idx] + 1);
+
+ std::replace_copy_if(std::begin(c), std::end(c), std::begin(d2),
+ equal_f(c[idx]), c[idx] + 1);
+
+ std::size_t count = 0;
+ HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::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;
+
+ std::vector c(10007);
+ std::vector d1(c.size());
+ std::vector d2(c.size()); //-V656
+
+ std::iota(std::begin(c), std::end(c), std::rand());
+
+ std::size_t idx = std::rand() % c.size(); //-V104
+
+ auto f = hpx::replace_copy_if(p, iterator(std::begin(c)),
+ iterator(std::end(c)), std::begin(d1), equal_f(c[idx]), c[idx] + 1);
+ f.wait();
+
+ std::replace_copy_if(std::begin(c), std::end(c), std::begin(d2),
+ equal_f(c[idx]), c[idx] + 1);
+
+ std::size_t count = 0;
+ HPX_TEST(std::equal(std::begin(d1), std::end(d1), std::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::execution;
+ test_replace_copy_if(simd, IteratorTag());
+ test_replace_copy_if(par_simd, IteratorTag());
+
+ test_replace_copy_if_async(simd(task), IteratorTag());
+ test_replace_copy_if_async(par_simd(task), IteratorTag());
+}
+
+void replace_copy_if_test()
+{
+ test_replace_copy_if();
+ test_replace_copy_if();
+}
+
+int hpx_main(hpx::program_options::variables_map& vm)
+{
+ unsigned int seed = (unsigned int) std::time(nullptr);
+ if (vm.count("seed"))
+ seed = vm["seed"].as();
+
+ std::cout << "using seed: " << seed << std::endl;
+ std::srand(seed);
+
+ replace_copy_if_test();
+ return hpx::local::finalize();
+}
+
+int main(int argc, char* argv[])
+{
+ // add command line option which controls the random number generator seed
+ using namespace hpx::program_options;
+ options_description desc_commandline(
+ "Usage: " HPX_APPLICATION_STRING " [options]");
+
+ desc_commandline.add_options()("seed,s", value(),
+ "the random number generator seed to use for this run");
+ // By default this test should run on all available cores
+ std::vector const cfg = {"hpx.os_threads=all"};
+
+ // Initialize and run HPX
+ hpx::local::init_params init_args;
+ init_args.desc_cmdline = desc_commandline;
+ init_args.cfg = cfg;
+
+ HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv, init_args), 0,
+ "HPX main exited with non-zero status");
+
+ return hpx::util::report_errors();
+}
diff --git a/libs/core/algorithms/tests/unit/datapar_algorithms/replace_datapar.cpp b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_datapar.cpp
new file mode 100644
index 000000000000..4c462be731d2
--- /dev/null
+++ b/libs/core/algorithms/tests/unit/datapar_algorithms/replace_datapar.cpp
@@ -0,0 +1,134 @@
+// Copyright (c) 2022 Srinivas Yadav
+//
+// SPDX-License-Identifier: BSL-1.0
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include