meta: support for pointer-like types

This commit is contained in:
Michele Caini
2020-06-21 23:39:26 +02:00
parent 4ad6c0a8a9
commit 2566e3631b
11 changed files with 162 additions and 89 deletions

1
TODO
View File

@@ -32,3 +32,4 @@ Next:
- meta_any deref fails if operator* returns a temporary
- remove dereferenceable detector from type traits (is broken)
- update meta.md
- review _t

View File

@@ -25,6 +25,7 @@
#include "meta/factory.hpp"
#include "meta/internal.hpp"
#include "meta/meta.hpp"
#include "meta/pointer.hpp"
#include "meta/policy.hpp"
#include "meta/range.hpp"
#include "meta/resolve.hpp"

View File

@@ -275,7 +275,7 @@ struct meta_type_node {
const bool is_function_pointer;
const bool is_member_object_pointer;
const bool is_member_function_pointer;
const bool is_dereferenceable;
const bool is_pointer_like;
const bool is_sequence_container;
const bool is_associative_container;
const size_type rank;
@@ -419,7 +419,7 @@ public:
std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
std::is_member_object_pointer_v<Type>,
std::is_member_function_pointer_v<Type>,
is_dereferenceable_v<Type>,
is_meta_pointer_like_v<Type>,
has_meta_sequence_container_traits_v<Type>,
has_meta_associative_container_traits_v<Type>,
std::rank_v<Type>,

View File

@@ -134,7 +134,7 @@ class meta_any {
[[nodiscard]] static meta_any dereference_operator(meta_any &any) {
meta_any other{};
if constexpr(is_dereferenceable_v<Type>) {
if constexpr(is_meta_pointer_like_v<Type>) {
if constexpr(std::is_const_v<std::remove_reference_t<decltype(*std::declval<Type>())>>) {
other = *any.cast<Type>();
} else {
@@ -1095,11 +1095,12 @@ public:
}
/**
* @brief Checks whether a type is dereferenceable or not.
* @return True if the underlying type is dereferenceable, false otherwise.
* @brief Checks whether a type is a pointer-like type or not.
* @return True if the underlying type is a pointer-like one, false
* otherwise.
*/
[[nodiscard]] bool is_dereferenceable() const ENTT_NOEXCEPT {
return node->is_dereferenceable;
[[nodiscard]] bool is_pointer_like() const ENTT_NOEXCEPT {
return node->is_pointer_like;
}
/**

48
src/entt/meta/pointer.hpp Normal file
View File

@@ -0,0 +1,48 @@
#ifndef ENTT_META_POINTER_HPP
#define ENTT_META_POINTER_HPP
#include <memory>
#include <type_traits>
#include "type_traits.hpp"
namespace entt {
/**
* @brief Makes plain pointers pointer-like types for the meta system.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<Type *>
: std::true_type
{};
/**
* @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<std::shared_ptr<Type>>
: std::true_type
{};
/**
* @brief Makes `std::unique_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
* @tparam Args Other arguments.
*/
template<typename Type, typename... Args>
struct is_meta_pointer_like<std::unique_ptr<Type, Args...>>
: std::true_type
{};
}
#endif

View File

@@ -72,6 +72,23 @@ template<typename Type>
inline constexpr auto has_meta_associative_container_traits_v = has_meta_associative_container_traits<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is a
* pointer-like type from the point of view of the meta system, false otherwise.
* @tparam Type Potentially pointer-like type.
*/
template<typename>
struct is_meta_pointer_like: std::false_type {};
/**
* @brief Helper variable template.
* @tparam Type Potentially pointer-like type.
*/
template<typename Type>
inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like<Type>::value;
}

View File

@@ -184,6 +184,7 @@ SETUP_BASIC_TEST(meta_conv entt/meta/meta_conv.cpp)
SETUP_BASIC_TEST(meta_ctor entt/meta/meta_ctor.cpp)
SETUP_BASIC_TEST(meta_data entt/meta/meta_data.cpp)
SETUP_BASIC_TEST(meta_func entt/meta/meta_func.cpp)
SETUP_BASIC_TEST(meta_pointer entt/meta/meta_pointer.cpp)
SETUP_BASIC_TEST(meta_prop entt/meta/meta_prop.cpp)
SETUP_BASIC_TEST(meta_range entt/meta/meta_range.cpp)
SETUP_BASIC_TEST(meta_type entt/meta/meta_type.cpp)

View File

@@ -622,79 +622,3 @@ TEST_F(MetaAny, UnmanageableType) {
ASSERT_TRUE(std::as_const(any).convert<unmanageable_t>());
ASSERT_FALSE(std::as_const(any).convert<int>());
}
TEST_F(MetaAny, DereferenceOperatorInvalidType) {
int value = 0;
entt::meta_any any{value};
ASSERT_FALSE(any.type().is_pointer());
ASSERT_FALSE(any.type().is_dereferenceable());
ASSERT_EQ(any.type(), entt::resolve<int>());
auto deref = *any;
ASSERT_FALSE(deref);
}
TEST_F(MetaAny, DereferenceOperatorConstType) {
const int value = 0;
entt::meta_any any{&value};
ASSERT_TRUE(any.type().is_pointer());
ASSERT_TRUE(any.type().is_dereferenceable());
ASSERT_EQ(any.type(), entt::resolve<const int *>());
auto deref = *any;
ASSERT_TRUE(deref);
ASSERT_FALSE(deref.type().is_pointer());
ASSERT_FALSE(deref.type().is_dereferenceable());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
ASSERT_EQ(*any.cast<const int *>(), 0);
ASSERT_EQ(value, 0);
}
TEST_F(MetaAny, DereferenceOperatorRawPointer) {
int value = 0;
entt::meta_any any{&value};
ASSERT_TRUE(any.type().is_pointer());
ASSERT_TRUE(any.type().is_dereferenceable());
ASSERT_EQ(any.type(), entt::resolve<int *>());
auto deref = *any;
ASSERT_TRUE(deref);
ASSERT_FALSE(deref.type().is_pointer());
ASSERT_FALSE(deref.type().is_dereferenceable());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
ASSERT_EQ(*any.cast<int *>(), 42);
ASSERT_EQ(value, 42);
}
TEST_F(MetaAny, DereferenceOperatorSmartPointer) {
auto value = std::make_shared<int>(0);
entt::meta_any any{value};
ASSERT_FALSE(any.type().is_pointer());
ASSERT_TRUE(any.type().is_dereferenceable());
ASSERT_EQ(any.type(), entt::resolve<std::shared_ptr<int>>());
auto deref = *any;
ASSERT_TRUE(deref);
ASSERT_FALSE(deref.type().is_pointer());
ASSERT_FALSE(deref.type().is_dereferenceable());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
ASSERT_EQ(*value, 42);
}

View File

@@ -1,10 +1,8 @@
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/container.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/resolve.hpp>
#include <entt/meta/type_traits.hpp>
TEST(MetaSequenceContainer, Empty) {
entt::meta_sequence_container container{};

View File

@@ -0,0 +1,81 @@
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/pointer.hpp>
#include <entt/meta/resolve.hpp>
TEST(MetaPointerLike, DereferenceOperatorInvalidType) {
int value = 0;
entt::meta_any any{value};
ASSERT_FALSE(any.type().is_pointer());
ASSERT_FALSE(any.type().is_pointer_like());
ASSERT_EQ(any.type(), entt::resolve<int>());
auto deref = *any;
ASSERT_FALSE(deref);
}
TEST(MetaPointerLike, DereferenceOperatorConstType) {
const int value = 0;
entt::meta_any any{&value};
ASSERT_TRUE(any.type().is_pointer());
ASSERT_TRUE(any.type().is_pointer_like());
ASSERT_EQ(any.type(), entt::resolve<const int *>());
auto deref = *any;
ASSERT_TRUE(deref);
ASSERT_FALSE(deref.type().is_pointer());
ASSERT_FALSE(deref.type().is_pointer_like());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
ASSERT_EQ(*any.cast<const int *>(), 0);
ASSERT_EQ(value, 0);
}
TEST(MetaPointerLike, DereferenceOperatorRawPointer) {
int value = 0;
entt::meta_any any{&value};
ASSERT_TRUE(any.type().is_pointer());
ASSERT_TRUE(any.type().is_pointer_like());
ASSERT_EQ(any.type(), entt::resolve<int *>());
auto deref = *any;
ASSERT_TRUE(deref);
ASSERT_FALSE(deref.type().is_pointer());
ASSERT_FALSE(deref.type().is_pointer_like());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
ASSERT_EQ(*any.cast<int *>(), 42);
ASSERT_EQ(value, 42);
}
TEST(MetaPointerLike, DereferenceOperatorSmartPointer) {
auto value = std::make_shared<int>(0);
entt::meta_any any{value};
ASSERT_FALSE(any.type().is_pointer());
ASSERT_TRUE(any.type().is_pointer_like());
ASSERT_EQ(any.type(), entt::resolve<std::shared_ptr<int>>());
auto deref = *any;
ASSERT_TRUE(deref);
ASSERT_FALSE(deref.type().is_pointer());
ASSERT_FALSE(deref.type().is_pointer_like());
ASSERT_EQ(deref.type(), entt::resolve<int>());
deref.cast<int>() = 42;
ASSERT_EQ(*any.cast<std::shared_ptr<int>>(), 42);
ASSERT_EQ(*value, 42);
}

View File

@@ -3,10 +3,11 @@
#include <vector>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/meta/container.hpp>
#include <entt/meta/factory.hpp>
#include <entt/meta/meta.hpp>
#include <entt/meta/pointer.hpp>
#include <entt/meta/resolve.hpp>
#include <entt/meta/container.hpp>
template<typename Type>
void set(Type &prop, Type value) {
@@ -164,9 +165,9 @@ TEST_F(MetaType, Traits) {
ASSERT_TRUE(entt::resolve<decltype(&clazz_t::member)>().is_member_function_pointer());
ASSERT_FALSE(entt::resolve<decltype(&clazz_t::value)>().is_member_function_pointer());
ASSERT_TRUE(entt::resolve<int *>().is_dereferenceable());
ASSERT_TRUE(entt::resolve<std::shared_ptr<int>>().is_dereferenceable());
ASSERT_FALSE(entt::resolve<int>().is_dereferenceable());
ASSERT_TRUE(entt::resolve<int *>().is_pointer_like());
ASSERT_TRUE(entt::resolve<std::shared_ptr<int>>().is_pointer_like());
ASSERT_FALSE(entt::resolve<int>().is_pointer_like());
ASSERT_TRUE(entt::resolve<std::vector<int>>().is_sequence_container());
ASSERT_FALSE((entt::resolve<std::map<int, char>>().is_sequence_container()));