From 3bf42c6ff3805a0d42bbc661794a95ff31bedc26 Mon Sep 17 00:00:00 2001 From: untodesu Date: Sat, 15 Mar 2025 16:22:09 +0500 Subject: Add whatever I was working on for the last month --- deps/include/entt/meta/factory.hpp | 668 +++++++++++++++++++++++++++++++++++++ 1 file changed, 668 insertions(+) create mode 100644 deps/include/entt/meta/factory.hpp (limited to 'deps/include/entt/meta/factory.hpp') diff --git a/deps/include/entt/meta/factory.hpp b/deps/include/entt/meta/factory.hpp new file mode 100644 index 0000000..3f61d69 --- /dev/null +++ b/deps/include/entt/meta/factory.hpp @@ -0,0 +1,668 @@ +#ifndef ENTT_META_FACTORY_HPP +#define ENTT_META_FACTORY_HPP + +#include +#include +#include +#include +#include +#include +#include +#include "../config/config.h" +#include "../core/bit.hpp" +#include "../core/fwd.hpp" +#include "../core/type_info.hpp" +#include "../core/type_traits.hpp" +#include "../locator/locator.hpp" +#include "context.hpp" +#include "meta.hpp" +#include "node.hpp" +#include "policy.hpp" +#include "range.hpp" +#include "resolve.hpp" +#include "utility.hpp" + +namespace entt { + +/*! @cond TURN_OFF_DOXYGEN */ +namespace internal { + +class basic_meta_factory { + using invoke_type = std::remove_pointer_t; + + auto *find_overload() { + auto *curr = &details->func[bucket]; + + while(curr->invoke != invoke) { + curr = curr->next.get(); + } + + return curr; + } + +protected: + void type(const id_type id) noexcept { + auto &&elem = meta_context::from(*ctx).value[parent]; + ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier"); + invoke = nullptr; + bucket = parent; + elem.id = id; + } + + void base(const id_type id, meta_base_node node) { + details->base.insert_or_assign(id, node); + invoke = nullptr; + bucket = parent; + } + + void conv(const id_type id, meta_conv_node node) { + details->conv.insert_or_assign(id, node); + invoke = nullptr; + bucket = parent; + } + + void ctor(const id_type id, meta_ctor_node node) { + details->ctor.insert_or_assign(id, node); + invoke = nullptr; + bucket = parent; + } + + void dtor(meta_dtor_node node) { + meta_context::from(*ctx).value[parent].dtor = node; + invoke = nullptr; + bucket = parent; + } + + void data(const id_type id, meta_data_node node) { + if(auto it = details->data.find(id); it == details->data.end()) { + details->data.insert_or_assign(id, std::move(node)); + } else if(it->second.set != node.set || it->second.get != node.get) { + it->second = std::move(node); + } + + invoke = nullptr; + bucket = id; + } + + void func(const id_type id, meta_func_node node) { + if(auto it = details->func.find(id); it == details->func.end()) { + auto &&elem = details->func.insert_or_assign(id, std::move(node)).first; + invoke = elem->second.invoke; + bucket = id; + } else { + auto *curr = &it->second; + + while(curr->invoke != node.invoke && curr->next) { + curr = curr->next.get(); + } + + if(curr->invoke == node.invoke) { + invoke = curr->invoke; + } else { + invoke = node.invoke; + curr->next = std::make_shared(); + *curr->next = std::move(node); + } + + bucket = id; + } + } + + void prop(const id_type key, meta_prop_node value) { + if(bucket == parent) { + details->prop[key] = std::move(value); + } else if(invoke == nullptr) { + details->data[bucket].prop[key] = std::move(value); + } else { + find_overload()->prop[key] = std::move(value); + } + } + + void traits(const meta_traits value) { + if(bucket == parent) { + meta_context::from(*ctx).value[bucket].traits |= value; + } else if(invoke == nullptr) { + details->data[bucket].traits |= value; + } else { + find_overload()->traits |= value; + } + } + + void custom(meta_custom_node node) { + if(bucket == parent) { + meta_context::from(*ctx).value[bucket].custom = std::move(node); + } else if(invoke == nullptr) { + details->data[bucket].custom = std::move(node); + } else { + find_overload()->custom = std::move(node); + } + } + +public: + basic_meta_factory(const id_type id, meta_ctx &area) + : ctx{&area}, + parent{id}, + bucket{id} { + auto &&elem = meta_context::from(*ctx).value[parent]; + + if(!elem.details) { + elem.details = std::make_shared(); + } + + details = elem.details.get(); + } + +private: + meta_ctx *ctx{}; + id_type parent{}; + id_type bucket{}; + invoke_type *invoke{}; + meta_type_descriptor *details{}; +}; + +} // namespace internal +/*! @endcond */ + +/** + * @brief Meta factory to be used for reflection purposes. + * @tparam Type Reflected type for which the factory was created. + */ +template +class meta_factory: private internal::basic_meta_factory { + using base_type = internal::basic_meta_factory; + + template + void data(const id_type id, std::index_sequence) noexcept { + using data_type = std::invoke_result_t; + using args_type = type_list)>::args_type...>; + static_assert(Policy::template value, "Invalid return type for the given policy"); + + base_type::data( + id, + internal::meta_data_node{ + /* this is never static */ + (std::is_member_object_pointer_v)> && ... && std::is_const_v>) ? internal::meta_traits::is_const : internal::meta_traits::is_none, + Setter::size, + &internal::resolve>>, + &meta_arg::size != 1u, type_list_element_t>...>>, + +[](meta_handle instance, meta_any value) { return (meta_setter>(*instance.operator->(), value.as_ref()) || ...); }, + &meta_getter}); + } + +public: + /*! @brief Default constructor. */ + meta_factory() noexcept + : internal::basic_meta_factory{type_id(), locator::value_or()} {} + + /** + * @brief Context aware constructor. + * @param area The context into which to construct meta types. + */ + meta_factory(meta_ctx &area) noexcept + : internal::basic_meta_factory{type_id().hash(), area} {} + + /** + * @brief Assigns a custom unique identifier to a meta type. + * @param id A custom unique identifier. + * @return A meta factory for the given type. + */ + meta_factory type(const id_type id) noexcept { + base_type::type(id); + return *this; + } + + /** + * @brief Assigns a meta base to a meta type. + * + * A reflected base class must be a real base class of the reflected type. + * + * @tparam Base Type of the base class to assign to the meta type. + * @return A meta factory for the parent type. + */ + template + meta_factory base() noexcept { + static_assert(!std::is_same_v && std::is_base_of_v, "Invalid base type"); + auto *const op = +[](const void *instance) noexcept { return static_cast(static_cast(static_cast(instance))); }; + base_type::base(type_id().hash(), internal::meta_base_node{&internal::resolve, op}); + return *this; + } + + /** + * @brief Assigns a meta conversion function to a meta type. + * + * Conversion functions can be either free functions or member + * functions.
+ * In case of free functions, they must accept a const reference to an + * instance of the parent type as an argument. In case of member functions, + * they should have no arguments at all. + * + * @tparam Candidate The actual function to use for the conversion. + * @return A meta factory for the parent type. + */ + template + auto conv() noexcept { + using conv_type = std::remove_cv_t>>; + auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast(instance))); }; + base_type::conv(type_id().hash(), internal::meta_conv_node{op}); + return *this; + } + + /** + * @brief Assigns a meta conversion function to a meta type. + * + * The given type must be such that an instance of the reflected type can be + * converted to it. + * + * @tparam To Type of the conversion function to assign to the meta type. + * @return A meta factory for the parent type. + */ + template + meta_factory conv() noexcept { + using conv_type = std::remove_cv_t>; + auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast(*static_cast(instance))); }; + base_type::conv(type_id().hash(), internal::meta_conv_node{op}); + return *this; + } + + /** + * @brief Assigns a meta constructor to a meta type. + * + * Both member functions and free function can be assigned to meta types in + * the role of constructors. All that is required is that they return an + * instance of the underlying type.
+ * From a client's point of view, nothing changes if a constructor of a meta + * type is a built-in one or not. + * + * @tparam Candidate The actual function to use as a constructor. + * @tparam Policy Optional policy (no policy set by default). + * @return A meta factory for the parent type. + */ + template + meta_factory ctor() noexcept { + using descriptor = meta_function_helper_t; + static_assert(Policy::template value, "Invalid return type for the given policy"); + static_assert(std::is_same_v>, Type>, "The function doesn't return an object of the required type"); + base_type::ctor(type_id().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg, &meta_construct}); + return *this; + } + + /** + * @brief Assigns a meta constructor to a meta type. + * + * A meta constructor is uniquely identified by the types of its arguments + * and is such that there exists an actual constructor of the underlying + * type that can be invoked with parameters whose types are those given. + * + * @tparam Args Types of arguments to use to construct an instance. + * @return A meta factory for the parent type. + */ + template + meta_factory ctor() noexcept { + // default constructor is already implicitly generated, no need for redundancy + if constexpr(sizeof...(Args) != 0u) { + using descriptor = meta_function_helper_t; + base_type::ctor(type_id().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg, &meta_construct}); + } + + return *this; + } + + /** + * @brief Assigns a meta destructor to a meta type. + * + * Both free functions and member functions can be assigned to meta types in + * the role of destructors.
+ * The signature of a free function should be identical to the following: + * + * @code{.cpp} + * void(Type &); + * @endcode + * + * Member functions should not take arguments instead.
+ * The purpose is to give users the ability to free up resources that + * require special treatment before an object is actually destroyed. + * + * @tparam Func The actual function to use as a destructor. + * @return A meta factory for the parent type. + */ + template + meta_factory dtor() noexcept { + static_assert(std::is_invocable_v, "The function doesn't accept an object of the type provided"); + auto *const op = +[](void *instance) { std::invoke(Func, *static_cast(instance)); }; + base_type::dtor(internal::meta_dtor_node{op}); + return *this; + } + + /** + * @brief Assigns a meta data to a meta type. + * + * Both data members and static and global variables, as well as constants + * of any kind, can be assigned to a meta type.
+ * From a client's point of view, all the variables associated with the + * reflected object will appear as if they were part of the type itself. + * + * @tparam Data The actual variable to attach to the meta type. + * @tparam Policy Optional policy (no policy set by default). + * @param id Unique identifier. + * @return A meta factory for the parent type. + */ + template + meta_factory data(const id_type id) noexcept { + if constexpr(std::is_member_object_pointer_v) { + using data_type = std::invoke_result_t; + static_assert(Policy::template value, "Invalid return type for the given policy"); + + base_type::data( + id, + internal::meta_data_node{ + /* this is never static */ + std::is_const_v> ? internal::meta_traits::is_const : internal::meta_traits::is_none, + 1u, + &internal::resolve>>, + &meta_arg>>>, + &meta_setter, + &meta_getter}); + } else { + using data_type = std::remove_pointer_t; + + if constexpr(std::is_pointer_v) { + static_assert(Policy::template value, "Invalid return type for the given policy"); + } else { + static_assert(Policy::template value, "Invalid return type for the given policy"); + } + + base_type::data( + id, + internal::meta_data_node{ + ((std::is_same_v>> || std::is_const_v>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static, + 1u, + &internal::resolve>>, + &meta_arg>>>, + &meta_setter, + &meta_getter}); + } + + return *this; + } + + /** + * @brief Assigns a meta data to a meta type by means of its setter and + * getter. + * + * Setters and getters can be either free functions, member functions or a + * mix of them.
+ * In case of free functions, setters and getters must accept a reference to + * an instance of the parent type as their first argument. A setter has then + * an extra argument of a type convertible to that of the parameter to + * set.
+ * In case of member functions, getters have no arguments at all, while + * setters has an argument of a type convertible to that of the parameter to + * set. + * + * @tparam Setter The actual function to use as a setter. + * @tparam Getter The actual function to use as a getter. + * @tparam Policy Optional policy (no policy set by default). + * @param id Unique identifier. + * @return A meta factory for the parent type. + */ + template + meta_factory data(const id_type id) noexcept { + using data_type = std::invoke_result_t; + static_assert(Policy::template value, "Invalid return type for the given policy"); + + if constexpr(std::is_same_v) { + base_type::data( + id, + internal::meta_data_node{ + /* this is never static */ + internal::meta_traits::is_const, + 0u, + &internal::resolve>>, + &meta_arg>, + &meta_setter, + &meta_getter}); + } else { + using args_type = typename meta_function_helper_t::args_type; + + base_type::data( + id, + internal::meta_data_node{ + /* this is never static nor const */ + internal::meta_traits::is_none, + 1u, + &internal::resolve>>, + &meta_arg>>, + &meta_setter, + &meta_getter}); + } + + return *this; + } + + /** + * @brief Assigns a meta data to a meta type by means of its setters and + * getter. + * + * Multi-setter support for meta data members. All setters are tried in the + * order of definition before returning to the caller.
+ * Setters can be either free functions, member functions or a mix of them + * and are provided via a `value_list` type. + * + * @sa data + * + * @tparam Setter The actual functions to use as setters. + * @tparam Getter The actual getter function. + * @tparam Policy Optional policy (no policy set by default). + * @param id Unique identifier. + * @return A meta factory for the parent type. + */ + template + meta_factory data(const id_type id) noexcept { + data(id, std::make_index_sequence{}); + return *this; + } + + /** + * @brief Assigns a meta function to a meta type. + * + * Both member functions and free functions can be assigned to a meta + * type.
+ * From a client's point of view, all the functions associated with the + * reflected object will appear as if they were part of the type itself. + * + * @tparam Candidate The actual function to attach to the meta type. + * @tparam Policy Optional policy (no policy set by default). + * @param id Unique identifier. + * @return A meta factory for the parent type. + */ + template + meta_factory func(const id_type id) noexcept { + using descriptor = meta_function_helper_t; + static_assert(Policy::template value, "Invalid return type for the given policy"); + + base_type::func( + id, + internal::meta_func_node{ + (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none), + descriptor::args_type::size, + &internal::resolve, void, std::remove_cv_t>>>, + &meta_arg, + &meta_invoke}); + + return *this; + } + + /** + * @brief Assigns a property to the last created meta object. + * + * Both the key and the value (if any) must be at least copy constructible. + * + * @tparam Value Optional type of the property value. + * @param id Property key. + * @param value Optional property value. + * @return A meta factory for the parent type. + */ + template + meta_factory prop(id_type id, [[maybe_unused]] Value &&...value) { + if constexpr(sizeof...(Value) == 0u) { + base_type::prop(id, internal::meta_prop_node{&internal::resolve}); + } else { + base_type::prop(id, internal::meta_prop_node{&internal::resolve>..., std::make_shared>(std::forward(value))...}); + } + + return *this; + } + + /** + * @brief Sets traits on the last created meta object. + * + * The assigned value must be an enum and intended as a bitmask. + * + * @tparam Value Type of the traits value. + * @param value Traits value. + * @return A meta factory for the parent type. + */ + template + meta_factory traits(const Value value) { + static_assert(std::is_enum_v, "Invalid enum type"); + base_type::traits(internal::user_to_meta_traits(value)); + return *this; + } + + /** + * @brief Sets user defined data that will never be used by the library. + * @tparam Value Type of user defined data to store. + * @tparam Args Types of arguments to use to construct the user data. + * @param args Parameters to use to initialize the user data. + * @return A meta factory for the parent type. + */ + template + meta_factory custom(Args &&...args) { + base_type::custom(internal::meta_custom_node{type_id().hash(), std::make_shared(std::forward(args)...)}); + return *this; + } +}; + +/** + * @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. + * + * @tparam Type Type to reflect. + * @param ctx The context into which to construct meta types. + * @return A meta factory for the given type. + */ +template +[[nodiscard]] auto meta(meta_ctx &ctx) noexcept { + auto &&context = internal::meta_context::from(ctx); + // make sure the type exists in the context before returning a factory + context.value.try_emplace(type_id().hash(), internal::resolve(context)); + return meta_factory{ctx}; +} + +/** + * @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. + * + * @tparam Type Type to reflect. + * @return A meta factory for the given type. + */ +template +[[nodiscard]] auto meta() noexcept { + return meta(locator::value_or()); +} + +/** + * @brief Resets a type and all its parts. + * + * Resets a type and all its data members, member functions and properties, as + * well as its constructors, destructors and conversion functions if any.
+ * Base classes aren't reset but the link between the two types is removed. + * + * The type is also removed from the set of searchable types. + * + * @param id Unique identifier. + * @param ctx The context from which to reset meta types. + */ +inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept { + auto &&context = internal::meta_context::from(ctx); + + for(auto it = context.value.begin(); it != context.value.end();) { + if(it->second.id == id) { + it = context.value.erase(it); + } else { + ++it; + } + } +} + +/** + * @brief Resets a type and all its parts. + * + * Resets a type and all its data members, member functions and properties, as + * well as its constructors, destructors and conversion functions if any.
+ * Base classes aren't reset but the link between the two types is removed. + * + * The type is also removed from the set of searchable types. + * + * @param id Unique identifier. + */ +inline void meta_reset(const id_type id) noexcept { + meta_reset(locator::value_or(), id); +} + +/** + * @brief Resets a type and all its parts. + * + * @sa meta_reset + * + * @tparam Type Type to reset. + * @param ctx The context from which to reset meta types. + */ +template +void meta_reset(meta_ctx &ctx) noexcept { + internal::meta_context::from(ctx).value.erase(type_id().hash()); +} + +/** + * @brief Resets a type and all its parts. + * + * @sa meta_reset + * + * @tparam Type Type to reset. + */ +template +void meta_reset() noexcept { + meta_reset(locator::value_or()); +} + +/** + * @brief Resets all meta types. + * + * @sa meta_reset + * + * @param ctx The context from which to reset meta types. + */ +inline void meta_reset(meta_ctx &ctx) noexcept { + internal::meta_context::from(ctx).value.clear(); +} + +/** + * @brief Resets all meta types. + * + * @sa meta_reset + */ +inline void meta_reset() noexcept { + meta_reset(locator::value_or()); +} + +} // namespace entt + +#endif -- cgit