Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relocation algorithms Clean #6314

Closed
Closed
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
2709dd9
relocate_at impl w/ tests
isidorostsa Jul 27, 2023
3afc851
uninitialized_relocate w/ tests and comments fixed
isidorostsa Jul 28, 2023
0b3a6e8
expected compile error tests
isidorostsa Jul 28, 2023
fe6e0fb
clang-format
isidorostsa Jul 28, 2023
8ef523a
add explicit-noexcept where it is missing
isidorostsa Jul 29, 2023
13a1279
enum instead of magic numbers
isidorostsa Jul 29, 2023
2c9edb0
remove explicit from move constructors
isidorostsa Jul 30, 2023
36b70cb
add explicit to relocate_at.cpp too
isidorostsa Jul 30, 2023
148d729
fix Werror=class-memaccess, cast away const
isidorostsa Jul 31, 2023
cafae0c
clang-format
isidorostsa Jul 31, 2023
bf48827
too long line
isidorostsa Aug 1, 2023
2706778
clang-format
isidorostsa Aug 1, 2023
07bd94c
Arrays of TR types are TR
isidorostsa Jul 11, 2023
6f22033
is_trivially_copyable -> is_trivially_relocatable correction
isidorostsa Jul 11, 2023
cb44e29
Add cvrefs and arrays to be "decayed"
isidorostsa Jul 13, 2023
7fb8958
arrays of known size
isidorostsa Jul 13, 2023
3f6059d
const volatile to avoid ambiguity
isidorostsa Jul 26, 2023
4367007
cover rvalues too
isidorostsa Jul 26, 2023
6dcb771
clang format
isidorostsa Jul 27, 2023
6e532e1
testing and more specific ambiguity checks
isidorostsa Jul 28, 2023
18705b9
clang-format
isidorostsa Jul 31, 2023
22aeff9
clang-format
isidorostsa Aug 6, 2023
944ccb9
detect trivially relocatable category
isidorostsa Aug 11, 2023
7dbc69e
specific loop version needed for relocations
isidorostsa Aug 11, 2023
ba51777
uninitialized_relocate helpers
isidorostsa Aug 11, 2023
b41893f
deprecate type_support/uninitialized_relocate.hpp
isidorostsa Aug 11, 2023
87f68e1
algorithms/uninitialized_relocate.hpp seq version
isidorostsa Aug 11, 2023
ab55350
algorithms/uninitialized_relocate.hpp par version
isidorostsa Aug 11, 2023
324c3f1
various syntax fixes
isidorostsa Aug 13, 2023
8d126a3
uninitialized_relocate_n test
isidorostsa Aug 21, 2023
b2f3946
include is_relocatable
isidorostsa Aug 21, 2023
40269c0
missing includes and namespaces
isidorostsa Aug 21, 2023
312cf1f
fix includes
isidorostsa Aug 22, 2023
b30eb55
fix typo + include
isidorostsa Aug 22, 2023
8685988
endline
isidorostsa Aug 22, 2023
2c1f407
remove circ dep
isidorostsa Aug 22, 2023
9b27231
correctly resolve namespaces
isidorostsa Aug 22, 2023
db65f32
change uninitialzied_relocate_n test name
isidorostsa Aug 22, 2023
8f0cc63
uninitialized_relocate iterators version
isidorostsa Aug 22, 2023
6e1e85e
add noexcept relocation detector
isidorostsa Aug 22, 2023
db8ed7c
use HPX_CONCEPT_REQUIRES, detect noexcepts
isidorostsa Aug 22, 2023
a3d51bf
fix returned value of nothrow relocation
isidorostsa Aug 22, 2023
00fb2e5
clang-format
isidorostsa Aug 22, 2023
0d3d917
clang-format
isidorostsa Aug 22, 2023
0d3a178
inspect
isidorostsa Aug 22, 2023
0a60cf8
Merge branch 'relocate_algorithms_clean' of github.com:isidorostsa/hp…
isidorostsa Aug 22, 2023
1a2e8a7
remove unneeded params + clang-format
isidorostsa Aug 22, 2023
99c4dbb
using execution_policy instead of hpx/execution
isidorostsa Aug 22, 2023
36080a3
include fixes
isidorostsa Aug 22, 2023
a9f9e9a
remove unused var
isidorostsa Aug 23, 2023
32ed3c1
unwrap zip_iterator manually
isidorostsa Aug 23, 2023
c288589
clang-format
isidorostsa Aug 23, 2023
95a70a0
gcc11 fix unpacking iterators
isidorostsa Aug 23, 2023
4b98351
clang-format
isidorostsa Aug 24, 2023
909998c
Add doxygen docs
isidorostsa Aug 24, 2023
4bdc115
clang-format
isidorostsa Aug 24, 2023
1e57fe5
docs typo
isidorostsa Aug 24, 2023
426c52a
EOF endline
isidorostsa Aug 24, 2023
8fd47df
public api gives better warnings
isidorostsa Aug 25, 2023
d26c2f6
atomics in test
isidorostsa Sep 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libs/core/algorithms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ set(algorithms_headers
hpx/parallel/algorithms/uninitialized_default_construct.hpp
hpx/parallel/algorithms/uninitialized_fill.hpp
hpx/parallel/algorithms/uninitialized_move.hpp
hpx/parallel/algorithms/uninitialized_relocate.hpp
hpx/parallel/algorithms/uninitialized_value_construct.hpp
hpx/parallel/algorithms/unique.hpp
hpx/parallel/container_algorithms/adjacent_difference.hpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#pragma once

#include <hpx/iterator_support/traits/is_iterator.hpp>
#include <hpx/type_support/is_relocatable.hpp>
#include <hpx/type_support/is_trivially_relocatable.hpp>

#include <type_traits>

Expand All @@ -25,7 +25,11 @@ namespace hpx::traits {
{
};

struct relocatable_pointer_tag : general_pointer_tag
struct trivially_relocatable_pointer_tag : general_pointer_tag
{
};

struct nothrow_relocatable_pointer_tag : general_pointer_tag
{
};

Expand Down Expand Up @@ -143,10 +147,27 @@ namespace hpx::traits {
bool Contiguous = iterators_are_contiguous_v<Source, Dest>>
struct pointer_relocate_category
{
using type = std::conditional_t<
std::is_same_v<iter_value_t<Source>, iter_value_t<Dest>> &&
is_relocatable_v<iter_value_t<Source>>,
relocatable_pointer_tag, general_pointer_tag>;
using type_src = iter_value_t<Source>;
using type_dst = iter_value_t<Dest>;

constexpr static bool valid_relocation =
is_relocatable_from_v<type_src, type_dst>;

constexpr static bool memcpy_legal =
!std::is_volatile_v<type_src> && !std::is_volatile_v<type_dst>;

constexpr static bool is_buffer_memcpyable = valid_relocation &&
is_trivially_relocatable_v<type_src> &&
iterators_are_contiguous_v<Source, Dest> && memcpy_legal;

constexpr static bool can_move_construct_nothrow =
std::is_nothrow_constructible_v<type_src,
std::add_rvalue_reference_t<type_dst>>;

using type = std::conditional_t<is_buffer_memcpyable,
trivially_relocatable_pointer_tag,
std::conditional_t<is_buffer_memcpyable,
nothrow_relocatable_pointer_tag, general_pointer_tag>>;
};

template <typename Source, typename Dest>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
// Copyright (c) 2014-2023 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)

/// \file parallel/algorithms/uninitialized_relocate.hpp

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding some docs as well? @dimitraka can help with the integration into the documentation build etc.

#pragma once

#include <hpx/config.hpp>
#include <hpx/concepts/concepts.hpp>
#include <hpx/execution/algorithms/detail/is_negative.hpp>
#include <hpx/executors/execution_policy.hpp>
#include <hpx/iterator_support/traits/is_iterator.hpp>
#include <hpx/parallel/algorithms/detail/dispatch.hpp>
#include <hpx/parallel/algorithms/detail/distance.hpp>
#include <hpx/parallel/unseq/loop.hpp>
#include <hpx/parallel/util/detail/algorithm_result.hpp>
#include <hpx/parallel/util/detail/clear_container.hpp>
#include <hpx/parallel/util/detail/sender_util.hpp>
#include <hpx/parallel/util/loop.hpp>
#include <hpx/parallel/util/partitioner_with_cleanup.hpp>
#include <hpx/parallel/util/result_types.hpp>
#include <hpx/parallel/util/transfer.hpp>
#include <hpx/parallel/util/zip_iterator.hpp>
#include <hpx/type_support/construct_at.hpp>

#include <algorithm>
#include <cstddef>
#include <cstring>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>

namespace hpx::parallel {

///////////////////////////////////////////////////////////////////////////
// uninitialized_relocate
namespace detail {
/// \cond NOINTERNAL

///////////////////////////////////////////////////////////////////////

template <typename ExPolicy, typename Iter, typename FwdIter2>
typename util::detail::algorithm_result<ExPolicy,
util::in_out_result<Iter, FwdIter2>>::type
parallel_uninitialized_relocate_n(
ExPolicy&& policy, Iter first, std::size_t count, FwdIter2 dest)
{
if (count == 0)
{
return util::detail::algorithm_result<ExPolicy,
util::in_out_result<Iter, FwdIter2>>::
get(util::in_out_result<Iter, FwdIter2>{first, dest});
}

using zip_iterator = hpx::util::zip_iterator<Iter, FwdIter2>;
using partition_result_type = std::pair<FwdIter2, FwdIter2>;

return util::partitioner_with_cleanup<ExPolicy,
util::in_out_result<Iter, FwdIter2>, partition_result_type>::
call(
HPX_FORWARD(ExPolicy, policy), zip_iterator(first, dest),
count,
[policy](zip_iterator t, std::size_t part_size) mutable
-> partition_result_type {
using hpx::get;

auto iters = t.get_iterator_tuple();

Iter part_source = get<0>(iters);
FwdIter2 part_dest = get<1>(iters);

// returns (dest begin, dest end)
return std::make_pair(part_dest,
util::get_second_element(
hpx::parallel::util::uninit_relocate_n(
HPX_FORWARD(ExPolicy, policy), part_source,
part_size, part_dest)));
},
// finalize, called once if no error occurred
[dest, first, count](auto&& data) mutable
-> util::in_out_result<Iter, FwdIter2> {
// make sure iterators embedded in function object that is
// attached to futures are invalidated
util::detail::clear_container(data);

std::advance(first, count);
std::advance(dest, count);
return util::in_out_result<Iter, FwdIter2>{first, dest};
},
// cleanup function, called for each partition which
// didn't fail, but only if at least one failed
[](partition_result_type&& r) -> void {
std::destroy(r.first, r.second);
});
}

/////////////////////////////////////////////////////////////////////////////
// uninitialized_relocate_n

/// \cond NOINTERNAL
template <typename IterPair>
struct uninitialized_relocate_n
: public algorithm<uninitialized_relocate_n<IterPair>, IterPair>
{
constexpr uninitialized_relocate_n() noexcept
: algorithm<uninitialized_relocate_n, IterPair>(
"uninitialized_relocate_n")
{
}

// non vectorized overload
template <typename ExPolicy, typename InIter, typename FwdIter2,
HPX_CONCEPT_REQUIRES_(
hpx::is_sequenced_execution_policy_v<ExPolicy>)>
static util::in_out_result<InIter, FwdIter2> sequential(
ExPolicy&& policy, InIter first, std::size_t count,
FwdIter2 dest)
{
return hpx::parallel::util::uninit_relocate_n(
HPX_FORWARD(ExPolicy, policy), first, count, dest);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sequential overload takes ExPolicy?

}

template <typename ExPolicy, typename Iter, typename FwdIter2>
static util::detail::algorithm_result_t<ExPolicy,
util::in_out_result<Iter, FwdIter2>>
parallel(
ExPolicy&& policy, Iter first, std::size_t count, FwdIter2 dest)
{
return parallel_uninitialized_relocate_n(
HPX_FORWARD(ExPolicy, policy), first, count, dest);
}
};
/// \endcond

/////////////////////////////////////////////////////////////////////////////
// uninitialized_relocate
/// \cond NOINTERNAL
template <typename IterPair>
struct uninitialized_relocate
: public algorithm<uninitialized_relocate<IterPair>, IterPair>
{
constexpr uninitialized_relocate() noexcept
: algorithm<uninitialized_relocate, IterPair>(
"uninitialized_relocate")
{
}

// non vectorized overload
template <typename ExPolicy, typename InIter, typename FwdIter2,
HPX_CONCEPT_REQUIRES_(
hpx::is_sequenced_execution_policy_v<ExPolicy>)>
static util::in_out_result<InIter, FwdIter2> sequential(
ExPolicy&& policy, InIter first, InIter last, FwdIter2 dest)
{
auto count = std::distance(first, last);

return hpx::parallel::util::uninit_relocate_n(
HPX_FORWARD(ExPolicy, policy), first, count, dest);
}

template <typename ExPolicy, typename InIter, typename FwdIter2>
static util::detail::algorithm_result_t<ExPolicy,
util::in_out_result<InIter, FwdIter2>>
parallel(
ExPolicy&& policy, InIter first, InIter last, FwdIter2 dest)
{
auto count = std::distance(first, last);

return parallel_uninitialized_relocate_n(
HPX_FORWARD(ExPolicy, policy), first, count, dest);
}
};
/// \endcond

} // namespace detail
} // namespace hpx::parallel

namespace hpx {

///////////////////////////////////////////////////////////////////////////
// CPO for hpx::uninitialized_relocate_n
inline constexpr struct uninitialized_relocate_n_t final
: hpx::detail::tag_parallel_algorithm<uninitialized_relocate_n_t>
{
// clang-format off
template <typename InIter, typename Size,
typename FwdIter,
HPX_CONCEPT_REQUIRES_(
hpx::traits::is_iterator_v<InIter> &&
hpx::traits::is_forward_iterator_v<FwdIter> &&
std::is_integral_v<Size>
)>
// clang-format on
friend FwdIter tag_fallback_invoke(hpx::uninitialized_relocate_n_t,
InIter first, Size count,
hkaiser marked this conversation as resolved.
Show resolved Hide resolved
FwdIter dest) noexcept(std::is_same_v<hpx::traits::
pointer_relocate_category<
InIter, FwdIter>,
hpx::traits::
nothrow_relocatable_pointer_tag> ||
std::is_same_v<
hpx::traits::pointer_relocate_category<InIter, FwdIter>,
hpx::traits::trivially_relocatable_pointer_tag>)
{
static_assert(hpx::traits::is_input_iterator_v<InIter>,
"Required at least input iterator.");
static_assert(hpx::traits::is_forward_iterator_v<FwdIter>,
"Requires at least forward iterator.");
static_assert(hpx::traits::pointer_relocate_category<InIter,
FwdIter>::valid_relocation,
"Relocating from this source type to this destination type is "
"ill-formed");

// if count is representing a negative value, we do nothing
if (hpx::parallel::detail::is_negative(count))
{
return dest;
}

return parallel::util::get_second_element(
hpx::parallel::detail::uninitialized_relocate_n<
parallel::util::in_out_result<InIter, FwdIter>>()
.call(hpx::execution::seq, first,
static_cast<std::size_t>(count), dest));
}

// clang-format off
template <typename ExPolicy, typename FwdIter1, typename Size,
typename FwdIter2,
HPX_CONCEPT_REQUIRES_(
hpx::is_execution_policy_v<ExPolicy> &&
hpx::traits::is_forward_iterator_v<FwdIter1> &&
hpx::traits::is_forward_iterator_v<FwdIter2> &&
std::is_integral_v<Size>
)>
friend typename parallel::util::detail::algorithm_result<ExPolicy,
FwdIter2>::type
tag_fallback_invoke(hpx::uninitialized_relocate_n_t, ExPolicy&& policy,
FwdIter1 first, Size count, FwdIter2 dest) noexcept(
std::is_same_v<
hpx::traits::pointer_relocate_category<FwdIter1, FwdIter2>,
hpx::traits::nothrow_relocatable_pointer_tag> ||
std::is_same_v<
hpx::traits::pointer_relocate_category<FwdIter1, FwdIter2>,
hpx::traits::trivially_relocatable_pointer_tag>)
// clang-format on
{
static_assert(hpx::traits::is_forward_iterator_v<FwdIter1>,
"Requires at least forward iterator.");
static_assert(hpx::traits::is_forward_iterator_v<FwdIter2>,
"Requires at least forward iterator.");
static_assert(hpx::traits::pointer_relocate_category<FwdIter1,
FwdIter2>::valid_relocation,
"Relocating from this source type to this destination type is "
"ill-formed");

// if count is representing a negative value, we do nothing
if (hpx::parallel::detail::is_negative(count))
{
return parallel::util::detail::algorithm_result<ExPolicy,
FwdIter2>::get(HPX_MOVE(dest));
}

return parallel::util::get_second_element(
hpx::parallel::detail::uninitialized_relocate_n<
parallel::util::in_out_result<FwdIter1, FwdIter2>>()
.call(HPX_FORWARD(ExPolicy, policy), first,
static_cast<std::size_t>(count), dest));
}
} uninitialized_relocate_n{};
} // namespace hpx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need an empty line at the EOF.

Loading