meta: reset-all functionality (see #358)

This commit is contained in:
Michele Caini
2019-11-10 16:28:41 +01:00
parent d6d79a2aa5
commit c645cb83a2
7 changed files with 95 additions and 61 deletions

View File

@@ -583,3 +583,14 @@ entt::meta<my_type>().reset();
```
The type can be re-registered later with a completely different name and form.
To unregister all the types at once instead, a generic meta factory is the way
to go:
```cpp
entt::meta().reset();
```
This function may touch more meta types than those explicitly created by the
user. In fact, all locally created meta types are visited and reset, including
those implicitly generated by the meta system under the hood.

View File

@@ -241,17 +241,45 @@ class extended_meta_factory;
/**
* @brief A meta factory to be used for reflection purposes.
*
* A meta factory is an utility class used to reflect types, data and functions
* of all sorts. This class ensures that the underlying web of types is built
* correctly and performs some checks in debug mode to ensure that there are no
* subtle errors at runtime.
* @brief Meta factory to be used for reflection purposes.
*
* The meta factory is an utility class used to reflect types, data members and
* functions of all sorts. This class ensures that the underlying web of types
* is built correctly and performs some checks in debug mode to ensure that
* there are no subtle errors at runtime.
*/
template<typename...>
class meta_factory;
/*! @brief Generic meta factory to be used for reflection purposes. */
template<>
class meta_factory<> {
public:
/**
* @brief Resets all meta types and all their parts.
*
* This function resets all meta type and their data members, member
* functions and properties, as well as their constructors, destructors,
* base classes and conversion functions if any.
*/
void reset() ENTT_NOEXCEPT {
auto *it = internal::meta_info<>::context;
while(it) {
internal::meta_info<>::reset(it);
it = it->context;
}
}
};
/**
* @brief Basic meta factory to be used for reflection purposes.
* @tparam Type Reflected type for which the factory was created.
*/
template<typename Type>
class meta_factory {
class meta_factory<Type> {
template<typename Node>
bool duplicate(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
return node && (node == candidate || duplicate(candidate, node->next));
@@ -269,6 +297,8 @@ class meta_factory {
ENTT_ASSERT(!duplicate(node, *internal::meta_info<>::global));
node->identifier = identifier;
node->next = *internal::meta_info<>::global;
if(node->next) { node->next->hook = &node->next; }
node->hook = internal::meta_info<>::global;
*internal::meta_info<>::global = node;
return extended_meta_factory<Type>{&node->prop};
@@ -281,7 +311,7 @@ public:
* This function is intended only for unnamed types.
*
* @param identifier Unique identifier.
* @return An extended meta factory for the parent type.
* @return An extended meta factory for the given type.
*/
auto type(const ENTT_ID_TYPE identifier) ENTT_NOEXCEPT {
static_assert(!is_named_type_v<Type>);
@@ -293,7 +323,7 @@ public:
*
* This function is intended only for named types
*
* @return An extended meta factory for the parent type.
* @return An extended meta factory for the given type.
*/
auto type() ENTT_NOEXCEPT {
static_assert(is_named_type_v<Type>);
@@ -678,7 +708,7 @@ public:
* Base classes aren't reset but the link between the two types is removed.
*/
void reset() ENTT_NOEXCEPT {
internal::meta_info<Type>::reset();
internal::meta_info<>::reset(internal::meta_info<Type>::resolve());
}
};
@@ -806,14 +836,15 @@ private:
* This is the point from which everything starts.<br/>
* By invoking this function with a type that is not yet reflected, a meta type
* is created to which it will be possible to attach meta objects through a
* dedicated factory.
* dedicated factory. If no type is provided, a generic meta factory is returned
* instead.
*
* @tparam Type Type to reflect.
* @return A meta factory for the given type.
* @tparam Type Type to reflect, if any.
* @return An eventually generic meta factory.
*/
template<typename Type>
inline meta_factory<Type> meta() ENTT_NOEXCEPT {
return meta_factory<Type>{};
template<typename... Type>
inline meta_factory<Type...> meta() ENTT_NOEXCEPT {
return meta_factory<Type...>{};
}

View File

@@ -102,7 +102,9 @@ struct meta_func_node {
struct meta_type_node {
using size_type = std::size_t;
meta_type_node * const context;
ENTT_ID_TYPE identifier;
meta_type_node ** hook;
meta_type_node * next;
meta_prop_node * prop;
const bool is_void;
@@ -199,23 +201,15 @@ template<>
struct meta_node<> {
inline static meta_type_node *local = nullptr;
inline static meta_type_node **global = &local;
};
inline static meta_type_node *context = nullptr;
static void reset(meta_type_node *node) ENTT_NOEXCEPT {
if(node->hook) {
*node->hook = node->next;
template<typename Type>
struct meta_node<Type> {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>);
static void reset() ENTT_NOEXCEPT {
auto * const node = resolve();
auto **it = meta_node<>::global;
while(*it && *it != node) {
it = &(*it)->next;
}
if(*it) {
*it = (*it)->next;
if(node->next) {
node->next->hook = node->hook;
}
}
const auto unregister_all = y_combinator{
@@ -237,15 +231,28 @@ struct meta_node<Type> {
unregister_all(&node->func, &internal::meta_func_node::prop);
node->identifier = {};
node->dtor = nullptr;
node->hook = nullptr;
node->next = nullptr;
node->dtor = nullptr;
}
};
template<typename Type>
struct meta_node<Type> {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>);
static meta_type_node * resolve() ENTT_NOEXCEPT {
static meta_type_node node{
[]() {
auto *curr = meta_node<>::context;
meta_node<>::context = &node;
return curr;
}(),
{},
nullptr,
nullptr,
nullptr,
std::is_void_v<Type>,
std::is_integral_v<Type>,
std::is_floating_point_v<Type>,

View File

@@ -2043,36 +2043,21 @@ TEST_F(Meta, Reset) {
ASSERT_NE(*entt::internal::meta_info<>::global, nullptr);
ASSERT_NE(entt::internal::meta_info<>::local, nullptr);
entt::meta<char>().reset();
entt::meta<concrete_type>().reset();
entt::meta<setter_getter_type>().reset();
entt::meta<fat_type>().reset();
entt::meta<data_type>().reset();
entt::meta<func_type>().reset();
entt::meta<array_type>().reset();
entt::meta<double>().reset();
entt::meta<props>().reset();
entt::meta<base_type>().reset();
entt::meta<derived_type>().reset();
entt::meta<empty_type>().reset();
entt::meta<an_abstract_type>().reset();
entt::meta<another_abstract_type>().reset();
entt::meta<unsigned int>().reset();
ASSERT_TRUE(entt::resolve("char"_hs));
ASSERT_TRUE(entt::resolve("base"_hs));
ASSERT_EQ(*entt::internal::meta_info<>::global, nullptr);
ASSERT_EQ(entt::internal::meta_info<>::local, nullptr);
entt::meta<char>().reset();
ASSERT_FALSE(entt::resolve("char"_hs));
ASSERT_TRUE(entt::resolve("base"_hs));
entt::meta().reset();
ASSERT_FALSE(entt::resolve("char"_hs));
ASSERT_FALSE(entt::resolve("base"_hs));
ASSERT_FALSE(entt::resolve("derived"_hs));
ASSERT_FALSE(entt::resolve("empty"_hs));
ASSERT_FALSE(entt::resolve("fat"_hs));
ASSERT_FALSE(entt::resolve("data"_hs));
ASSERT_FALSE(entt::resolve("func"_hs));
ASSERT_FALSE(entt::resolve("setter_getter"_hs));
ASSERT_FALSE(entt::resolve("an_abstract_type"_hs));
ASSERT_FALSE(entt::resolve("another_abstract_type"_hs));
ASSERT_FALSE(entt::resolve("concrete"_hs));
ASSERT_EQ(*entt::internal::meta_info<>::global, nullptr);
ASSERT_EQ(entt::internal::meta_info<>::local, nullptr);
Meta::SetUpAfterUnregistration();
entt::meta_any any{42.};

View File

@@ -56,5 +56,5 @@ LIB_EXPORT void a_module_meta_init() {
}
LIB_EXPORT void a_module_meta_deinit() {
entt::meta<char>().reset();
entt::meta().reset();
}

View File

@@ -61,5 +61,5 @@ LIB_EXPORT void another_module_meta_init() {
}
LIB_EXPORT void another_module_meta_deinit() {
entt::meta<int>().reset();
entt::meta().reset();
}

View File

@@ -129,8 +129,8 @@ TEST(Lib, Meta) {
ASSERT_TRUE(entt::resolve<char>().data("c"_hs));
a_module_meta_deinit();
entt::meta().reset();
another_module_meta_deinit();
entt::meta<double>().reset();
ASSERT_FALSE(entt::resolve("double"_hs));
ASSERT_FALSE(entt::resolve("char"_hs));