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

P1144 Relocation primitives #6324

Merged
merged 44 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
115ac17
similar type detection
isidorostsa Aug 18, 2023
c58ad81
is_relocatable_from
isidorostsa Aug 18, 2023
aba288b
relocate_at algorithm
isidorostsa Aug 18, 2023
21d9722
uninitialized_relocate algorithm
isidorostsa Aug 18, 2023
d9dfe22
tests
isidorostsa Aug 18, 2023
b556c02
remove commented code
isidorostsa Aug 18, 2023
dda8519
reject failing destroy_at types
isidorostsa Aug 18, 2023
0411137
move to namespace experimental
isidorostsa Aug 18, 2023
b2951d3
make relocate's format like relocate_at
isidorostsa Aug 19, 2023
aa09ce4
relocate test
isidorostsa Aug 19, 2023
2b55ebf
clang-format and comments
isidorostsa Aug 19, 2023
57d4264
remove whitespaces for inspect
isidorostsa Aug 19, 2023
799fc3d
fix fail test
isidorostsa Aug 23, 2023
b80f7b9
& and && are nor triv. rel.
isidorostsa Aug 23, 2023
d789470
unneeded void cast
isidorostsa Aug 23, 2023
8d218e5
addition to a test
isidorostsa Aug 23, 2023
f1e142e
only objects are relocatable
isidorostsa Aug 23, 2023
3801e8b
comment correction
isidorostsa Aug 23, 2023
3261583
clang-format
isidorostsa Aug 23, 2023
3a5d8d2
template arg name size -> N
isidorostsa Aug 23, 2023
bf1a01a
decay -> remove_cv
isidorostsa Aug 24, 2023
1c09732
similar type detection
isidorostsa Aug 18, 2023
168aad6
is_relocatable_from
isidorostsa Aug 18, 2023
9dff12a
relocate_at algorithm
isidorostsa Aug 18, 2023
d4a3a4a
uninitialized_relocate algorithm
isidorostsa Aug 18, 2023
e0449d5
tests
isidorostsa Aug 18, 2023
0b14f6f
remove commented code
isidorostsa Aug 18, 2023
5b96c29
reject failing destroy_at types
isidorostsa Aug 18, 2023
8fecec0
move to namespace experimental
isidorostsa Aug 18, 2023
6c58314
make relocate's format like relocate_at
isidorostsa Aug 19, 2023
0334457
relocate test
isidorostsa Aug 19, 2023
3797e55
clang-format and comments
isidorostsa Aug 19, 2023
b940642
remove whitespaces for inspect
isidorostsa Aug 19, 2023
639f7fe
fix fail test
isidorostsa Aug 23, 2023
9f73777
& and && are nor triv. rel.
isidorostsa Aug 23, 2023
e30dc0e
unneeded void cast
isidorostsa Aug 23, 2023
a33c1bd
addition to a test
isidorostsa Aug 23, 2023
445d779
only objects are relocatable
isidorostsa Aug 23, 2023
7378834
comment correction
isidorostsa Aug 23, 2023
00aed1c
clang-format
isidorostsa Aug 23, 2023
6e78171
template arg name size -> N
isidorostsa Aug 23, 2023
af1f6f6
decay -> remove_cv
isidorostsa Aug 24, 2023
ea53ac9
Merge branch 'relocate_primitives' of github.com:isidorostsa/hpx_fork…
isidorostsa Aug 28, 2023
9a4c2d7
More fixes for CMake V3.27
hkaiser Aug 24, 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
24 changes: 12 additions & 12 deletions cmake/FindJemalloc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ find_path(
ENV
JEMALLOC_ROOT
${HPX_JEMALLOC_ROOT}
${PC_JEMALLOC_MINIMAL_INCLUDEDIR}
${PC_JEMALLOC_MINIMAL_INCLUDE_DIRS}
${PC_JEMALLOC_INCLUDEDIR}
${PC_JEMALLOC_INCLUDE_DIRS}
${PC_Jemalloc_MINIMAL_INCLUDEDIR}
${PC_Jemalloc_MINIMAL_INCLUDE_DIRS}
${PC_Jemalloc_INCLUDEDIR}
${PC_Jemalloc_INCLUDE_DIRS}
PATH_SUFFIXES include
)

