diff --git a/src/entt/core/any.hpp b/src/entt/core/any.hpp index d5670c8a8..7ebf50c62 100644 --- a/src/entt/core/any.hpp +++ b/src/entt/core/any.hpp @@ -189,6 +189,22 @@ class basic_any { initialize(std::forward(args)...); } + /** + * @brief Constructs a wrapper taking ownership of the passed object. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value A pointer to an object to take ownership of. + */ + template>>> + explicit basic_any(std::in_place_t, Type *value) + : instance{value}, + info{&type_id>()}, + vtable{basic_vtable>}, + mode{any_policy::dynamic} { + if(instance == nullptr) { + reset(); + } + } + /** * @brief Constructs a wrapper from a given value. * @tparam Type Type of object to use to initialize the wrapper. diff --git a/test/entt/core/any.cpp b/test/entt/core/any.cpp index 1852fd452..8d9bf4123 100644 --- a/test/entt/core/any.cpp +++ b/test/entt/core/any.cpp @@ -46,6 +46,17 @@ struct fat { struct alignas(64u) over_aligned {}; +TEST(Any, Empty) { + entt::any any{}; + + ASSERT_FALSE(any); + ASSERT_FALSE(any.owner()); + ASSERT_EQ(any.policy(), entt::any_policy::empty); + ASSERT_EQ(any.type(), entt::type_id()); + ASSERT_EQ(entt::any_cast(&any), nullptr); + ASSERT_EQ(any.data(), nullptr); +} + TEST(Any, SBO) { entt::any any{'c'}; @@ -69,15 +80,35 @@ TEST(Any, NoSBO) { ASSERT_EQ(entt::any_cast(any), instance); } -TEST(Any, Empty) { - entt::any any{}; +TEST(Any, SBOInPlaceConstruction) { + std::unique_ptr instance = std::make_unique(2); + entt::any any{std::in_place, instance.release()}; + + ASSERT_TRUE(any); + ASSERT_TRUE(any.owner()); + ASSERT_EQ(any.policy(), entt::any_policy::dynamic); + ASSERT_EQ(any.type(), entt::type_id()); + ASSERT_EQ(entt::any_cast(&any), nullptr); + ASSERT_EQ(entt::any_cast(any), 2); + + auto other = any.as_ref(); + + ASSERT_TRUE(other); + ASSERT_FALSE(other.owner()); + ASSERT_EQ(other.policy(), entt::any_policy::ref); + ASSERT_EQ(other.type(), entt::type_id()); + ASSERT_EQ(entt::any_cast(other), 2); + ASSERT_EQ(other.data(), any.data()); +} + +TEST(Any, SBOInPlaceNullptrConstruction) { + int *instance = nullptr; + entt::any any{std::in_place, instance}; ASSERT_FALSE(any); ASSERT_FALSE(any.owner()); ASSERT_EQ(any.policy(), entt::any_policy::empty); ASSERT_EQ(any.type(), entt::type_id()); - ASSERT_EQ(entt::any_cast(&any), nullptr); - ASSERT_EQ(any.data(), nullptr); } TEST(Any, SBOInPlaceTypeConstruction) { @@ -361,6 +392,37 @@ TEST(Any, SBOAsConstRefTransferValue) { ASSERT_EQ(value, 2); } +TEST(Any, NoSBOInPlaceConstruction) { + std::unique_ptr instance = std::make_unique(.1, .2, .3, .4); + entt::any any{std::in_place, instance.release()}; + + ASSERT_TRUE(any); + ASSERT_TRUE(any.owner()); + ASSERT_EQ(any.policy(), entt::any_policy::dynamic); + ASSERT_EQ(any.type(), entt::type_id()); + ASSERT_EQ(entt::any_cast(&any), nullptr); + ASSERT_EQ(entt::any_cast(any), (fat{.1, .2, .3, .4})); + + auto other = any.as_ref(); + + ASSERT_TRUE(other); + ASSERT_FALSE(other.owner()); + ASSERT_EQ(other.policy(), entt::any_policy::ref); + ASSERT_EQ(other.type(), entt::type_id()); + ASSERT_EQ(entt::any_cast(other), (fat{.1, .2, .3, .4})); + ASSERT_EQ(other.data(), any.data()); +} + +TEST(Any, NoSBOInPlaceNullptrConstruction) { + fat *instance = nullptr; + entt::any any{std::in_place, instance}; + + ASSERT_FALSE(any); + ASSERT_FALSE(any.owner()); + ASSERT_EQ(any.policy(), entt::any_policy::empty); + ASSERT_EQ(any.type(), entt::type_id()); +} + TEST(Any, NoSBOInPlaceTypeConstruction) { const fat instance{.1, .2, .3, .4}; entt::any any{std::in_place_type, instance};