diff --git a/indirect.h b/indirect.h index 63618784..f16ec572 100644 --- a/indirect.h +++ b/indirect.h @@ -44,6 +44,16 @@ namespace xyz { } #endif // XYZ_UNREACHABLE_DEFINED +#ifndef XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED +#define XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED +#if defined(__cpp_impl_trivially_relocatable) && \ + defined(__cpp_lib_trivially_relocatable) +#define XYZ_TRIVIALLY_RELOCATABLE_IF(x) [[trivially_relocatable(x)]] +#else +#define XYZ_TRIVIALLY_RELOCATABLE_IF(x) +#endif +#endif // XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED + template class indirect; @@ -53,8 +63,25 @@ inline constexpr bool is_indirect_v = false; template inline constexpr bool is_indirect_v> = true; +#if defined(__cpp_lib_trivially_relocatable) +template +inline constexpr bool indirect_allocator_pocma_models_relocatable_v = + std::allocator_traits::is_always_equal::value || + (std::allocator_traits::propagate_on_container_copy_assignment::value && + std::allocator_traits::propagate_on_container_move_assignment::value && + std::allocator_traits::propagate_on_container_swap::value); + +template +inline constexpr bool indirect_be_trivially_relocatable_v = + std::is_trivially_relocatable_v && + std::is_trivially_relocatable_v< + typename std::allocator_traits::pointer> && + indirect_allocator_pocma_models_relocatable_v; +#endif + template > -class indirect { +class XYZ_TRIVIALLY_RELOCATABLE_IF( + indirect_be_trivially_relocatable_v) indirect { using allocator_traits = std::allocator_traits; public: diff --git a/indirect_test.cc b/indirect_test.cc index fbaf2398..14ae334f 100644 --- a/indirect_test.cc +++ b/indirect_test.cc @@ -42,6 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #endif // XYZ_HAS_STD_OPTIONAL #include +#include #include #include #include @@ -54,6 +55,17 @@ using std::in_place_t; namespace { +TEST(IndirectTest, TriviallyRelocatable) { +#if defined(__cpp_impl_trivially_relocatable) && \ + defined(__cpp_lib_trivially_relocatable) + static_assert(std::is_trivially_relocatable_v>); +#ifdef XYZ_HAS_STD_MEMORY_RESOURCE + static_assert(!std::is_trivially_relocatable_v< + xyz::indirect>>); +#endif +#endif // defined(__cpp_impl_trivially_relocatable) && ... +} + TEST(IndirectTest, DefaultConstructor) { xyz::indirect i; EXPECT_EQ(*i, 0); diff --git a/polymorphic.h b/polymorphic.h index e8354d80..fed74e92 100644 --- a/polymorphic.h +++ b/polymorphic.h @@ -46,6 +46,16 @@ namespace xyz { } #endif // XYZ_UNREACHABLE_DEFINED +#ifndef XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED +#define XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED +#if defined(__cpp_impl_trivially_relocatable) && \ + defined(__cpp_lib_trivially_relocatable) +#define XYZ_TRIVIALLY_RELOCATABLE_IF(x) [[trivially_relocatable(x)]] +#else +#define XYZ_TRIVIALLY_RELOCATABLE_IF(x) +#endif +#endif // XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED + namespace detail { template struct control_block { @@ -117,8 +127,24 @@ class direct_control_block final : public control_block { } // namespace detail +#if defined(__cpp_lib_trivially_relocatable) +template +inline constexpr bool polymorphic_allocator_pocma_models_relocatable_v = + std::allocator_traits::is_always_equal::value || + (std::allocator_traits::propagate_on_container_copy_assignment::value && + std::allocator_traits::propagate_on_container_move_assignment::value && + std::allocator_traits::propagate_on_container_swap::value); + +template +inline constexpr bool polymorphic_be_trivially_relocatable_v = + std::is_trivially_relocatable_v && + std::is_trivially_relocatable_v*> && + polymorphic_allocator_pocma_models_relocatable_v; +#endif + template > -class polymorphic { +class XYZ_TRIVIALLY_RELOCATABLE_IF( + (polymorphic_be_trivially_relocatable_v)) polymorphic { using cblock_t = detail::control_block; cblock_t* cb_; diff --git a/polymorphic_cxx14.h b/polymorphic_cxx14.h index 444bcb30..02c0cf1c 100644 --- a/polymorphic_cxx14.h +++ b/polymorphic_cxx14.h @@ -54,6 +54,16 @@ namespace xyz { } // namespace xyz #endif // XYZ_UNREACHABLE_DEFINED +#ifndef XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED +#define XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED +#if defined(__cpp_impl_trivially_relocatable) && \ + defined(__cpp_lib_trivially_relocatable) +#define XYZ_TRIVIALLY_RELOCATABLE_IF(x) [[trivially_relocatable(x)]] +#else +#define XYZ_TRIVIALLY_RELOCATABLE_IF(x) +#endif +#endif // XYZ_TRIVIALLY_RELOCATABLE_IF_DEFINED + #ifndef XYZ_EMPTY_BASE_DEFINED #define XYZ_EMPTY_BASE_DEFINED // This is a helper class to allow empty base class optimization. @@ -157,8 +167,33 @@ class direct_control_block final : public control_block { } // namespace detail +#if defined(__cpp_lib_trivially_relocatable) +template +struct polymorphic_allocator_pocma_models_relocatable + : std::integral_constant< + bool, + std::allocator_traits::is_always_equal::value || + (std::allocator_traits< + A>::propagate_on_container_copy_assignment::value && + std::allocator_traits< + A>::propagate_on_container_move_assignment::value && + std::allocator_traits::propagate_on_container_swap::value)> { +}; + +template +struct polymorphic_be_trivially_relocatable + : std::integral_constant< + bool, std::is_trivially_relocatable::value && + std::is_trivially_relocatable< + detail::control_block*>::value && + polymorphic_allocator_pocma_models_relocatable::value> { +}; +#endif + template > -class polymorphic : private detail::empty_base_optimization { +class XYZ_TRIVIALLY_RELOCATABLE_IF( + (polymorphic_be_trivially_relocatable::value)) polymorphic + : private detail::empty_base_optimization { using cblock_t = detail::control_block; cblock_t* cb_; diff --git a/polymorphic_test.cc b/polymorphic_test.cc index f304440b..847e8c3b 100644 --- a/polymorphic_test.cc +++ b/polymorphic_test.cc @@ -56,6 +56,7 @@ using std::in_place_type_t; #ifdef XYZ_HAS_STD_OPTIONAL #include #endif // XYZ_HAS_STD_OPTIONAL +#include #include #include #include @@ -216,6 +217,18 @@ TEST(PolymorphicTest, SwapWithNoSBOAndSBO) { EXPECT_EQ(b->value(), 42); } +TEST(PolymorphicTest, TriviallyRelocatable) { +#if defined(__cpp_impl_trivially_relocatable) && \ + defined(__cpp_lib_trivially_relocatable) + static_assert(std::is_trivially_relocatable>::value, + ""); +#ifdef XYZ_HAS_STD_MEMORY_RESOURCE + static_assert(!std::is_trivially_relocatable_v< + xyz::polymorphic>>); +#endif +#endif // defined(__cpp_impl_trivially_relocatable) && ... +} + TEST(PolymorphicTest, AccessDerivedObject) { xyz::polymorphic a(xyz::in_place_type_t{}, 42); EXPECT_EQ(a->value(), 42);