Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 28 additions & 1 deletion indirect.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 T, class A>
class indirect;

Expand All @@ -53,8 +63,25 @@ inline constexpr bool is_indirect_v = false;
template <class T, class A>
inline constexpr bool is_indirect_v<indirect<T, A>> = true;

#if defined(__cpp_lib_trivially_relocatable)
template <class A>
inline constexpr bool indirect_allocator_pocma_models_relocatable_v =
std::allocator_traits<A>::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<A>::propagate_on_container_swap::value);

template <class A>
inline constexpr bool indirect_be_trivially_relocatable_v =
std::is_trivially_relocatable_v<A> &&
std::is_trivially_relocatable_v<
typename std::allocator_traits<A>::pointer> &&
indirect_allocator_pocma_models_relocatable_v<A>;
#endif

template <class T, class A = std::allocator<T>>
class indirect {
class XYZ_TRIVIALLY_RELOCATABLE_IF(
indirect_be_trivially_relocatable_v<A>) indirect {
using allocator_traits = std::allocator_traits<A>;

public:
Expand Down
12 changes: 12 additions & 0 deletions indirect_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <optional>
#endif // XYZ_HAS_STD_OPTIONAL
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
Expand All @@ -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<xyz::indirect<int>>);
#ifdef XYZ_HAS_STD_MEMORY_RESOURCE
static_assert(!std::is_trivially_relocatable_v<
xyz::indirect<int, std::pmr::polymorphic_allocator<int>>>);
#endif
#endif // defined(__cpp_impl_trivially_relocatable) && ...
}

TEST(IndirectTest, DefaultConstructor) {
xyz::indirect<int> i;
EXPECT_EQ(*i, 0);
Expand Down
28 changes: 27 additions & 1 deletion polymorphic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class T, class A>
struct control_block {
Expand Down Expand Up @@ -117,8 +127,24 @@ class direct_control_block final : public control_block<T, A> {

} // namespace detail

#if defined(__cpp_lib_trivially_relocatable)
template <class A>
inline constexpr bool polymorphic_allocator_pocma_models_relocatable_v =
std::allocator_traits<A>::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<A>::propagate_on_container_swap::value);

template <class T, class A>
inline constexpr bool polymorphic_be_trivially_relocatable_v =
std::is_trivially_relocatable_v<A> &&
std::is_trivially_relocatable_v<detail::control_block<T, A>*> &&
polymorphic_allocator_pocma_models_relocatable_v<A>;
#endif

template <class T, class A = std::allocator<T>>
class polymorphic {
class XYZ_TRIVIALLY_RELOCATABLE_IF(
(polymorphic_be_trivially_relocatable_v<T, A>)) polymorphic {
using cblock_t = detail::control_block<T, A>;
cblock_t* cb_;

Expand Down
37 changes: 36 additions & 1 deletion polymorphic_cxx14.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -157,8 +167,33 @@ class direct_control_block final : public control_block<T, A> {

} // namespace detail

#if defined(__cpp_lib_trivially_relocatable)
template <class A>
struct polymorphic_allocator_pocma_models_relocatable
: std::integral_constant<
bool,
std::allocator_traits<A>::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<A>::propagate_on_container_swap::value)> {
};

template <class T, class A>
struct polymorphic_be_trivially_relocatable
: std::integral_constant<
bool, std::is_trivially_relocatable<A>::value &&
std::is_trivially_relocatable<
detail::control_block<T, A>*>::value &&
polymorphic_allocator_pocma_models_relocatable<A>::value> {
};
#endif

template <class T, class A = std::allocator<T>>
class polymorphic : private detail::empty_base_optimization<A> {
class XYZ_TRIVIALLY_RELOCATABLE_IF(
(polymorphic_be_trivially_relocatable<T, A>::value)) polymorphic
: private detail::empty_base_optimization<A> {
using cblock_t = detail::control_block<T, A>;
cblock_t* cb_;

Expand Down
13 changes: 13 additions & 0 deletions polymorphic_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ using std::in_place_type_t;
#ifdef XYZ_HAS_STD_OPTIONAL
#include <optional>
#endif // XYZ_HAS_STD_OPTIONAL
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -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<xyz::polymorphic<int>>::value,
"");
#ifdef XYZ_HAS_STD_MEMORY_RESOURCE
static_assert(!std::is_trivially_relocatable_v<
xyz::polymorphic<int, std::pmr::polymorphic_allocator<int>>>);
#endif
#endif // defined(__cpp_impl_trivially_relocatable) && ...
}

TEST(PolymorphicTest, AccessDerivedObject) {
xyz::polymorphic<Base> a(xyz::in_place_type_t<Derived>{}, 42);
EXPECT_EQ(a->value(), 42);
Expand Down