Expand All @@ -32,10 +32,10 @@ if(MSVC)
ENV
JEMALLOC_ROOT
${HPX_JEMALLOC_ROOT}
${PC_JEMALLOC_MINIMAL_INCLUDEDIR}
${PC_JEMALLOC_MINIMAL_INCLUDE_DIRS}
${PC_JEMALLOC_INCLUDEDIR}
${PC_JEMALLOC_INCLUDE_DIRS}
${PC_Jemalloc_MINIMAL_INCLUDEDIR}
${PC_Jemalloc_MINIMAL_INCLUDE_DIRS}
${PC_Jemalloc_INCLUDEDIR}
${PC_Jemalloc_INCLUDE_DIRS}
PATH_SUFFIXES include
)
endif()
Expand All @@ -58,10 +58,10 @@ find_library(
ENV
JEMALLOC_ROOT
${HPX_JEMALLOC_ROOT}
${PC_JEMALLOC_MINIMAL_LIBDIR}
${PC_JEMALLOC_MINIMAL_LIBRARY_DIRS}
${PC_JEMALLOC_LIBDIR}
${PC_JEMALLOC_LIBRARY_DIRS}
${PC_Jemalloc_MINIMAL_LIBDIR}
${PC_Jemalloc_MINIMAL_LIBRARY_DIRS}
${PC_Jemalloc_LIBDIR}
${PC_Jemalloc_LIBRARY_DIRS}
PATH_SUFFIXES lib lib64
)

