diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index 6288d56a2..d0a70626d 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -236,10 +236,6 @@ meta_any invoke([[maybe_unused]] meta_handle handle, meta_any *args, std::index_ */ -template -class extended_meta_factory; - - /** * @brief Meta factory to be used for reflection purposes. * @@ -274,6 +270,123 @@ public: }; +/** + * @brief Extended meta factory to be used for reflection purposes. + * @tparam Type Reflected type for which the factory was created. + * @tparam Spec Property specialization pack used to disambiguate overloads. + */ +template +class meta_factory: public meta_factory { + bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT { + return node && (node->key() == key || duplicate(key, node->next)); + } + + template + void unpack(std::index_sequence, std::tuple property, Other &&... other) { + unroll(choice<3>, std::move(std::get(property))..., std::forward(other)...); + } + + template + void unroll(choice_t<3>, std::tuple property, Other &&... other) { + unpack(std::index_sequence_for{}, std::move(property), std::forward(other)...); + } + + template + void unroll(choice_t<2>, std::pair property, Other &&... other) { + assign(std::move(property.first), std::move(property.second)); + unroll(choice<3>, std::forward(other)...); + } + + template + std::enable_if_t> + unroll(choice_t<1>, Property &&property, Other &&... other) { + assign(std::forward(property)); + unroll(choice<3>, std::forward(other)...); + } + + template + void unroll(choice_t<0>, Func &&invocable, Other &&... other) { + unroll(choice<3>, std::forward(invocable)(), std::forward(other)...); + } + + template + void unroll(choice_t<0>) {} + + template + void assign(Key &&key, Value &&... value) { + static auto property{std::make_tuple(std::forward(key), std::forward(value)...)}; + + static internal::meta_prop_node node{ + nullptr, + []() -> meta_any { + return std::get<0>(property); + }, + []() -> meta_any { + if constexpr(sizeof...(Value) == 0) { + return {}; + } else { + return std::get<1>(property); + } + } + }; + + ENTT_ASSERT(!duplicate(node.key(), *curr)); + node.next = *curr; + *curr = &node; + } + +public: + /** + * @brief Constructs an extended factory from a given node. + * @param target The underlying node to which to assign the properties. + */ + meta_factory(entt::internal::meta_prop_node **target) + : curr{target} + {} + + /** + * @brief Assigns a property to the last meta object created. + * + * Both the key and the value (if any) must be at least copy constructible. + * + * @tparam PropertyOrKey Type of the property or property key. + * @tparam Value Optional type of the property value. + * @param property_or_key Property or property key. + * @param value Optional property value. + * @return A meta factory for the parent type. + */ + template + auto prop(PropertyOrKey &&property_or_key, Value &&... value) && { + if constexpr(sizeof...(Value) == 0) { + unroll(choice<3>, std::forward(property_or_key)); + } else { + assign(std::forward(property_or_key), std::forward(value)...); + } + + return meta_factory{curr}; + } + + /** + * @brief Assigns properties to the last meta object created. + * + * Both the keys and the values (if any) must be at least copy + * constructible. + * + * @tparam Property Types of the properties. + * @param property Properties to assign to the last meta object created. + * @return A meta factory for the parent type. + */ + template + auto props(Property... property) && { + unroll(choice<3>, std::forward(property)...); + return meta_factory{curr}; + } + +private: + entt::internal::meta_prop_node **curr{nullptr}; +}; + + /** * @brief Basic meta factory to be used for reflection purposes. * @tparam Type Reflected type for which the factory was created. @@ -301,7 +414,7 @@ class meta_factory { node->hook = internal::meta_info<>::global; *internal::meta_info<>::global = node; - return extended_meta_factory{&node->prop}; + return meta_factory{&node->prop}; } public: @@ -456,7 +569,7 @@ public: node.next = type->ctor; type->ctor = &node; - return extended_meta_factory>{&node.prop}; + return meta_factory>{&node.prop}; } /** @@ -489,7 +602,7 @@ public: node.next = type->ctor; type->ctor = &node; - return extended_meta_factory{&node.prop}; + return meta_factory{&node.prop}; } /** @@ -607,7 +720,7 @@ public: curr->next = type->data; type->data = curr; - return extended_meta_factory>{&curr->prop}; + return meta_factory>{&curr->prop}; } /** @@ -654,7 +767,7 @@ public: node.next = type->data; type->data = &node; - return extended_meta_factory, std::integral_constant>{&node.prop}; + return meta_factory, std::integral_constant>{&node.prop}; } /** @@ -696,7 +809,7 @@ public: node.next = type->func; type->func = &node; - return extended_meta_factory>{&node.prop}; + return meta_factory>{&node.prop}; } /** @@ -713,138 +826,27 @@ public: }; -/** - * @brief Extended meta factory to be used for reflection purposes. - * @tparam Type Reflected type for which the factory was created. - * @tparam Spec Property specialization pack used to disambiguate overloads. - */ -template -class extended_meta_factory: public meta_factory { - bool duplicate(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT { - return node && (node->key() == key || duplicate(key, node->next)); - } - - template - void unpack(std::index_sequence, std::tuple property, Other &&... other) { - unroll(choice<3>, std::move(std::get(property))..., std::forward(other)...); - } - - template - void unroll(choice_t<3>, std::tuple property, Other &&... other) { - unpack(std::index_sequence_for{}, std::move(property), std::forward(other)...); - } - - template - void unroll(choice_t<2>, std::pair property, Other &&... other) { - assign(std::move(property.first), std::move(property.second)); - unroll(choice<3>, std::forward(other)...); - } - - template - std::enable_if_t> - unroll(choice_t<1>, Property &&property, Other &&... other) { - assign(std::forward(property)); - unroll(choice<3>, std::forward(other)...); - } - - template - void unroll(choice_t<0>, Func &&invocable, Other &&... other) { - unroll(choice<3>, std::forward(invocable)(), std::forward(other)...); - } - - template - void unroll(choice_t<0>) {} - - template - void assign(Key &&key, Value &&... value) { - static auto property{std::make_tuple(std::forward(key), std::forward(value)...)}; - - static internal::meta_prop_node node{ - nullptr, - []() -> meta_any { - return std::get<0>(property); - }, - []() -> meta_any { - if constexpr(sizeof...(Value) == 0) { - return {}; - } else { - return std::get<1>(property); - } - } - }; - - ENTT_ASSERT(!duplicate(node.key(), *curr)); - node.next = *curr; - *curr = &node; - } - -public: - /** - * @brief Constructs an extended factory from a given node. - * @param target The underlying node to which to assign the properties. - */ - extended_meta_factory(entt::internal::meta_prop_node **target) - : curr{target} - {} - - /** - * @brief Assigns a property to the last meta object created. - * - * Both the key and the value (if any) must be at least copy constructible. - * - * @tparam PropertyOrKey Type of the property or property key. - * @tparam Value Optional type of the property value. - * @param property_or_key Property or property key. - * @param value Optional property value. - * @return A meta factory for the parent type. - */ - template - auto prop(PropertyOrKey &&property_or_key, Value &&... value) && { - if constexpr(sizeof...(Value) == 0) { - unroll(choice<3>, std::forward(property_or_key)); - } else { - assign(std::forward(property_or_key), std::forward(value)...); - } - - return extended_meta_factory{curr}; - } - - /** - * @brief Assigns properties to the last meta object created. - * - * Both the keys and the values (if any) must be at least copy - * constructible. - * - * @tparam Property Types of the properties. - * @param property Properties to assign to the last meta object created. - * @return A meta factory for the parent type. - */ - template - auto props(Property... property) && { - unroll(choice<3>, std::forward(property)...); - return extended_meta_factory{curr}; - } - -private: - entt::internal::meta_prop_node **curr{nullptr}; -}; - - /** * @brief Utility function to use for reflection. * * This is the point from which everything starts.
* 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. If no type is provided, a generic meta factory is returned - * instead. + * dedicated factory. If no type is provided instead, a generic meta factory is + * returned. * * @tparam Type Type to reflect, if any. * @return An eventually generic meta factory. */ template inline meta_factory meta() ENTT_NOEXCEPT { - return meta_factory{}; + if constexpr(sizeof...(Type) == 0) { + return meta_factory{}; + } else { + auto * const node = internal::meta_info::resolve(); + // extended meta factory to allow assigning properties to opaque meta types + return meta_factory{&node->prop}; + } }