diff --git a/docs/sphinx/api/public_api.rst b/docs/sphinx/api/public_api.rst index 75b6fecbd002..1006fdf28542 100644 --- a/docs/sphinx/api/public_api.rst +++ b/docs/sphinx/api/public_api.rst @@ -567,8 +567,8 @@ Functions - :cpp:func:`hpx::parallel::v1::uninitialized_copy` - :cpp:func:`hpx::parallel::v1::uninitialized_copy_n` -- :cpp:func:`hpx::parallel::v1::uninitialized_default_construct` -- :cpp:func:`hpx::parallel::v1::uninitialized_default_construct_n` +- :cpp:func:`hpx::uninitialized_default_construct` +- :cpp:func:`hpx::uninitialized_default_construct_n` - :cpp:func:`hpx::parallel::v1::uninitialized_fill` - :cpp:func:`hpx::parallel::v1::uninitialized_fill_n` - :cpp:func:`hpx::uninitialized_move` @@ -576,6 +576,8 @@ Functions - :cpp:func:`hpx::parallel::v1::uninitialized_value_construct` - :cpp:func:`hpx::parallel::v1::uninitialized_value_construct_n` +- :cpp:func:`hpx::ranges::uninitialized_default_construct` +- :cpp:func:`hpx::ranges::uninitialized_default_construct_n` - :cpp:func:`hpx::ranges::uninitialized_move` - :cpp:func:`hpx::ranges::uninitialized_move_n` diff --git a/docs/sphinx/manual/writing_single_node_hpx_applications.rst b/docs/sphinx/manual/writing_single_node_hpx_applications.rst index 17d696916004..66064220a525 100644 --- a/docs/sphinx/manual/writing_single_node_hpx_applications.rst +++ b/docs/sphinx/manual/writing_single_node_hpx_applications.rst @@ -724,11 +724,11 @@ Parallel algorithms * Copies a number of objects to an uninitialized area of memory. * ```` * :cppreference-memory:`uninitialized_copy_n` - * * :cpp:func:`hpx::parallel::v1::uninitialized_default_construct` + * * :cpp:func:`hpx::uninitialized_default_construct` * Copies a range of objects to an uninitialized area of memory. * ```` * :cppreference-memory:`uninitialized_default_construct` - * * :cpp:func:`hpx::parallel::v1::uninitialized_default_construct_n` + * * :cpp:func:`hpx::uninitialized_default_construct_n` * Copies a number of objects to an uninitialized area of memory. * ```` * :cppreference-memory:`uninitialized_default_construct_n` diff --git a/libs/full/include_local/include/hpx/local/memory.hpp b/libs/full/include_local/include/hpx/local/memory.hpp index 582f73d749a0..0d1cbec9d942 100644 --- a/libs/full/include_local/include/hpx/local/memory.hpp +++ b/libs/full/include_local/include/hpx/local/memory.hpp @@ -12,8 +12,6 @@ namespace hpx { using hpx::parallel::uninitialized_copy; using hpx::parallel::uninitialized_copy_n; - using hpx::parallel::uninitialized_default_construct; - using hpx::parallel::uninitialized_default_construct_n; using hpx::parallel::uninitialized_fill; using hpx::parallel::uninitialized_fill_n; using hpx::parallel::uninitialized_value_construct; diff --git a/libs/parallelism/algorithms/CMakeLists.txt b/libs/parallelism/algorithms/CMakeLists.txt index 8cb2dc63226c..91039de9bdc3 100644 --- a/libs/parallelism/algorithms/CMakeLists.txt +++ b/libs/parallelism/algorithms/CMakeLists.txt @@ -121,6 +121,7 @@ set(algorithms_headers hpx/parallel/container_algorithms/stable_sort.hpp hpx/parallel/container_algorithms/transform.hpp hpx/parallel/container_algorithms/transform_reduce.hpp + hpx/parallel/container_algorithms/uninitialized_default_construct.hpp hpx/parallel/container_algorithms/uninitialized_move.hpp hpx/parallel/container_algorithms/unique.hpp hpx/parallel/container_memory.hpp diff --git a/libs/parallelism/algorithms/include/hpx/parallel/algorithms/uninitialized_default_construct.hpp b/libs/parallelism/algorithms/include/hpx/parallel/algorithms/uninitialized_default_construct.hpp index 5a506cae3fd2..9672105bc506 100644 --- a/libs/parallelism/algorithms/include/hpx/parallel/algorithms/uninitialized_default_construct.hpp +++ b/libs/parallelism/algorithms/include/hpx/parallel/algorithms/uninitialized_default_construct.hpp @@ -8,6 +8,164 @@ #pragma once +#if defined(DOXYGEN) +namespace hpx { + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// by default-initialization. If an exception is thrown during the + /// initialization, the function has no effects. + /// + /// \note Complexity: Performs exactly \a last - \a first assignments. + /// + /// \tparam FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// + /// \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. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked without an execution policy object will execute in + /// sequential order in the calling thread. + /// + /// \returns The \a uninitialized_default_construct algorithm + /// returns nothing + /// + template + void uninitialized_default_construct(FwdIter first, FwdIter last); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// by default-initialization. If an exception is thrown during the + /// initialization, the function has no effects. + /// + /// \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 FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// + /// \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. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked with an execution policy object of type \a + /// sequenced_policy execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked with an execution policy object of type \a + /// parallel_policy or \a parallel_task_policy are permitted to execute + /// in an unordered fashion in unspecified threads, and indeterminately + /// sequenced within each thread. + /// + /// \returns The \a uninitialized_default_construct algorithm returns a + /// \a hpx::future, if the execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and returns nothing + /// otherwise. + /// + template + typename parallel::util::detail::algorithm_result::type + uninitialized_default_construct( + ExPolicy&& policy, FwdIter first, FwdIter last); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// [first, first + count) by default-initialization. If an exception + /// is thrown during the initialization, the function has no effects. + /// + /// \note Complexity: Performs exactly \a count assignments, if + /// count > 0, no assignments otherwise. + /// + /// \tparam FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Size The type of the argument specifying the number of + /// elements to apply \a f to. + /// + /// \param first Refers to the beginning of the sequence of elements + /// the algorithm will be applied to. + /// \param count Refers to the number of elements starting at + /// \a first the algorithm will be applied to. + /// + /// The assignments in the parallel \a uninitialized_default_construct_n + /// algorithm invoked without an execution policy object execute in + /// sequential order in the calling thread. + /// + /// \returns The \a uninitialized_default_construct_n algorithm returns a + /// returns \a FwdIter. + /// The \a uninitialized_default_construct_n algorithm returns + /// the iterator to the element in the source range, one past + /// the last element constructed. + /// + template + FwdIter uninitialized_default_construct_n(FwdIter first, Size count); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// [first, first + count) by default-initialization. If an exception + /// is thrown during the initialization, the function has no effects. + /// + /// \note Complexity: Performs exactly \a count assignments, if + /// count > 0, no assignments otherwise. + /// + /// \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 FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Size The type of the argument specifying the number of + /// elements to apply \a f to. + /// + /// \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 count Refers to the number of elements starting at + /// \a first the algorithm will be applied to. + /// + /// The assignments in the parallel \a uninitialized_default_construct_n + /// algorithm invoked with an execution policy object of type + /// \a sequenced_policy execute in sequential order in the + /// calling thread. + /// + /// The assignments in the parallel \a uninitialized_default_construct_n + /// algorithm invoked with an execution policy object of type + /// \a parallel_policy or + /// \a parallel_task_policy are permitted to execute in an + /// unordered fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a uninitialized_default_construct_n algorithm returns a + /// \a hpx::future if the execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a FwdIter otherwise. + /// The \a uninitialized_default_construct_n algorithm returns + /// the iterator to the element in the source range, one past + /// the last element constructed. + /// + template + typename parallel::util::detail::algorithm_result::type + uninitialized_default_construct_n( + ExPolicy&& policy, FwdIter first, Size count); +} // namespace hpx + +#else // DOXYGEN + #include #include #include @@ -15,6 +173,7 @@ #include #include #include +#include #include #include #include @@ -36,19 +195,19 @@ namespace hpx { namespace parallel { inline namespace v1 { // provide our own implementation of std::uninitialized_default_construct as some // versions of MSVC horribly fail at compiling it for some types T - template - void std_uninitialized_default_construct(InIter first, InIter last) + template + Iter std_uninitialized_default_construct(Iter first, Sent last) { - typedef - typename std::iterator_traits::value_type value_type; + using value_type = typename std::iterator_traits::value_type; - InIter s_first = first; + Iter s_first = first; try { for (/* */; first != last; ++first) { ::new (std::addressof(*first)) value_type; } + return first; } catch (...) { @@ -66,8 +225,8 @@ namespace hpx { namespace parallel { inline namespace v1 { std::size_t count, util::cancellation_token& tok) { - typedef - typename std::iterator_traits::value_type value_type; + using value_type = + typename std::iterator_traits::value_type; return util::loop_with_cleanup_n_with_token( first, count, tok, @@ -121,11 +280,11 @@ namespace hpx { namespace parallel { inline namespace v1 { } }); } - /////////////////////////////////////////////////////////////////////// template struct uninitialized_default_construct - : public detail::algorithm> + : public detail::algorithm, + FwdIter> { uninitialized_default_construct() : uninitialized_default_construct::algorithm( @@ -133,76 +292,54 @@ namespace hpx { namespace parallel { inline namespace v1 { { } - template - static hpx::util::unused_type sequential( - ExPolicy, InIter first, InIter last) + template + static FwdIter sequential(ExPolicy, FwdIter first, Sent last) { - std_uninitialized_default_construct(first, last); - return hpx::util::unused; + return std_uninitialized_default_construct(first, last); } - template - static typename util::detail::algorithm_result::type - parallel(ExPolicy&& policy, FwdIter first, FwdIter last) + template + static + typename util::detail::algorithm_result::type + parallel(ExPolicy&& policy, FwdIter first, Sent last) { - return util::detail::algorithm_result::get( - parallel_sequential_uninitialized_default_construct_n( - std::forward(policy), first, - std::distance(first, last))); + return parallel_sequential_uninitialized_default_construct_n( + std::forward(policy), first, + detail::distance(first, last)); } }; /// \endcond } // namespace detail - /// Constructs objects of type typename iterator_traits::value_type - /// in the uninitialized storage designated by the range [first, last) by - /// default-initialization. If an exception is thrown during the - /// initialization, the function has no effects. - /// - /// \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 FwdIter The type of the source iterators used (deduced). - /// This iterator type must meet the requirements of an - /// forward iterator. - /// - /// \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. - /// - /// The assignments in the parallel \a uninitialized_default_construct - /// algorithm invoked with an execution policy object of type \a sequenced_policy - /// execute in sequential order in the calling thread. - /// - /// The assignments in the parallel \a uninitialized_default_construct - /// algorithm invoked with an execution policy object of type \a parallel_policy - /// or \a parallel_task_policy are permitted to execute in an - /// unordered fashion in unspecified threads, and indeterminately sequenced - /// within each thread. - /// - /// \returns The \a uninitialized_default_construct algorithm returns a - /// \a hpx::future, if the execution policy is of type - /// \a sequenced_task_policy or - /// \a parallel_task_policy and returns \a void otherwise. - /// template ::value&& hpx::traits::is_iterator::value)> + HPX_DEPRECATED_V(1, 7, + "hpx::parallel::uninitialized_default_construct is deprecated, use " + "hpx::uninitialized_default_construct " + "instead") typename util::detail::algorithm_result::type - uninitialized_default_construct( - ExPolicy&& policy, FwdIter first, FwdIter last) + uninitialized_default_construct( + ExPolicy&& policy, FwdIter first, FwdIter last) { static_assert((hpx::traits::is_forward_iterator::value), "Required at least forward iterator."); - return detail::uninitialized_default_construct().call( - std::forward(policy), first, last); +#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + using result_type = + typename hpx::parallel::util::detail::algorithm_result< + ExPolicy>::type; + + return hpx::util::void_guard(), + hpx::parallel::v1::detail::uninitialized_default_construct< + FwdIter>() + .call(std::forward(policy), first, last); +#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000 +#pragma GCC diagnostic pop +#endif } /////////////////////////////////////////////////////////////////////////// @@ -249,8 +386,9 @@ namespace hpx { namespace parallel { inline namespace v1 { { } - template - static InIter sequential(ExPolicy, InIter first, std::size_t count) + template + static FwdIter sequential( + ExPolicy, FwdIter first, std::size_t count) { return std_uninitialized_default_construct_n(first, count); } @@ -267,60 +405,18 @@ namespace hpx { namespace parallel { inline namespace v1 { /// \endcond } // namespace detail - /// Constructs objects of type typename iterator_traits::value_type - /// in the uninitialized storage designated by the range [first, first + count) by - /// default-initialization. If an exception is thrown during the - /// initialization, the function has no effects. - /// - /// \note Complexity: Performs exactly \a count assignments, if - /// count > 0, no assignments otherwise. - /// - /// \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 FwdIter The type of the source iterators used (deduced). - /// This iterator type must meet the requirements of an - /// forward iterator. - /// \tparam Size The type of the argument specifying the number of - /// elements to apply \a f to. - /// - /// \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 count Refers to the number of elements starting at - /// \a first the algorithm will be applied to. - /// - /// The assignments in the parallel \a uninitialized_default_construct_n - /// algorithm invoked with an execution policy object of type - /// \a sequenced_policy execute in sequential order in the - /// calling thread. - /// - /// The assignments in the parallel \a uninitialized_default_construct_n - /// algorithm invoked with an execution policy object of type - /// \a parallel_policy or - /// \a parallel_task_policy are permitted to execute in an - /// unordered fashion in unspecified threads, and indeterminately sequenced - /// within each thread. - /// - /// \returns The \a uninitialized_default_construct_n algorithm returns a - /// \a hpx::future if the execution policy is of type - /// \a sequenced_task_policy or - /// \a parallel_task_policy and - /// returns \a FwdIter otherwise. - /// The \a uninitialized_default_construct_n algorithm returns the - /// iterator to the element in the source range, one past - /// the last element constructed. - /// template ::value&& hpx::traits::is_iterator::value)> + HPX_DEPRECATED_V(1, 7, + "hpx::parallel::uninitialized_default_construct_n is deprecated, use " + "hpx::uninitialized_default_construct_n " + "instead") typename util::detail::algorithm_result::type - uninitialized_default_construct_n( - ExPolicy&& policy, FwdIter first, Size count) + uninitialized_default_construct_n( + ExPolicy&& policy, FwdIter first, Size count) { - static_assert((hpx::traits::is_forward_iterator::value), + static_assert(hpx::traits::is_forward_iterator::value, "Requires at least forward iterator."); // if count is representing a negative value, we do nothing @@ -330,7 +426,125 @@ namespace hpx { namespace parallel { inline namespace v1 { std::move(first)); } +#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif return detail::uninitialized_default_construct_n().call( std::forward(policy), first, std::size_t(count)); } +#if defined(HPX_GCC_VERSION) && HPX_GCC_VERSION >= 100000 +#pragma GCC diagnostic pop +#endif }}} // namespace hpx::parallel::v1 + +namespace hpx { + /////////////////////////////////////////////////////////////////////////// + // DPO for hpx::uninitialized_default_construct + HPX_INLINE_CONSTEXPR_VARIABLE struct uninitialized_default_construct_t final + : hpx::functional::tag_fallback + { + // clang-format off + template ::value + )> + // clang-format on + friend void tag_fallback_dispatch( + hpx::uninitialized_default_construct_t, FwdIter first, FwdIter last) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + hpx::parallel::v1::detail::uninitialized_default_construct< + FwdIter>() + .call(hpx::execution::seq, first, last); + } + + // clang-format off + template ::value && + hpx::traits::is_forward_iterator::value + )> + // clang-format on + friend typename parallel::util::detail::algorithm_result::type + tag_fallback_dispatch(hpx::uninitialized_default_construct_t, + ExPolicy&& policy, FwdIter first, FwdIter last) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + using result_type = + typename hpx::parallel::util::detail::algorithm_result< + ExPolicy>::type; + + return hpx::util::void_guard(), + hpx::parallel::v1::detail::uninitialized_default_construct< + FwdIter>() + .call(std::forward(policy), first, last); + } + + } uninitialized_default_construct{}; + + /////////////////////////////////////////////////////////////////////////// + // DPO for hpx::uninitialized_default_construct_n + HPX_INLINE_CONSTEXPR_VARIABLE struct uninitialized_default_construct_n_t + final + : hpx::functional::tag_fallback + { + // clang-format off + template ::value + )> + // clang-format on + friend FwdIter tag_fallback_dispatch( + hpx::uninitialized_default_construct_n_t, FwdIter first, Size count) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + // if count is representing a negative value, we do nothing + if (hpx::parallel::v1::detail::is_negative(count)) + { + return first; + } + + return hpx::parallel::v1::detail::uninitialized_default_construct_n< + FwdIter>() + .call(hpx::execution::seq, first, std::size_t(count)); + } + + // clang-format off + template ::value && + hpx::traits::is_forward_iterator::value + )> + // clang-format on + friend typename parallel::util::detail::algorithm_result::type + tag_fallback_dispatch(hpx::uninitialized_default_construct_n_t, + ExPolicy&& policy, FwdIter first, Size count) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + // if count is representing a negative value, we do nothing + if (hpx::parallel::v1::detail::is_negative(count)) + { + return parallel::util::detail::algorithm_result::get(std::move(first)); + } + + return hpx::parallel::v1::detail::uninitialized_default_construct_n< + FwdIter>() + .call( + std::forward(policy), first, std::size_t(count)); + } + + } uninitialized_default_construct_n{}; +} // namespace hpx + +#endif // DOXYGEN diff --git a/libs/parallelism/algorithms/include/hpx/parallel/container_algorithms/uninitialized_default_construct.hpp b/libs/parallelism/algorithms/include/hpx/parallel/container_algorithms/uninitialized_default_construct.hpp new file mode 100644 index 000000000000..3cec8ee70bf5 --- /dev/null +++ b/libs/parallelism/algorithms/include/hpx/parallel/container_algorithms/uninitialized_default_construct.hpp @@ -0,0 +1,413 @@ +// Copyright (c) 2020 ETH Zurich +// Copyright (c) 2014 Grant Mercer +// +// 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) + +/// \file parallel/container_algorithms/uninitialized_default_construct.hpp + +#pragma once + +#if defined(DOXYGEN) + +namespace hpx { namespace ranges { + // clang-format off + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// by default-initialization. If an exception is thrown during the + /// initialization, the function has no effects. + /// + /// \note Complexity: Performs exactly \a last - \a first assignments. + /// + /// \tparam FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Sent The type of the source sentinel (deduced). This + /// sentinel type must be a sentinel for FwdIter. + /// + /// \param first Refers to the beginning of the sequence of elements + /// the algorithm will be applied to. + /// \param last Refers to sentinel value denoting the end of the + /// sequence of elements the algorithm will be applied. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked without an execution policy object will execute in + /// sequential order in the calling thread. + /// + /// \returns The \a uninitialized_default_construct algorithm returns a + /// returns \a FwdIter. + /// The \a uninitialized_default_construct algorithm returns the + /// output iterator to the element in the range, one past + /// the last element constructed. + /// + template + FwdIter uninitialized_default_construct( + FwdIter first, Sent last); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// by default-initialization. If an exception is thrown during the + /// initialization, the function has no effects. + /// + /// \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 FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Sent The type of the source sentinel (deduced). This + /// sentinel type must be a sentinel for FwdIter. + /// + /// \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 sentinel value denoting the end of the + /// sequence of elements the algorithm will be applied. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked with an execution policy object of type \a + /// sequenced_policy execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked with an execution policy object of type \a + /// parallel_policy or \a parallel_task_policy are permitted to execute + /// in an unordered fashion in unspecified threads, and indeterminately + /// sequenced within each thread. + /// + /// \returns The \a uninitialized_default_construct algorithm returns a + /// \a hpx::future if the execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a FwdIter otherwise. + /// The \a uninitialized_default_construct algorithm returns + /// the iterator to the element in the source range, one past + /// the last element constructed. + /// + template + typename parallel::util::detail::algorithm_result::type + uninitialized_default_construct( + ExPolicy&& policy, FwdIter first, Sent last); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// by default-initialization. If an exception is thrown during the + /// initialization, the function has no effects. + /// + /// \note Complexity: Performs exactly \a last - \a first 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. + /// + /// \param rng Refers to the range to which will be default + /// constructed. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked without an execution policy object will execute in + /// sequential order in the calling thread. + /// + /// \returns The \a uninitialized_default_construct algorithm returns a + /// returns \a hpx::traits::range_traits + /// ::iterator_type. + /// The \a uninitialized_default_construct algorithm returns + /// the output iterator to the element in the range, one past + /// the last element constructed. + /// + template + typename hpx::traits::range_traits::iterator_type + uninitialized_default_construct(Rng&& rng); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// by default-initialization. If an exception is thrown during the + /// initialization, the function has no effects. + /// + /// \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 an input iterator. + /// + /// \param policy The execution policy to use for the scheduling of + /// the iterations. + /// \param rng Refers to the range to which the value + /// will be default consutrcted + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked with an execution policy object of type \a + /// sequenced_policy execute in sequential order in the calling thread. + /// + /// The assignments in the parallel \a uninitialized_default_construct + /// algorithm invoked with an execution policy object of type \a + /// parallel_policy or \a parallel_task_policy are permitted to execute + /// in an unordered fashion in unspecified threads, and indeterminately + /// sequenced within each thread. + /// + /// \returns The \a uninitialized_default_construct algorithm returns a + /// \a hpx::future + /// ::iterator_type>, if the + /// execution policy is of type \a sequenced_task_policy + /// or \a parallel_task_policy and returns \a typename + /// hpx::traits::range_traits::iterator_type otherwise. + /// The \a uninitialized_default_construct algorithm returns + /// the output iterator to the element in the range, one past + /// the last element constructed. + /// + template + typename parallel::util::detail::algorithm_result::iterator_type>::type + uninitialized_default_construct(ExPolicy&& policy, Rng&& rng); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// [first, first + count) by default-initialization. If an exception + /// is thrown during the initialization, the function has no effects. + /// + /// \note Complexity: Performs exactly \a count assignments, if + /// count > 0, no assignments otherwise. + /// + /// \tparam FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Size The type of the argument specifying the number of + /// elements to apply \a f to. + /// + /// \param first Refers to the beginning of the sequence of elements + /// the algorithm will be applied to. + /// \param count Refers to the number of elements starting at + /// \a first the algorithm will be applied to. + /// + /// The assignments in the parallel \a uninitialized_default_construct_n + /// algorithm invoked without an execution policy object execute in + /// sequential order in the calling thread. + /// + /// \returns The \a uninitialized_default_construct_n algorithm returns a + /// returns \a FwdIter. + /// The \a uninitialized_default_construct_n algorithm returns + /// the iterator to the element in the source range, one past + /// the last element constructed. + /// + template + FwdIter uninitialized_default_construct_n(FwdIter first, Size count); + + /// Constructs objects of type typename iterator_traits + /// ::value_type in the uninitialized storage designated by the range + /// [first, first + count) by default-initialization. If an exception + /// is thrown during the initialization, the function has no effects. + /// + /// \note Complexity: Performs exactly \a count assignments, if + /// count > 0, no assignments otherwise. + /// + /// \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 FwdIter The type of the source iterators used (deduced). + /// This iterator type must meet the requirements of an + /// forward iterator. + /// \tparam Size The type of the argument specifying the number of + /// elements to apply \a f to. + /// + /// \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 count Refers to the number of elements starting at + /// \a first the algorithm will be applied to. + /// + /// The assignments in the parallel \a uninitialized_default_construct_n + /// algorithm invoked with an execution policy object of type + /// \a sequenced_policy execute in sequential order in the + /// calling thread. + /// + /// The assignments in the parallel \a uninitialized_default_construct_n + /// algorithm invoked with an execution policy object of type + /// \a parallel_policy or + /// \a parallel_task_policy are permitted to execute in an + /// unordered fashion in unspecified threads, and indeterminately sequenced + /// within each thread. + /// + /// \returns The \a uninitialized_default_construct_n algorithm returns a + /// \a hpx::future if the execution policy is of type + /// \a sequenced_task_policy or + /// \a parallel_task_policy and + /// returns \a FwdIter otherwise. + /// The \a uninitialized_default_construct_n algorithm returns + /// the iterator to the element in the source range, one past + /// the last element constructed. + /// + template + typename typename parallel::util::detail::algorithm_result::type + uninitialized_default_construct_n( + ExPolicy&& policy, FwdIter first, Size count); + + // clang-format on +}} // namespace hpx::ranges +#else + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace hpx { namespace ranges { + HPX_INLINE_CONSTEXPR_VARIABLE struct uninitialized_default_construct_t final + : hpx::functional::tag_fallback + { + private: + // clang-format off + template ::value && + hpx::traits::is_sentinel_for::value + )> + // clang-format on + friend FwdIter tag_fallback_dispatch( + hpx::ranges::uninitialized_default_construct_t, FwdIter first, + Sent last) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::uninitialized_default_construct< + FwdIter>() + .call(hpx::execution::seq, first, last); + } + + // clang-format off + template ::value && + hpx::traits::is_forward_iterator::value && + hpx::traits::is_sentinel_for::value + )> + // clang-format on + friend typename parallel::util::detail::algorithm_result::type + tag_fallback_dispatch(hpx::ranges::uninitialized_default_construct_t, + ExPolicy&& policy, FwdIter first, Sent last) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::uninitialized_default_construct< + FwdIter>() + .call(std::forward(policy), first, last); + } + + // clang-format off + template ::value + )> + // clang-format on + friend typename hpx::traits::range_traits::iterator_type + tag_fallback_dispatch( + hpx::ranges::uninitialized_default_construct_t, Rng&& rng) + { + using iterator_type = + typename hpx::traits::range_traits::iterator_type; + + static_assert( + hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::uninitialized_default_construct< + iterator_type>() + .call(hpx::execution::seq, std::begin(rng), std::end(rng)); + } + + // clang-format off + template ::value && + hpx::traits::is_range::value + )> + // clang-format on + friend typename parallel::util::detail::algorithm_result::iterator_type>::type + tag_fallback_dispatch(hpx::ranges::uninitialized_default_construct_t, + ExPolicy&& policy, Rng&& rng) + { + using iterator_type = + typename hpx::traits::range_traits::iterator_type; + + static_assert( + hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::uninitialized_default_construct< + iterator_type>() + .call(std::forward(policy), std::begin(rng), + std::end(rng)); + } + } uninitialized_default_construct{}; + + HPX_INLINE_CONSTEXPR_VARIABLE struct uninitialized_default_construct_n_t + final + : hpx::functional::tag_fallback + { + private: + // clang-format off + template ::value + )> + // clang-format on + friend FwdIter tag_fallback_dispatch( + hpx::ranges::uninitialized_default_construct_n_t, FwdIter first, + Size count) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::uninitialized_default_construct_n< + FwdIter>() + .call(hpx::execution::seq, first, count); + } + + // clang-format off + template ::value && + hpx::traits::is_forward_iterator::value + )> + // clang-format on + friend typename parallel::util::detail::algorithm_result::type + tag_fallback_dispatch(hpx::ranges::uninitialized_default_construct_n_t, + ExPolicy&& policy, FwdIter first, Size count) + { + static_assert(hpx::traits::is_forward_iterator::value, + "Requires at least forward iterator."); + + return hpx::parallel::v1::detail::uninitialized_default_construct_n< + FwdIter>() + .call(std::forward(policy), first, count); + } + } uninitialized_default_construct_n{}; +}} // namespace hpx::ranges + +#endif diff --git a/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_construct_tests.hpp b/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_construct_tests.hpp index 645b43c301d5..4a22e3e4670a 100644 --- a/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_construct_tests.hpp +++ b/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_construct_tests.hpp @@ -52,7 +52,7 @@ void test_uninitialized_default_construct(ExPolicy&& policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(default_constructable)); - hpx::parallel::uninitialized_default_construct( + hpx::uninitialized_default_construct( std::forward(policy), iterator(p), iterator(p + data_size)); std::size_t count = 0; @@ -76,7 +76,7 @@ void test_uninitialized_default_construct_async(ExPolicy&& policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(default_constructable)); - auto f = hpx::parallel::uninitialized_default_construct( + auto f = hpx::uninitialized_default_construct( std::forward(policy), iterator(p), iterator(p + data_size)); f.wait(); @@ -104,7 +104,7 @@ void test_uninitialized_default_construct2(ExPolicy&& policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(value_constructable)); - hpx::parallel::uninitialized_default_construct( + hpx::uninitialized_default_construct( std::forward(policy), iterator(p), iterator(p + data_size)); std::size_t count = 0; @@ -128,7 +128,7 @@ void test_uninitialized_default_construct_async2(ExPolicy&& policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(value_constructable)); - auto f = hpx::parallel::uninitialized_default_construct( + auto f = hpx::uninitialized_default_construct( std::forward(policy), iterator(p), iterator(p + data_size)); f.wait(); @@ -167,7 +167,7 @@ void test_uninitialized_default_construct_exception( bool caught_exception = false; try { - hpx::parallel::uninitialized_default_construct(policy, + hpx::uninitialized_default_construct(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) @@ -215,7 +215,7 @@ void test_uninitialized_default_construct_exception_async( bool returned_from_algorithm = false; try { - auto f = hpx::parallel::uninitialized_default_construct(policy, + auto f = hpx::uninitialized_default_construct(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) @@ -271,7 +271,7 @@ void test_uninitialized_default_construct_bad_alloc( bool caught_bad_alloc = false; try { - hpx::parallel::uninitialized_default_construct(policy, + hpx::uninitialized_default_construct(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) @@ -319,7 +319,7 @@ void test_uninitialized_default_construct_bad_alloc_async( bool returned_from_algorithm = false; try { - auto f = hpx::parallel::uninitialized_default_construct(policy, + auto f = hpx::uninitialized_default_construct(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) diff --git a/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_constructn.cpp b/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_constructn.cpp index c2aeee0e07e5..8238b5ceb069 100644 --- a/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_constructn.cpp +++ b/libs/parallelism/algorithms/tests/unit/algorithms/uninitialized_default_constructn.cpp @@ -50,8 +50,7 @@ void test_uninitialized_default_construct_n(ExPolicy policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(default_constructable)); - hpx::parallel::uninitialized_default_construct_n( - policy, iterator(p), data_size); + hpx::uninitialized_default_construct_n(policy, iterator(p), data_size); std::size_t count = 0; std::for_each(p, p + data_size, [&count](default_constructable v1) { @@ -74,8 +73,8 @@ void test_uninitialized_default_construct_n_async(ExPolicy policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(default_constructable)); - auto f = hpx::parallel::uninitialized_default_construct_n( - policy, iterator(p), data_size); + auto f = + hpx::uninitialized_default_construct_n(policy, iterator(p), data_size); f.wait(); std::size_t count = 0; @@ -102,8 +101,7 @@ void test_uninitialized_default_construct_n2(ExPolicy policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(value_constructable)); - hpx::parallel::uninitialized_default_construct_n( - policy, iterator(p), data_size); + hpx::uninitialized_default_construct_n(policy, iterator(p), data_size); std::size_t count = 0; std::for_each(p, p + data_size, [&count](value_constructable v1) { @@ -126,8 +124,8 @@ void test_uninitialized_default_construct_n_async2(ExPolicy policy, IteratorTag) std::memset( static_cast(p), 0xcd, data_size * sizeof(value_constructable)); - auto f = hpx::parallel::uninitialized_default_construct_n( - policy, iterator(p), data_size); + auto f = + hpx::uninitialized_default_construct_n(policy, iterator(p), data_size); f.wait(); std::size_t count = 0; @@ -191,7 +189,7 @@ void test_uninitialized_default_construct_n_exception( bool caught_exception = false; try { - hpx::parallel::uninitialized_default_construct_n(policy, + hpx::uninitialized_default_construct_n(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) @@ -239,7 +237,7 @@ void test_uninitialized_default_construct_n_exception_async( bool returned_from_algorithm = false; try { - auto f = hpx::parallel::uninitialized_default_construct_n(policy, + auto f = hpx::uninitialized_default_construct_n(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) @@ -320,7 +318,7 @@ void test_uninitialized_default_construct_n_bad_alloc( bool caught_bad_alloc = false; try { - hpx::parallel::uninitialized_default_construct_n(policy, + hpx::uninitialized_default_construct_n(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) @@ -368,7 +366,7 @@ void test_uninitialized_default_construct_n_bad_alloc_async( bool returned_from_algorithm = false; try { - auto f = hpx::parallel::uninitialized_default_construct_n(policy, + auto f = hpx::uninitialized_default_construct_n(policy, decorated_iterator(p, [&throw_after]() { if (throw_after-- == 0) diff --git a/libs/parallelism/algorithms/tests/unit/container_algorithms/CMakeLists.txt b/libs/parallelism/algorithms/tests/unit/container_algorithms/CMakeLists.txt index a588b0a59fe8..a1c7057fd28e 100644 --- a/libs/parallelism/algorithms/tests/unit/container_algorithms/CMakeLists.txt +++ b/libs/parallelism/algorithms/tests/unit/container_algorithms/CMakeLists.txt @@ -94,6 +94,8 @@ set(tests transform_reduce_binary_exception_range transform_reduce_binary_range transform_reduce_range + uninitialized_default_construct_range + uninitialized_default_constructn_range uninitialized_move_range uninitialized_move_n_range unique_range diff --git a/libs/parallelism/algorithms/tests/unit/container_algorithms/uninitialized_default_construct_range.cpp b/libs/parallelism/algorithms/tests/unit/container_algorithms/uninitialized_default_construct_range.cpp new file mode 100644 index 000000000000..eeae277a9ace --- /dev/null +++ b/libs/parallelism/algorithms/tests/unit/container_algorithms/uninitialized_default_construct_range.cpp @@ -0,0 +1,288 @@ +// Copyright (c) 2018 Christopher Ogle +// Copyright (c) 2020 Hartmut Kaiser +// +// 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 +#include + +#include "test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +struct default_constructable +{ + default_constructable() + : value_(42) + { + } + + explicit default_constructable(std::int32_t val) + { + value_ = val; + } + + bool operator!=(std::int32_t const& lhs) const + { + return lhs != value_; + } + + std::int32_t value_; +}; + +struct value_constructable +{ + std::int32_t value_; +}; + +std::size_t const data_size = 10007; + +//////////////////////////////////////////////////////////////////////////// +template +void test_uninitialized_default_construct_range_sent(IteratorTag) +{ + typedef std::vector base_iterator; + + base_iterator c(data_size, default_constructable(10)); + auto end_size = rand() % data_size; + c[end_size] = default_constructable(20); + + hpx::ranges::uninitialized_default_construct( + std::begin(c), sentinel{20}); + + std::size_t count42 = 0; + std::size_t count10 = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count42, &count10](default_constructable v1) { + if (v1.value_ == 42) + { + count42++; + } + else if (v1.value_ == 10) + { + count10++; + } + }); + + HPX_TEST_EQ(count42, end_size); + HPX_TEST_EQ(count10, data_size - end_size - 1); +} + +template +void test_uninitialized_default_construct_range_sent( + ExPolicy&& policy, IteratorTag) +{ + typedef std::vector base_iterator; + + base_iterator c(data_size, default_constructable(10)); + auto end_size = rand() % data_size; + c[end_size] = default_constructable(20); + + hpx::ranges::uninitialized_default_construct( + policy, std::begin(c), sentinel{20}); + + std::size_t count42 = 0; + std::size_t count10 = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count42, &count10](default_constructable v1) { + if (v1.value_ == 42) + { + count42++; + } + else if (v1.value_ == 10) + { + count10++; + } + }); + + HPX_TEST_EQ(count42, end_size); + HPX_TEST_EQ(count10, data_size - end_size - 1); +} + +template +void test_uninitialized_default_construct_range(IteratorTag) +{ + typedef std::vector base_iterator; + + base_iterator c(data_size, default_constructable(10)); + hpx::ranges::uninitialized_default_construct(c); + + std::size_t count = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count](default_constructable v1) { + HPX_TEST_EQ(v1.value_, 42); + ++count; + }); + HPX_TEST_EQ(count, data_size); +} + +template +void test_uninitialized_default_construct_range(ExPolicy&& policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector base_iterator; + + base_iterator c(data_size, default_constructable(10)); + hpx::ranges::uninitialized_default_construct( + std::forward(policy), c); + + std::size_t count = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count](default_constructable v1) { + HPX_TEST_EQ(v1.value_, 42); + ++count; + }); + HPX_TEST_EQ(count, data_size); +} + +template +void test_uninitialized_default_construct_range_async( + ExPolicy&& policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector base_iterator; + + base_iterator c(data_size, default_constructable(10)); + auto f = hpx::ranges::uninitialized_default_construct( + std::forward(policy), c); + f.wait(); + + std::size_t count = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count](default_constructable v1) { + HPX_TEST_EQ(v1.value_, 42); + ++count; + }); + HPX_TEST_EQ(count, data_size); +} + +template +void test_uninitialized_default_construct_range2(ExPolicy&& policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector base_iterator; + base_iterator c(data_size, value_constructable{10}); + + hpx::ranges::uninitialized_default_construct( + std::forward(policy), c); + + std::size_t count = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count](value_constructable v1) { + HPX_TEST_EQ(v1.value_, (std::int32_t) 10); + ++count; + }); + HPX_TEST_EQ(count, data_size); +} + +template +void test_uninitialized_default_construct_range_async2( + ExPolicy&& policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + typedef std::vector base_iterator; + base_iterator c(data_size, value_constructable{10}); + + auto f = hpx::ranges::uninitialized_default_construct( + std::forward(policy), c); + f.wait(); + + std::size_t count = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count](value_constructable v1) { + HPX_TEST_EQ(v1.value_, (std::int32_t) 10); + ++count; + }); + HPX_TEST_EQ(count, data_size); +} + +template +void test_uninitialized_default_construct_range() +{ + using namespace hpx::execution; + + test_uninitialized_default_construct_range(IteratorTag()); + test_uninitialized_default_construct_range(seq, IteratorTag()); + test_uninitialized_default_construct_range(par, IteratorTag()); + test_uninitialized_default_construct_range(par_unseq, IteratorTag()); + + test_uninitialized_default_construct_range_async(seq(task), IteratorTag()); + test_uninitialized_default_construct_range_async(par(task), IteratorTag()); + + test_uninitialized_default_construct_range2(seq, IteratorTag()); + test_uninitialized_default_construct_range2(par, IteratorTag()); + test_uninitialized_default_construct_range2(par_unseq, IteratorTag()); + + test_uninitialized_default_construct_range_async2(seq(task), IteratorTag()); + test_uninitialized_default_construct_range_async2(par(task), IteratorTag()); + + test_uninitialized_default_construct_range_sent(IteratorTag()); + test_uninitialized_default_construct_range_sent(seq, IteratorTag()); + test_uninitialized_default_construct_range_sent(par, IteratorTag()); + test_uninitialized_default_construct_range_sent(par_unseq, IteratorTag()); +} + +void uninitialized_default_construct_range_test() +{ + test_uninitialized_default_construct_range< + std::random_access_iterator_tag>(); + test_uninitialized_default_construct_range(); +} + +//////////////////////////////////////////////////////////////////////////// +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); + + uninitialized_default_construct_range_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/parallelism/algorithms/tests/unit/container_algorithms/uninitialized_default_constructn_range.cpp b/libs/parallelism/algorithms/tests/unit/container_algorithms/uninitialized_default_constructn_range.cpp new file mode 100644 index 000000000000..02d60512d3c6 --- /dev/null +++ b/libs/parallelism/algorithms/tests/unit/container_algorithms/uninitialized_default_constructn_range.cpp @@ -0,0 +1,188 @@ +// Copyright (c) 2014 Grant Mercer +// Copyright (c) 2015 Hartmut Kaiser +// +// 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 + +#include "test_utils.hpp" + +//////////////////////////////////////////////////////////////////////////// +struct default_constructable +{ + default_constructable() + : value_(42) + { + } + + explicit default_constructable(std::int32_t val) + { + value_ = val; + } + + std::int32_t value_; +}; + +std::size_t const data_size = 10007; + +//////////////////////////////////////////////////////////////////////////// +template +void test_uninitialized_default_construct_n(IteratorTag) +{ + using base_iterator = std::vector; + + base_iterator c(data_size, default_constructable(10)); + auto end_size = rand() % data_size; + hpx::ranges::uninitialized_default_construct_n(std::begin(c), end_size); + + std::size_t count42 = 0; + std::size_t count10 = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count42, &count10](default_constructable v1) { + if (v1.value_ == 42) + { + count42++; + } + else if (v1.value_ == 10) + { + count10++; + } + }); + + HPX_TEST_EQ(count42, end_size); + HPX_TEST_EQ(count10, data_size - end_size); +} + +template +void test_uninitialized_default_construct_n(ExPolicy&& policy, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + using base_iterator = std::vector; + + base_iterator c(data_size, default_constructable(10)); + auto end_size = rand() % data_size; + hpx::ranges::uninitialized_default_construct_n( + policy, std::begin(c), end_size); + + std::size_t count42 = 0; + std::size_t count10 = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count42, &count10](default_constructable v1) { + if (v1.value_ == 42) + { + count42++; + } + else if (v1.value_ == 10) + { + count10++; + } + }); + + HPX_TEST_EQ(count42, end_size); + HPX_TEST_EQ(count10, data_size - end_size); +} + +template +void test_uninitialized_default_construct_n_async(ExPolicy&& p, IteratorTag) +{ + static_assert(hpx::is_execution_policy::value, + "hpx::is_execution_policy::value"); + + using base_iterator = std::vector; + + base_iterator c(data_size, default_constructable(10)); + auto end_size = rand() % data_size; + auto f = hpx::ranges::uninitialized_default_construct_n( + p, std::begin(c), end_size); + f.wait(); + + std::size_t count42 = 0; + std::size_t count10 = 0; + std::for_each(std::begin(c), std::begin(c) + data_size, + [&count42, &count10](default_constructable v1) { + if (v1.value_ == 42) + { + count42++; + } + else if (v1.value_ == 10) + { + count10++; + } + }); + + HPX_TEST_EQ(count42, end_size); + HPX_TEST_EQ(count10, data_size - end_size); +} + +template +void test_uninitialized_default_construct_n() +{ + using namespace hpx::execution; + + test_uninitialized_default_construct_n(IteratorTag()); + + test_uninitialized_default_construct_n(seq, IteratorTag()); + test_uninitialized_default_construct_n(par, IteratorTag()); + test_uninitialized_default_construct_n(par_unseq, IteratorTag()); + + test_uninitialized_default_construct_n_async(seq(task), IteratorTag()); + test_uninitialized_default_construct_n_async(par(task), IteratorTag()); +} + +void uninitialized_default_construct_n_test() +{ + test_uninitialized_default_construct_n(); + test_uninitialized_default_construct_n(); +} + +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); + + uninitialized_default_construct_n_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(); +}