meta any: in place construction/emplace
This commit is contained in:
+55
-21
@@ -364,6 +364,45 @@ public:
|
||||
copy_fn{nullptr}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs a meta any by directly initializing the new object.
|
||||
*
|
||||
* This class uses a technique called small buffer optimization (SBO) to
|
||||
* completely eliminate the need to allocate memory, where possible.<br/>
|
||||
* From the user's point of view, nothing will change, but the elimination
|
||||
* of allocations will reduce the jumps in memory and therefore will avoid
|
||||
* chasing of pointers. This will greatly improve the use of the cache, thus
|
||||
* increasing the overall performance.
|
||||
*
|
||||
* @tparam Type Type of object to use to initialize the container.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
meta_any(std::in_place_type_t<Type>, Args &&... args) {
|
||||
using actual_type = std::remove_cv_t<std::remove_reference_t<Type>>;
|
||||
constexpr auto sbo_allowed = sizeof(actual_type) <= sizeof(void *);
|
||||
node = internal::meta_info<Type>::resolve();
|
||||
|
||||
compare_fn = &compare<actual_type>;
|
||||
|
||||
if constexpr(sbo_allowed) {
|
||||
instance = new (&storage) actual_type{std::forward<Args>(args)...};
|
||||
destroy_fn = &destroy_storage<actual_type>;
|
||||
copy_fn = ©_storage<actual_type>;
|
||||
} else {
|
||||
using chunk_type = std::aligned_storage_t<sizeof(actual_type), alignof(actual_type)>;
|
||||
|
||||
auto chunk = std::make_unique<chunk_type>();
|
||||
instance = new (chunk.get()) actual_type{std::forward<Args>(args)...};
|
||||
new (&storage) chunk_type *{chunk.get()};
|
||||
chunk.release();
|
||||
|
||||
destroy_fn = &destroy_object<actual_type>;
|
||||
copy_fn = ©_object<actual_type>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a meta any from a given value.
|
||||
*
|
||||
@@ -378,27 +417,9 @@ public:
|
||||
* @param type An instance of an object to use to initialize the container.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, meta_any>>>
|
||||
meta_any(Type &&type) {
|
||||
using actual_type = std::remove_cv_t<std::remove_reference_t<Type>>;
|
||||
node = internal::meta_info<Type>::resolve();
|
||||
|
||||
compare_fn = &compare<actual_type>;
|
||||
|
||||
if constexpr(sizeof(actual_type) <= sizeof(void *)) {
|
||||
instance = new (&storage) actual_type{std::forward<Type>(type)};
|
||||
destroy_fn = &destroy_storage<actual_type>;
|
||||
copy_fn = ©_storage<actual_type>;
|
||||
} else {
|
||||
using chunk_type = std::aligned_storage_t<sizeof(actual_type), alignof(actual_type)>;
|
||||
|
||||
auto *chunk = new chunk_type;
|
||||
instance = new (chunk) actual_type{std::forward<Type>(type)};
|
||||
new (&storage) chunk_type *{chunk};
|
||||
|
||||
destroy_fn = &destroy_object<actual_type>;
|
||||
copy_fn = ©_object<actual_type>;
|
||||
}
|
||||
}
|
||||
meta_any(Type &&type)
|
||||
: meta_any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(type)}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
@@ -562,6 +583,19 @@ public:
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the contained object by initializing a new instance
|
||||
* directly.
|
||||
* @tparam Type Type of object to use to initialize the container.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args&& ... args) {
|
||||
[[maybe_unused]] meta_any other{std::move(*this)};
|
||||
*this = meta_any{std::in_place_type_t<Type>{}, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns false if a container is empty, true otherwise.
|
||||
* @return False if the container is empty, true otherwise.
|
||||
|
||||
@@ -264,6 +264,21 @@ TEST_F(Meta, MetaAnyEmpty) {
|
||||
ASSERT_NE(any, entt::meta_any{'c'});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnySBOInPlaceConstruction) {
|
||||
entt::meta_any any{std::in_place_type<int>, 42};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(any).cast<int>(), 42);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place_type<int>, 42}));
|
||||
ASSERT_EQ(any, entt::meta_any{42});
|
||||
ASSERT_NE(any, entt::meta_any{3});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnySBOCopyConstruction) {
|
||||
entt::meta_any any{42};
|
||||
entt::meta_any other{any};
|
||||
@@ -324,6 +339,23 @@ TEST_F(Meta, MetaAnySBOMoveAssignment) {
|
||||
ASSERT_NE(other, entt::meta_any{0});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyNoSBOInPlaceConstruction) {
|
||||
int value = 42;
|
||||
fat_type instance{&value};
|
||||
entt::meta_any any{std::in_place_type<fat_type>, instance};
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<fat_type>());
|
||||
ASSERT_EQ(any.cast<fat_type>(), instance);
|
||||
ASSERT_EQ(std::as_const(any).cast<fat_type>(), instance);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place_type<fat_type>, instance}));
|
||||
ASSERT_EQ(any, entt::meta_any{instance});
|
||||
ASSERT_NE(any, entt::meta_any{fat_type{}});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyNoSBOCopyConstruction) {
|
||||
int value = 42;
|
||||
fat_type instance{&value};
|
||||
@@ -404,6 +436,22 @@ TEST_F(Meta, MetaAnyNoSBODestruction) {
|
||||
ASSERT_EQ(fat_type::counter, 1);
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnyEmplace) {
|
||||
entt::meta_any any{};
|
||||
any.emplace<int>(42);
|
||||
|
||||
ASSERT_TRUE(any);
|
||||
ASSERT_FALSE(any.can_cast<void>());
|
||||
ASSERT_TRUE(any.can_cast<int>());
|
||||
ASSERT_EQ(any.cast<int>(), 42);
|
||||
ASSERT_EQ(std::as_const(any).cast<int>(), 42);
|
||||
ASSERT_NE(any.data(), nullptr);
|
||||
ASSERT_NE(std::as_const(any).data(), nullptr);
|
||||
ASSERT_EQ(any, (entt::meta_any{std::in_place_type<int>, 42}));
|
||||
ASSERT_EQ(any, entt::meta_any{42});
|
||||
ASSERT_NE(any, entt::meta_any{3});
|
||||
}
|
||||
|
||||
TEST_F(Meta, MetaAnySBOSwap) {
|
||||
entt::meta_any lhs{'c'};
|
||||
entt::meta_any rhs{42};
|
||||
|
||||
Reference in New Issue
Block a user