Expand Down
2 changes: 2 additions & 0 deletions libs/core/type_support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ set(type_support_headers
hpx/type_support/lazy_enable_if.hpp
hpx/type_support/pack.hpp
hpx/type_support/meta.hpp
hpx/type_support/relocate_at.hpp
hpx/type_support/static.hpp
hpx/type_support/uninitialized_relocate.hpp
hpx/type_support/unwrap_ref.hpp
hpx/type_support/unused.hpp
hpx/type_support/void_guard.hpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,25 @@
namespace hpx {

template <typename T>
struct is_relocatable : std::is_move_constructible<T>
struct is_relocatable
: std::bool_constant<std::is_move_constructible_v<T> &&
std::is_object_v<T>>
{
};

// ToTp(FromTp&&) must be well-formed
template <typename ToTp, typename FromTp>
struct is_relocatable_from
: std::bool_constant<
std::is_constructible_v<std::remove_cv_t<ToTp>, FromTp> &&
std::is_same_v<std::remove_cv_t<ToTp>, std::remove_cv_t<FromTp>>>
{
};

template <typename T>
inline constexpr bool is_relocatable_v = is_relocatable<T>::value;

template <typename ToTp, typename FromTp>
inline constexpr bool is_relocatable_from_v =
is_relocatable_from<ToTp, FromTp>::value;
} // namespace hpx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,61 @@ namespace hpx {
{
};

// References are not trivially relocatable
template <typename T>
struct is_trivially_relocatable<T&> : std::false_type
{
};

// Temporary objects are not trivially relocatable
template <typename T>
struct is_trivially_relocatable<T&&> : std::false_type
{
};

// Constness, Volatility, Arrays are ignored
template <typename T>
struct is_trivially_relocatable<T const> : is_trivially_relocatable<T>
{
};

template <typename T>
struct is_trivially_relocatable<T volatile> : is_trivially_relocatable<T>
{
};

template <typename T>
struct is_trivially_relocatable<T const volatile>
: is_trivially_relocatable<T>
{
};

template <typename T>
struct is_trivially_relocatable<T[]> : is_trivially_relocatable<T>
{
};

template <typename T, int N>
struct is_trivially_relocatable<T[N]> : is_trivially_relocatable<T>
{
};

template <typename T, int N>
struct is_trivially_relocatable<T const[N]> : is_trivially_relocatable<T>
{
};

template <typename T, int N>
struct is_trivially_relocatable<T volatile[N]> : is_trivially_relocatable<T>
{
};

template <typename T, int N>
struct is_trivially_relocatable<T const volatile[N]>
: is_trivially_relocatable<T>
{
};

template <typename T>
inline constexpr bool is_trivially_relocatable_v =
is_trivially_relocatable<T>::value;
Expand Down
146 changes: 146 additions & 0 deletions libs/core/type_support/include/hpx/type_support/relocate_at.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// Copyright (c) 2023 Isidoros Tsaousis-Seiras
//
// 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 <hpx/concepts/concepts.hpp>
#include <hpx/type_support/construct_at.hpp>
#include <hpx/type_support/is_relocatable.hpp>
#include <hpx/type_support/is_trivially_relocatable.hpp>

#include <cstring>
#include <type_traits>

#if defined(HPX_HAVE_P1144_STD_RELOCATE_AT)
#include <memory>
#endif

namespace hpx::detail {
#if __cplusplus < 202002L
// until c++20 std::destroy_at can be used only on non-array types
template <typename T,
HPX_CONCEPT_REQUIRES_(std::is_destructible_v<T> && !std::is_array_v<T>)>
#else
// since c++20 std::destroy_at can be used on array types, destructing each element
template <typename T, HPX_CONCEPT_REQUIRES_(std::is_destructible_v<T>)>
#endif
struct destroy_guard
{
T* t;
explicit destroy_guard(T* t)
: t(t)
{
}
~destroy_guard()
{
std::destroy_at(t);
}
};
} // namespace hpx::detail

#if defined(HPX_HAVE_P1144_STD_RELOCATE_AT)
using std::relocate;
using std::relocate_at;
#else

namespace hpx::experimental {

namespace detail {

/*
The condition to use memmove is:
hpx::is_trivially_relocatable_v<T> &&
!std::is_volatile_v<T>

The reason for the volatile check is that memmove is not allowed to
change the value of a volatile object.
*/

template <typename T>
constexpr bool relocate_using_memmove =
hpx::is_trivially_relocatable_v<T> && !std::is_volatile_v<T>;

template <typename T,
std::enable_if_t<relocate_using_memmove<T>, int> = 0>
T* relocate_at_helper(T* src, T* dst) noexcept
{
void* dst_void = const_cast<void*>(static_cast<const void*>(dst));
void* src_void = const_cast<void*>(static_cast<const void*>(src));

std::memmove(dst_void, src_void, sizeof(T));

return std::launder(dst);
};

// this is move and destroy
template <typename T,
std::enable_if_t<!relocate_using_memmove<T>, int> = 0>
T* relocate_at_helper(T* src, T* dst) noexcept(
std::is_nothrow_move_constructible_v<T>)
{
hpx::detail::destroy_guard g(src);
return hpx::construct_at(dst, HPX_MOVE(*src));
};

template <typename T>
T relocate_helper(T* src) noexcept(
std::is_nothrow_move_constructible_v<T>)
{
hpx::detail::destroy_guard g(src);
return HPX_MOVE(*src);
}

/*
P1144 also proposes a version of relocate that does not call the
move constructor and instead memmoves the bytes of src to dest.

Giving an interface like:

T dest = relocate(std::addressof(src));

That results in a valid T object (dest) without calling any
constructor or destructor.

This is not possible to do with the current C++ standard.

One of the proposed ways to implement this uses a hypothetical
attribute "do_not_construct" and NRVO.

Implementation:

template <class T, std::enable_if_t<relocate_using_memmove<T>, int> = 0>
T relocate(T* source)
{
__attribute__((do_not_construct)) T t; // hypothetical attribute
std::memmove(std::addressof(t), source, sizeof(T));
return t; // NRVO
}
*/
} // namespace detail

template <typename T>
T* relocate_at(T* src, T* dst) noexcept(
// noexcept if the memmove path is taken or if the move path is noexcept
noexcept(detail::relocate_at_helper(src, dst)))
{
static_assert(hpx::is_relocatable_v<T>,
"new (dst) T(std::move(*src)) must be well-formed");

return detail::relocate_at_helper(src, dst);
}

template <typename T>
T relocate(T* src) noexcept(noexcept(detail::relocate_helper(src)))
{
static_assert(
hpx::is_relocatable_v<T>, "T(std::move(*src)) must be well-formed");

return detail::relocate_helper(src);
}

#endif // !defined(HPX_HAVE_P1144_STD_RELOCATE_AT)

} // namespace hpx::experimental
Loading