diff --git a/BUILD.bazel b/BUILD.bazel index 9e4656de..00dec1a6 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -13,6 +13,7 @@ cc_library( srcs = ["indirect.cc"], hdrs = ["indirect.h"], copts = ["-Iexternal/value_types/"], + defines = ["XYZ_HAS_EXTENSION_MAKE_INDIRECT"], visibility = ["//visibility:public"], deps = ["feature_check"], ) @@ -91,6 +92,7 @@ cc_library( srcs = ["polymorphic.cc"], hdrs = ["polymorphic.h"], copts = ["-Iexternal/value_types/"], + defines = ["XYZ_HAS_EXTENSION_MAKE_POLYMORPHIC"], visibility = ["//visibility:public"], ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ea6f117..a241e3cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ target_sources(xyz_value_types xyz_add_library( NAME indirect ALIAS xyz_value_types::indirect + DEFINITIONS XYZ_HAS_EXTENSION_MAKE_INDIRECT ) target_sources(indirect INTERFACE @@ -75,6 +76,7 @@ target_sources(indirect_cxx17 xyz_add_library( NAME polymorphic ALIAS xyz_value_types::polymorphic + DEFINITIONS XYZ_HAS_EXTENSION_MAKE_POLYMORPHIC ) target_sources(polymorphic INTERFACE diff --git a/indirect.h b/indirect.h index 3ff9df0d..22dd7cd3 100644 --- a/indirect.h +++ b/indirect.h @@ -463,6 +463,18 @@ template indirect(std::allocator_arg_t, Alloc, Value) -> indirect< Value, typename std::allocator_traits::template rebind_alloc>; +#ifdef XYZ_HAS_EXTENSION_MAKE_INDIRECT +template +auto make_indirect(Us&&... us) -> indirect { + return indirect(std::in_place, std::forward(us)...); +} + +template +auto allocate_indirect(const A& a, Us&&... us) -> indirect { + return indirect(std::allocator_arg, a, std::in_place, + std::forward(us)...); +} +#endif // XYZ_HAS_EXTENSION_MAKE_INDIRECT } // namespace xyz template diff --git a/indirect_test.cc b/indirect_test.cc index 9d9b99d3..8a2384cb 100644 --- a/indirect_test.cc +++ b/indirect_test.cc @@ -1015,8 +1015,6 @@ TEST(IndirectTest, SupportNonCopyableType) { EXPECT_TRUE(a.valueless_after_move()); } -} // namespace - struct NonThreeWayComparable { int x_; @@ -1052,3 +1050,30 @@ TEST(IndirectTest, NonThreeWayComparable) { EXPECT_TRUE(i != ii); } #endif // XYZ_HAS_STD_THREE_WAY_COMPARISON + +#ifdef XYZ_HAS_EXTENSION_MAKE_INDIRECT +TEST(IndirectTest, MakeIndirectNoArgs) { + auto i = xyz::make_indirect(); + EXPECT_EQ(*i, 0); +} + +TEST(IndirectTest, MakeIndirect) { + auto i = xyz::make_indirect(42); + EXPECT_EQ(*i, 42); +} + +TEST(IndirectTest, AllocateIndirectNoArgs) { + auto a = xyz::TaggedAllocator(1); + auto i = xyz::allocate_indirect(a); + EXPECT_EQ(*i, 0); + EXPECT_EQ(i.get_allocator().tag, 1); +} + +TEST(IndirectTest, AllocateIndirect) { + auto a = xyz::TaggedAllocator(1); + auto i = xyz::allocate_indirect(a, 42); + EXPECT_EQ(*i, 42); + EXPECT_EQ(i.get_allocator().tag, 1); +} +#endif // XYZ_HAS_EXTENSION_MAKE_INDIRECT +} // namespace diff --git a/polymorphic.h b/polymorphic.h index 5b2c6b4c..5510b62a 100644 --- a/polymorphic.h +++ b/polymorphic.h @@ -403,8 +403,20 @@ class polymorphic { cb_ = nullptr; } } -}; // namespace xyz +}; + +#ifdef XYZ_HAS_EXTENSION_MAKE_POLYMORPHIC +template +auto make_polymorphic(Us&&... us) -> polymorphic { + return polymorphic(std::in_place_type, std::forward(us)...); +} +template +auto allocate_polymorphic(const A& a, Us&&... us) -> polymorphic { + return polymorphic(std::allocator_arg, a, std::in_place_type, + std::forward(us)...); +} +#endif // XYZ_HAS_EXTENSION_MAKE_POLYMORPHIC } // namespace xyz #endif // XYZ_POLYMORPHIC_H_ diff --git a/polymorphic_test.cc b/polymorphic_test.cc index 4d2c64d9..89b09d3f 100644 --- a/polymorphic_test.cc +++ b/polymorphic_test.cc @@ -845,4 +845,61 @@ TEST(PolymorphicTest, TaggedAllocatorsNotEqualMoveConstructFromValueless) { EXPECT_TRUE(iii.valueless_after_move()); } +#ifdef XYZ_HAS_EXTENSION_MAKE_POLYMORPHIC +TEST(PolymorphicTest, MakePolymorphicDerivedNoArgs) { + auto p = xyz::make_polymorphic(); + EXPECT_EQ(p->value(), 0); +} + +TEST(PolymorphicTest, MakePolymorphicBaseDerivedNoArgs) { + auto p = xyz::make_polymorphic(); + static_assert(std::is_same_v>); + EXPECT_EQ(p->value(), 0); +} + +TEST(PolymorphicTest, MakePolymorphicDerived) { + auto p = xyz::make_polymorphic(42); + EXPECT_EQ(p->value(), 42); +} + +TEST(PolymorphicTest, MakePolymorphicBaseDerived) { + auto p = xyz::make_polymorphic(42); + static_assert(std::is_same_v>); + EXPECT_EQ(p->value(), 42); +} + +TEST(PolymorphicTest, AllocatePolymorphicDerivedNoArgs) { + xyz::TaggedAllocator a(1); + auto p = xyz::allocate_polymorphic(a); + EXPECT_EQ(p->value(), 0); + EXPECT_EQ(p.get_allocator().tag, 1); +} + +TEST(PolymorphicTest, AllocatePolymorphicBaseDerivedNoArgs) { + xyz::TaggedAllocator a(1); + auto p = xyz::allocate_polymorphic(a); + static_assert( + std::is_same_v>>); + EXPECT_EQ(p->value(), 0); + EXPECT_EQ(p.get_allocator().tag, 1); +} + +TEST(PolymorphicTest, AllocatePolymorphicDerived) { + xyz::TaggedAllocator a(1); + auto p = xyz::allocate_polymorphic(a, 42); + EXPECT_EQ(p->value(), 42); + EXPECT_EQ(p.get_allocator().tag, 1); +} + +TEST(PolymorphicTest, AllocatePolymorphicBaseDerived) { + xyz::TaggedAllocator a(1); + auto p = xyz::allocate_polymorphic(a, 42); + static_assert( + std::is_same_v>>); + EXPECT_EQ(p->value(), 42); + EXPECT_EQ(p.get_allocator().tag, 1); +} +#endif // XYZ_HAS_EXTENSION_MAKE_POLYMORPHIC } // namespace