-
-
Notifications
You must be signed in to change notification settings - Fork 542
update relocation definitions to track p2786r13 standard #6869
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
base: master
Are you sure you want to change the base?
Changes from 7 commits
3840ea4
a5585d2
df80f76
37063e4
9d857b6
657e7f7
2e6decb
6e33bff
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // Copyright (c) 2025 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/config.hpp> | ||
|
|
||
| #include <cstddef> | ||
| #include <type_traits> | ||
|
|
||
| #include <hpx/type_support/is_trivially_relocatable.hpp> | ||
|
|
||
| namespace hpx::experimental { | ||
|
|
||
| // P2786R13 defines a single feature-test macro __cpp_trivial_relocatability | ||
| // that covers both the core-language keyword and the associated library traits | ||
| // (std::is_trivially_relocatable, std::is_replaceable, std::relocate_at). | ||
| // The language and library features are bundled in one proposal, so guarding on | ||
| // this macro is sufficient to confirm that std::is_replaceable is available. | ||
| #if defined(__cpp_trivial_relocatability) | ||
|
guptapratykshh marked this conversation as resolved.
Outdated
|
||
| HPX_CXX_CORE_EXPORT template <typename T> | ||
| struct is_replaceable : std::is_replaceable<T> | ||
| { | ||
| }; | ||
|
guptapratykshh marked this conversation as resolved.
Outdated
|
||
| #else | ||
| HPX_CXX_CORE_EXPORT template <typename T> | ||
| struct is_replaceable | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A type is replaceable if what you get from move constructing is the same you get from move assigning. T move_assigned = some_t();
T move_constructed(std::move(existing)); // 1
move_assigned = std::move(existing); // 2You want Replaceable is an opt-in trait, you might want to take a look at how we deal with such traits in the Take a look at this paper to learn more about how to detect replaceability.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are array types not replaceable?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. arrays are not replaceable because they are not assignable types. while arrays are objects, they do not support move assignment (std::is_trivially_move_assignable_v<T[]> is false), which is core requirement for replaceability according to P2786R13. the explicit specialisations make this exclusion clear and match the expected behavior shown in the test assertions at lines 35-36. |
||
| : std::bool_constant<std::is_object_v<T> && !std::is_const_v<T> && | ||
| !std::is_volatile_v<T> && | ||
| (std::is_scalar_v<T> || | ||
| ((std::is_class_v<T> || std::is_union_v<T>) && | ||
| std::is_trivially_move_constructible_v<T> && | ||
| std::is_trivially_move_assignable_v<T> && | ||
| std::is_trivially_destructible_v<T>) )> | ||
| { | ||
| }; | ||
|
|
||
| HPX_CXX_CORE_EXPORT template <typename T> | ||
| struct is_replaceable<T[]> : std::false_type | ||
| { | ||
| }; | ||
|
|
||
| HPX_CXX_CORE_EXPORT template <typename T, std::size_t N> | ||
| struct is_replaceable<T[N]> : std::false_type | ||
| { | ||
| }; | ||
| #endif | ||
|
|
||
| HPX_CXX_CORE_EXPORT template <typename T> | ||
| inline constexpr bool is_replaceable_v = is_replaceable<T>::value; | ||
|
|
||
| } // namespace hpx::experimental | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,19 @@ | |
|
|
||
| namespace hpx::experimental { | ||
|
|
||
| // P2786R13 defines a single feature-test macro __cpp_trivial_relocatability | ||
| // that covers both the core-language keyword and the associated library traits | ||
| // (std::is_trivially_relocatable, std::is_replaceable, std::relocate_at). | ||
| // The language and library features are bundled in one proposal, so guarding on | ||
| // this macro is sufficient to confirm that std::is_trivially_relocatable is | ||
| // available. | ||
| #if defined(__cpp_trivial_relocatability) | ||
|
guptapratykshh marked this conversation as resolved.
Outdated
|
||
| template <typename T> | ||
| struct is_trivially_relocatable : std::is_trivially_relocatable<T> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should also be added to the replacabillity definition
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this feature test macro should also be updated |
||
| { | ||
| }; | ||
| #else | ||
|
guptapratykshh marked this conversation as resolved.
Outdated
|
||
|
|
||
| // All trivially copyable types are trivially relocatable | ||
| // Other types should default to false. | ||
| HPX_CXX_CORE_EXPORT template <typename T> | ||
|
|
@@ -74,6 +87,8 @@ namespace hpx::experimental { | |
| { | ||
| }; | ||
|
|
||
| #endif | ||
|
|
||
| HPX_CXX_CORE_EXPORT template <typename T> | ||
| inline constexpr bool is_trivially_relocatable_v = | ||
| is_trivially_relocatable<T>::value; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| // Copyright (c) 2026 Pratyksh Gupta | ||
| // | ||
| // 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 <hpx/type_support/is_replaceable.hpp> | ||
|
guptapratykshh marked this conversation as resolved.
Outdated
|
||
|
|
||
| #include <cassert> | ||
| #include <memory> | ||
| #include <mutex> | ||
| #include <type_traits> | ||
|
|
||
| using hpx::experimental::is_replaceable; | ||
| using hpx::experimental::is_replaceable_v; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Those tests should be updated in accordance with the changes in the implementation of the replacabillity trait. |
||
|
|
||
| // Integral types are replaceable (trivially relocatable) | ||
| static_assert(is_replaceable_v<int>); | ||
| // Const types are not assignable (thus not replaceable) | ||
| static_assert(!is_replaceable_v<int const>); | ||
|
|
||
| // Pointer types are replaceable if they are not const-qualified themselves. | ||
| static_assert(is_replaceable_v<int*>); | ||
| static_assert(is_replaceable_v<int const*>); | ||
|
|
||
| // Pointers follow the same rules as other objects. A pointer is replaceable only | ||
| // if it is not const-qualified itself, as replacement requires assignment. | ||
| // P2786R13 Section 3.2: "const-qualified objects are never replaceable." | ||
| static_assert(!is_replaceable_v<int* const>); | ||
|
|
||
| // Function pointers are replaceable | ||
| static_assert(is_replaceable_v<int (*)()>); | ||
|
|
||
| // Arrays are not assignable | ||
| static_assert(!is_replaceable_v<int[]>); | ||
| static_assert(!is_replaceable_v<int[4]>); | ||
|
|
||
| // References are not objects | ||
| static_assert(!is_replaceable_v<int&>); | ||
| static_assert(!is_replaceable_v<int&&>); | ||
|
|
||
| // Void types | ||
| static_assert(!is_replaceable_v<void>); | ||
|
|
||
| // std::mutex is not move assignable, nor trivially relocatable | ||
| static_assert(!is_replaceable_v<std::mutex>); | ||
|
|
||
| struct trivial_class | ||
| { | ||
| int x; | ||
| }; | ||
| static_assert(is_replaceable_v<trivial_class>); | ||
|
|
||
| // Replaceability implies a type can be destroyed and reconstructed. | ||
| // Consequently, a type must be destructible to be replaceable. | ||
| // Per P2786R13, implicit replaceability also requires trivial relocatability, | ||
| // which in turn requires trivial destructibility. | ||
| struct not_destructible | ||
| { | ||
| not_destructible(not_destructible&&); | ||
| ~not_destructible() = delete; | ||
| }; | ||
| static_assert(!is_replaceable_v<not_destructible>); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is destructibility a requirement of replaceability?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, implicit replaceability requires trivial relocatability, which requires trivial destructibility |
||
|
|
||
| struct not_move_assignable | ||
| { | ||
| not_move_assignable& operator=(not_move_assignable&&) = delete; | ||
| }; | ||
| static_assert(!is_replaceable_v<not_move_assignable>); | ||
|
|
||
| struct not_move_constructible | ||
| { | ||
| not_move_constructible(not_move_constructible&&) = delete; | ||
| not_move_constructible& operator=(not_move_constructible&&); | ||
| }; | ||
| static_assert(!is_replaceable_v<not_move_constructible>); | ||
|
|
||
| struct move_assignable_but_not_implicitly_replaceable | ||
| { | ||
| std::unique_ptr<int> p; | ||
| move_assignable_but_not_implicitly_replaceable( | ||
| move_assignable_but_not_implicitly_replaceable&&) = default; | ||
| move_assignable_but_not_implicitly_replaceable& operator=( | ||
| move_assignable_but_not_implicitly_replaceable&&) = default; | ||
| }; | ||
| static_assert( | ||
| !is_replaceable_v<move_assignable_but_not_implicitly_replaceable>); | ||
|
|
||
| // Opt-in example | ||
| struct opt_in_replaceable | ||
| { | ||
| std::unique_ptr<int> p; | ||
| opt_in_replaceable(opt_in_replaceable&&) = default; | ||
| opt_in_replaceable& operator=(opt_in_replaceable&&) = default; | ||
| }; | ||
|
|
||
| // Specialize is_replaceable for opt_in_replaceable | ||
| namespace hpx::experimental { | ||
| template <> | ||
| struct is_replaceable<opt_in_replaceable> : std::true_type | ||
| { | ||
| }; | ||
| } // namespace hpx::experimental | ||
|
|
||
| static_assert(is_replaceable_v<opt_in_replaceable>); | ||
|
|
||
| // volatile types are not replaceable because their state is unstable and | ||
| // bitwise move-assignment (replacement) cannot guarantee preservation of | ||
| // their specific access semantics. | ||
| static_assert(!is_replaceable_v<int volatile>); | ||
| static_assert(is_replaceable_v<int volatile*>); // pointer to volatile is OK | ||
| static_assert(!is_replaceable_v<int* volatile>); // volatile pointer is not | ||
|
|
||
| struct has_const_member | ||
| { | ||
| int const x; | ||
| }; | ||
| // move assignment is deleted for classes with const members | ||
| static_assert(!is_replaceable_v<has_const_member>); | ||
|
|
||
| struct has_volatile_member | ||
| { | ||
| int volatile x; | ||
| }; | ||
| // volatile members do not necessarily make move assignment non-trivial | ||
| static_assert(is_replaceable_v<has_volatile_member>); | ||
|
|
||
| int main() {} | ||
Uh oh!
There was an error while loading. Please reload this page.