From ded6fd2e03c3e60aa0807cd88ebebfbf5baec308 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:31:35 +0100 Subject: [PATCH 01/29] Upgraded entt Deleted the header only entt lib and added the full and latest library to the dependencies list --- .gitmodules | 3 + Nuake/dependencies/entt | 1 + Nuake/src/Vendors/entt/entt.hpp | 44741 ------------------------------ premake5.lua | 12 +- 4 files changed, 13 insertions(+), 44744 deletions(-) create mode 160000 Nuake/dependencies/entt delete mode 100644 Nuake/src/Vendors/entt/entt.hpp diff --git a/.gitmodules b/.gitmodules index d571900e..8afa4461 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,3 +31,6 @@ [submodule "Nuake/dependencies/freetype"] path = Nuake/dependencies/freetype url = https://github.com/freetype/freetype.git +[submodule "Nuake/dependencies/entt"] + path = Nuake/dependencies/entt + url = https://github.com/skypjack/entt.git diff --git a/Nuake/dependencies/entt b/Nuake/dependencies/entt new file mode 160000 index 00000000..156bc470 --- /dev/null +++ b/Nuake/dependencies/entt @@ -0,0 +1 @@ +Subproject commit 156bc470cea3a49cdbddd0ae74db77a8c207bbe8 diff --git a/Nuake/src/Vendors/entt/entt.hpp b/Nuake/src/Vendors/entt/entt.hpp deleted file mode 100644 index f089a319..00000000 --- a/Nuake/src/Vendors/entt/entt.hpp +++ /dev/null @@ -1,44741 +0,0 @@ -// #include "config/version.h" -#ifndef ENTT_CONFIG_VERSION_H -#define ENTT_CONFIG_VERSION_H - - -#define ENTT_VERSION_MAJOR 3 -#define ENTT_VERSION_MINOR 7 -#define ENTT_VERSION_PATCH 1 - - -#endif - -// #include "core/algorithm.hpp" -#ifndef ENTT_CORE_ALGORITHM_HPP -#define ENTT_CORE_ALGORITHM_HPP - - -#include -#include -#include -#include -#include -// #include "utility.hpp" -#ifndef ENTT_CORE_UTILITY_HPP -#define ENTT_CORE_UTILITY_HPP - - -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - - - -namespace entt { - - -/*! @brief Identity function object (waiting for C++20). */ -struct identity { - /** - * @brief Returns its argument unchanged. - * @tparam Type Type of the argument. - * @param value The actual argument. - * @return The submitted value as-is. - */ - template - [[nodiscard]] constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT { - return std::forward(value); - } -}; - - -/** - * @brief Constant utility to disambiguate overloaded members of a class. - * @tparam Type Type of the desired overload. - * @tparam Class Type of class to which the member belongs. - * @param member A valid pointer to a member. - * @return Pointer to the member. - */ -template -[[nodiscard]] constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; } - - -/** - * @brief Constant utility to disambiguate overloaded functions. - * @tparam Func Function type of the desired overload. - * @param func A valid pointer to a function. - * @return Pointer to the function. - */ -template -[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; } - - -/** - * @brief Helper type for visitors. - * @tparam Func Types of function objects. - */ -template -struct overloaded: Func... { - using Func::operator()...; -}; - - -/** - * @brief Deduction guide. - * @tparam Func Types of function objects. - */ -template -overloaded(Func...) --> overloaded; - - -/** - * @brief Basic implementation of a y-combinator. - * @tparam Func Type of a potentially recursive function. - */ -template -struct y_combinator { - /** - * @brief Constructs a y-combinator from a given function. - * @param recursive A potentially recursive function. - */ - y_combinator(Func recursive): - func{std::move(recursive)} - {} - - /** - * @brief Invokes a y-combinator and therefore its underlying function. - * @tparam Args Types of arguments to use to invoke the underlying function. - * @param args Parameters to use to invoke the underlying function. - * @return Return value of the underlying function, if any. - */ - template - decltype(auto) operator()(Args &&... args) const { - return func(*this, std::forward(args)...); - } - - /*! @copydoc operator()() */ - template - decltype(auto) operator()(Args &&... args) { - return func(*this, std::forward(args)...); - } - -private: - Func func; -}; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Function object to wrap `std::sort` in a class type. - * - * Unfortunately, `std::sort` cannot be passed as template argument to a class - * template or a function template.
- * This class fills the gap by wrapping some flavors of `std::sort` in a - * function object. - */ -struct std_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam It Type of random access iterator. - * @tparam Compare Type of comparison function object. - * @tparam Args Types of arguments to forward to the sort function. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - * @param args Arguments to forward to the sort function, if any. - */ - template, typename... Args> - void operator()(It first, It last, Compare compare = Compare{}, Args &&... args) const { - std::sort(std::forward(args)..., std::move(first), std::move(last), std::move(compare)); - } -}; - - -/*! @brief Function object for performing insertion sort. */ -struct insertion_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam It Type of random access iterator. - * @tparam Compare Type of comparison function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - */ - template> - void operator()(It first, It last, Compare compare = Compare{}) const { - if(first < last) { - for(auto it = first + 1; it < last; ++it) { - auto value = std::move(*it); - auto pre = it; - - for(; pre > first && compare(value, *(pre-1)); --pre) { - *pre = std::move(*(pre-1)); - } - - *pre = std::move(value); - } - } - } -}; - - -/** - * @brief Function object for performing LSD radix sort. - * @tparam Bit Number of bits processed per pass. - * @tparam N Maximum number of bits to sort. - */ -template -struct radix_sort { - static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass"); - - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given _getter_ to access the - * actual data to be sorted. - * - * This implementation is inspired by the online book - * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). - * - * @tparam It Type of random access iterator. - * @tparam Getter Type of _getter_ function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param getter A valid _getter_ function object. - */ - template - void operator()(It first, It last, Getter getter = Getter{}) const { - if(first < last) { - static constexpr auto mask = (1 << Bit) - 1; - static constexpr auto buckets = 1 << Bit; - static constexpr auto passes = N / Bit; - - using value_type = typename std::iterator_traits::value_type; - std::vector aux(std::distance(first, last)); - - auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) { - std::size_t index[buckets]{}; - std::size_t count[buckets]{}; - - for(auto it = from; it != to; ++it) { - ++count[(getter(*it) >> start) & mask]; - } - - for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { - index[pos + 1u] = index[pos] + count[pos]; - } - - for(auto it = from; it != to; ++it) { - out[index[(getter(*it) >> start) & mask]++] = std::move(*it); - } - }; - - for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) { - part(first, last, aux.begin(), pass * Bit); - part(aux.begin(), aux.end(), first, (pass + 1) * Bit); - } - - if constexpr(passes & 1) { - part(first, last, aux.begin(), (passes - 1) * Bit); - std::move(aux.begin(), aux.end(), first); - } - } - } -}; - - -} - - -#endif - -// #include "core/any.hpp" -#ifndef ENTT_CORE_ANY_HPP -#define ENTT_CORE_ANY_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - -// #include "type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "hashed_string.hpp" -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct fnv1a_traits; - - -template<> -struct fnv1a_traits { - using type = std::uint32_t; - static constexpr std::uint32_t offset = 2166136261; - static constexpr std::uint32_t prime = 16777619; -}; - - -template<> -struct fnv1a_traits { - using type = std::uint64_t; - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string { - using traits_type = internal::fnv1a_traits; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {} - const Char *str; - }; - - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT { - auto value = traits_type::offset; - - while(*curr != 0) { - value = (value ^ static_cast(*(curr++))) * traits_type::prime; - } - - return value; - } - -public: - /*! @brief Character type. */ - using value_type = Char; - /*! @brief Unsigned integer type. */ - using hash_type = id_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifer. - * @param size Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT { - id_type partial{traits_type::offset}; - while(size--) { partial = (partial^(str++)[0])*traits_type::prime; } - return partial; - } - - /** - * @brief Returns directly the numeric representation of a string. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * const auto value = basic_hashed_string::to_value("my.png"); - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - * @return The numeric representation of the string. - */ - template - [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT { - return helper(str); - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { - return helper(wrapper.str); - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() ENTT_NOEXCEPT - : str{nullptr}, hash{} - {} - - /** - * @brief Constructs a hashed string from an array of const characters. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * basic_hashed_string hs{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param curr Human-readable identifer. - */ - template - constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT - : str{curr}, hash{helper(curr)} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT - : str{wrapper.str}, hash{helper(wrapper.str)} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - [[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT { - return str; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { - return hash; - } - - /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const value_type *str; - hash_type hash; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the character type of the hashed string directly from a - * human-readable identifer provided to the constructor. - * - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ -template -basic_hashed_string(const Char (&str)[N]) --> basic_hashed_string; - - -/** - * @brief Compares two hashed strings. - * @tparam Char Character type. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const basic_hashed_string &lhs, const basic_hashed_string &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - - -inline namespace literals { - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_string{str}; -} - - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_wstring{str}; -} - - -} - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief A SBO friendly, type-safe container for single values of any type. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_any { - enum class operation { COPY, MOVE, DTOR, COMP, ADDR, CADDR, REF, CREF, TYPE }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void *(const operation, const basic_any &, const void *); - - template - static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v; - - template - [[nodiscard]] static bool compare(const void *lhs, const void *rhs) { - if constexpr(!std::is_function_v && is_equality_comparable_v) { - return *static_cast(lhs) == *static_cast(rhs); - } else { - return lhs == rhs; - } - } - - template - static Type & as(const void *to) { - return *const_cast(static_cast(to)); - } - - template - static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(std::is_void_v) { - switch(op) { - case operation::COPY: - case operation::MOVE: - case operation::REF: - case operation::CREF: - as(to).vtable = from.vtable; - break; - default: - break; - } - } else if constexpr(std::is_lvalue_reference_v) { - using base_type = std::decay_t; - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to) = *static_cast(from.instance); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - as(to).vtable = from.vtable; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - as(to).vtable = from.vtable; - break; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = std::exchange(as(&from).instance, nullptr); - as(to).vtable = from.vtable; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } - - return nullptr; - } - - template - void initialize([[maybe_unused]] Args &&... args) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - if constexpr(std::is_aggregate_v) { - new (&storage) Type{std::forward(args)...}; - } else { - new (&storage) Type(std::forward(args)...); - } - } else { - if constexpr(std::is_aggregate_v) { - instance = new Type{std::forward(args)...}; - } else { - instance = new Type(std::forward(args)...); - } - } - } - } - -public: - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : basic_any{std::in_place_type} - {} - - /** - * @brief Constructs an any by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_any(std::in_place_type_t, Args &&... args) - : instance{}, - vtable{&basic_vtable} - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs an any that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - basic_any(std::reference_wrapper value) ENTT_NOEXCEPT - : basic_any{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs an any from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template, basic_any>>> - basic_any(Type &&value) - : basic_any{std::in_place_type>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any &other) - : basic_any{std::in_place_type} - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{std::in_place_type} - { - other.vtable(operation::MOVE, other, this); - } - - /*! @brief Frees the internal storage, whatever it means. */ - ~basic_any() { - vtable(operation::DTOR, *this, nullptr); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This any object. - */ - basic_any & operator=(const basic_any &other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::COPY, other, this); - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This any object. - */ - basic_any & operator=(basic_any &&other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { - emplace(value.get()); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - std::enable_if_t, basic_any>, basic_any &> - operator=(Type &&value) { - emplace>(std::forward(value)); - return *this; - } - - /** - * @brief Returns the type of the contained object. - * @return The type of the contained object, if any. - */ - [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info{}; - vtable(operation::TYPE, *this, &info); - return info; - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return vtable(operation::CADDR, *this, nullptr); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return const_cast(vtable(operation::ADDR, *this, nullptr)); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - } - - /** - * @brief Returns false if a wrapper is empty, true otherwise. - * @return False if the wrapper is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(vtable(operation::CADDR, *this, nullptr) == nullptr); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - bool operator==(const basic_any &other) const ENTT_NOEXCEPT { - return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); - } - - /** - * @brief Aliasing constructor. - * @return An any that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::REF, *this, &ref); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::CREF, *this, &ref); - return ref; - } - -private: - union { const void *instance; storage_type storage; }; - vtable_type *vtable; -}; - - -/** - * @brief Checks if two wrappers differ in their content. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param lhs A wrapper, either empty or not. - * @param rhs A wrapper, either empty or not. - * @return True if the two wrappers differ in their content, false otherwise. - */ -template -[[nodiscard]] inline bool operator!=(const basic_any &lhs, const basic_any &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Performs type-safe access to the contained object. - * @tparam Type Type to which conversion is required. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param data Target any object. - * @return The element converted to the requested type. - */ -template -Type any_cast(const basic_any &data) ENTT_NOEXCEPT { - const auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &&data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(std::move(*instance)); -} - - -/*! @copydoc any_cast */ -template -const Type * any_cast(const basic_any *data) ENTT_NOEXCEPT { - return (data->type() == type_id() ? static_cast(data->data()) : nullptr); -} - - -/*! @copydoc any_cast */ -template -Type * any_cast(basic_any *data) ENTT_NOEXCEPT { - // last attempt to make wrappers for const references return their values - return (data->type() == type_id() ? static_cast(static_cast, Type> *>(data)->data()) : nullptr); -} - - -} - - -#endif - -// #include "core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "core/family.hpp" -#ifndef ENTT_CORE_FAMILY_HPP -#define ENTT_CORE_FAMILY_HPP - - -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Dynamic identifier generator. - * - * Utility class template that can be used to assign unique identifiers to types - * at runtime. Use different specializations to create separate sets of - * identifiers. - */ -template -class family { - inline static ENTT_MAYBE_ATOMIC(id_type) identifier{}; - -public: - /*! @brief Unsigned integer type. */ - using family_type = id_type; - - /*! @brief Statically generated unique identifier for the given type. */ - template - // at the time I'm writing, clang crashes during compilation if auto is used instead of family_type - inline static const family_type type = identifier++; -}; - - -} - - -#endif - -// #include "core/hashed_string.hpp" -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct fnv1a_traits; - - -template<> -struct fnv1a_traits { - using type = std::uint32_t; - static constexpr std::uint32_t offset = 2166136261; - static constexpr std::uint32_t prime = 16777619; -}; - - -template<> -struct fnv1a_traits { - using type = std::uint64_t; - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string { - using traits_type = internal::fnv1a_traits; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {} - const Char *str; - }; - - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT { - auto value = traits_type::offset; - - while(*curr != 0) { - value = (value ^ static_cast(*(curr++))) * traits_type::prime; - } - - return value; - } - -public: - /*! @brief Character type. */ - using value_type = Char; - /*! @brief Unsigned integer type. */ - using hash_type = id_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifer. - * @param size Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT { - id_type partial{traits_type::offset}; - while(size--) { partial = (partial^(str++)[0])*traits_type::prime; } - return partial; - } - - /** - * @brief Returns directly the numeric representation of a string. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * const auto value = basic_hashed_string::to_value("my.png"); - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - * @return The numeric representation of the string. - */ - template - [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT { - return helper(str); - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { - return helper(wrapper.str); - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() ENTT_NOEXCEPT - : str{nullptr}, hash{} - {} - - /** - * @brief Constructs a hashed string from an array of const characters. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * basic_hashed_string hs{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param curr Human-readable identifer. - */ - template - constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT - : str{curr}, hash{helper(curr)} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT - : str{wrapper.str}, hash{helper(wrapper.str)} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - [[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT { - return str; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { - return hash; - } - - /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const value_type *str; - hash_type hash; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the character type of the hashed string directly from a - * human-readable identifer provided to the constructor. - * - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ -template -basic_hashed_string(const Char (&str)[N]) --> basic_hashed_string; - - -/** - * @brief Compares two hashed strings. - * @tparam Char Character type. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const basic_hashed_string &lhs, const basic_hashed_string &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - - -inline namespace literals { - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_string{str}; -} - - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_wstring{str}; -} - - -} - - -} - - -#endif - -// #include "core/ident.hpp" -#ifndef ENTT_CORE_IDENT_HPP -#define ENTT_CORE_IDENT_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - -// #include "type_traits.hpp" - - - -namespace entt { - - -/** - * @brief Types identifiers. - * - * Variable template used to generate identifiers at compile-time for the given - * types. Use the `get` member function to know what's the identifier associated - * to the specific type. - * - * @note - * Identifiers are constant expression and can be used in any context where such - * an expression is required. As an example: - * @code{.cpp} - * using id = entt::identifier; - * - * switch(a_type_identifier) { - * case id::type: - * // ... - * break; - * case id::type: - * // ... - * break; - * default: - * // ... - * } - * @endcode - * - * @tparam Types List of types for which to generate identifiers. - */ -template -class identifier { - template - [[nodiscard]] static constexpr id_type get(std::index_sequence) { - static_assert(std::disjunction_v...>, "Invalid type"); - return (0 + ... + (std::is_same_v...>>> ? id_type{Index} : id_type{})); - } - -public: - /*! @brief Unsigned integer type. */ - using identifier_type = id_type; - - /*! @brief Statically generated unique identifier for the given type. */ - template - static constexpr identifier_type type = get>(std::index_sequence_for{}); -}; - - -} - - -#endif - -// #include "core/monostate.hpp" -#ifndef ENTT_CORE_MONOSTATE_HPP -#define ENTT_CORE_MONOSTATE_HPP - - -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Minimal implementation of the monostate pattern. - * - * A minimal, yet complete configuration system built on top of the monostate - * pattern. Thread safe by design, it works only with basic types like `int`s or - * `bool`s.
- * Multiple types and therefore more than one value can be associated with a - * single key. Because of this, users must pay attention to use the same type - * both during an assignment and when they try to read back their data. - * Otherwise, they can incur in unexpected results. - */ -template -struct monostate { - /** - * @brief Assigns a value of a specific type to a given key. - * @tparam Type Type of the value to assign. - * @param val User data to assign to the given key. - */ - template - void operator=(Type val) const ENTT_NOEXCEPT { - value = val; - } - - /** - * @brief Gets a value of a specific type for a given key. - * @tparam Type Type of the value to get. - * @return Stored value, if any. - */ - template - operator Type() const ENTT_NOEXCEPT { - return value; - } - -private: - template - inline static ENTT_MAYBE_ATOMIC(Type) value{}; -}; - - -/** - * @brief Helper variable template. - * @tparam Value Value used to differentiate between different variables. - */ -template -inline monostate monostate_v = {}; - - -} - - -#endif - -// #include "core/type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" - -// #include "hashed_string.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - -// #include "core/utility.hpp" -#ifndef ENTT_CORE_UTILITY_HPP -#define ENTT_CORE_UTILITY_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -/*! @brief Identity function object (waiting for C++20). */ -struct identity { - /** - * @brief Returns its argument unchanged. - * @tparam Type Type of the argument. - * @param value The actual argument. - * @return The submitted value as-is. - */ - template - [[nodiscard]] constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT { - return std::forward(value); - } -}; - - -/** - * @brief Constant utility to disambiguate overloaded members of a class. - * @tparam Type Type of the desired overload. - * @tparam Class Type of class to which the member belongs. - * @param member A valid pointer to a member. - * @return Pointer to the member. - */ -template -[[nodiscard]] constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; } - - -/** - * @brief Constant utility to disambiguate overloaded functions. - * @tparam Func Function type of the desired overload. - * @param func A valid pointer to a function. - * @return Pointer to the function. - */ -template -[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; } - - -/** - * @brief Helper type for visitors. - * @tparam Func Types of function objects. - */ -template -struct overloaded: Func... { - using Func::operator()...; -}; - - -/** - * @brief Deduction guide. - * @tparam Func Types of function objects. - */ -template -overloaded(Func...) --> overloaded; - - -/** - * @brief Basic implementation of a y-combinator. - * @tparam Func Type of a potentially recursive function. - */ -template -struct y_combinator { - /** - * @brief Constructs a y-combinator from a given function. - * @param recursive A potentially recursive function. - */ - y_combinator(Func recursive): - func{std::move(recursive)} - {} - - /** - * @brief Invokes a y-combinator and therefore its underlying function. - * @tparam Args Types of arguments to use to invoke the underlying function. - * @param args Parameters to use to invoke the underlying function. - * @return Return value of the underlying function, if any. - */ - template - decltype(auto) operator()(Args &&... args) const { - return func(*this, std::forward(args)...); - } - - /*! @copydoc operator()() */ - template - decltype(auto) operator()(Args &&... args) { - return func(*this, std::forward(args)...); - } - -private: - Func func; -}; - - -} - - -#endif - -// #include "entity/entity.hpp" -#ifndef ENTT_ENTITY_ENTITY_HPP -#define ENTT_ENTITY_ENTITY_HPP - - -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - - - -namespace entt { - - -/** - * @brief Entity traits. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is an accepted entity type. - */ -template -struct entt_traits; - - -/** - * @brief Entity traits for enumeration types. - * @tparam Type The type to check. - */ -template -struct entt_traits>> - : entt_traits> -{}; - - -/** - * @brief Entity traits for a 32 bits entity identifier. - * - * A 32 bits entity identifier guarantees: - * - * * 20 bits for the entity number (suitable for almost all the games). - * * 12 bit for the version (resets in [0-4095]). - */ -template<> -struct entt_traits { - /*! @brief Underlying entity type. */ - using entity_type = std::uint32_t; - /*! @brief Underlying version type. */ - using version_type = std::uint16_t; - /*! @brief Difference type. */ - using difference_type = std::int64_t; - - /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr entity_type entity_mask = 0xFFFFF; - /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr entity_type version_mask = 0xFFF; - /*! @brief Extent of the entity number within an identifier. */ - static constexpr std::size_t entity_shift = 20u; -}; - - -/** - * @brief Entity traits for a 64 bits entity identifier. - * - * A 64 bits entity identifier guarantees: - * - * * 32 bits for the entity number (an indecently large number). - * * 32 bit for the version (an indecently large number). - */ -template<> -struct entt_traits { - /*! @brief Underlying entity type. */ - using entity_type = std::uint64_t; - /*! @brief Underlying version type. */ - using version_type = std::uint32_t; - /*! @brief Difference type. */ - using difference_type = std::int64_t; - - /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr entity_type entity_mask = 0xFFFFFFFF; - /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr entity_type version_mask = 0xFFFFFFFF; - /*! @brief Extent of the entity number within an identifier. */ - static constexpr std::size_t entity_shift = 32u; -}; - - -/** - * @brief Converts an entity type to its underlying type. - * @tparam Entity The value type. - * @param entity The value to convert. - * @return The integral representation of the given value. - */ -template -[[nodiscard]] constexpr auto to_integral(const Entity entity) ENTT_NOEXCEPT { - return static_cast::entity_type>(entity); -} - - -/*! @brief Null object for all entity identifiers. */ -struct null_t { - /** - * @brief Converts the null object to identifiers of any type. - * @tparam Entity Type of entity identifier. - * @return The null representation for the given identifier. - */ - template - [[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT { - return Entity{entt_traits::entity_mask}; - } - - /** - * @brief Compares two null objects. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==(const null_t &) const ENTT_NOEXCEPT { - return true; - } - - /** - * @brief Compares two null objects. - * @return False in all cases. - */ - [[nodiscard]] constexpr bool operator!=(const null_t &) const ENTT_NOEXCEPT { - return false; - } - - /** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @return False if the two elements differ, true otherwise. - */ - template - [[nodiscard]] constexpr bool operator==(const Entity &entity) const ENTT_NOEXCEPT { - return (to_integral(entity) & entt_traits::entity_mask) == to_integral(static_cast(*this)); - } - - /** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @return True if the two elements differ, false otherwise. - */ - template - [[nodiscard]] constexpr bool operator!=(const Entity &entity) const ENTT_NOEXCEPT { - return !(entity == *this); - } -}; - - -/** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @param other A null object yet to be converted. - * @return False if the two elements differ, true otherwise. - */ -template -[[nodiscard]] constexpr bool operator==(const Entity &entity, const null_t &other) ENTT_NOEXCEPT { - return other.operator==(entity); -} - - -/** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @param other A null object yet to be converted. - * @return True if the two elements differ, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const Entity &entity, const null_t &other) ENTT_NOEXCEPT { - return !(other == entity); -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Compile-time constant for null entities. - * - * There exist implicit conversions from this variable to entity identifiers of - * any allowed type. Similarly, there exist comparision operators between the - * null entity and any other entity identifier. - */ -inline constexpr null_t null{}; - - -} - - -#endif - -// #include "entity/group.hpp" -#ifndef ENTT_ENTITY_GROUP_HPP -#define ENTT_ENTITY_GROUP_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - -// #include "entity.hpp" -#ifndef ENTT_ENTITY_ENTITY_HPP -#define ENTT_ENTITY_ENTITY_HPP - - -#include -#include -#include -// #include "../config/config.h" - - - -namespace entt { - - -/** - * @brief Entity traits. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is an accepted entity type. - */ -template -struct entt_traits; - - -/** - * @brief Entity traits for enumeration types. - * @tparam Type The type to check. - */ -template -struct entt_traits>> - : entt_traits> -{}; - - -/** - * @brief Entity traits for a 32 bits entity identifier. - * - * A 32 bits entity identifier guarantees: - * - * * 20 bits for the entity number (suitable for almost all the games). - * * 12 bit for the version (resets in [0-4095]). - */ -template<> -struct entt_traits { - /*! @brief Underlying entity type. */ - using entity_type = std::uint32_t; - /*! @brief Underlying version type. */ - using version_type = std::uint16_t; - /*! @brief Difference type. */ - using difference_type = std::int64_t; - - /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr entity_type entity_mask = 0xFFFFF; - /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr entity_type version_mask = 0xFFF; - /*! @brief Extent of the entity number within an identifier. */ - static constexpr std::size_t entity_shift = 20u; -}; - - -/** - * @brief Entity traits for a 64 bits entity identifier. - * - * A 64 bits entity identifier guarantees: - * - * * 32 bits for the entity number (an indecently large number). - * * 32 bit for the version (an indecently large number). - */ -template<> -struct entt_traits { - /*! @brief Underlying entity type. */ - using entity_type = std::uint64_t; - /*! @brief Underlying version type. */ - using version_type = std::uint32_t; - /*! @brief Difference type. */ - using difference_type = std::int64_t; - - /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr entity_type entity_mask = 0xFFFFFFFF; - /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr entity_type version_mask = 0xFFFFFFFF; - /*! @brief Extent of the entity number within an identifier. */ - static constexpr std::size_t entity_shift = 32u; -}; - - -/** - * @brief Converts an entity type to its underlying type. - * @tparam Entity The value type. - * @param entity The value to convert. - * @return The integral representation of the given value. - */ -template -[[nodiscard]] constexpr auto to_integral(const Entity entity) ENTT_NOEXCEPT { - return static_cast::entity_type>(entity); -} - - -/*! @brief Null object for all entity identifiers. */ -struct null_t { - /** - * @brief Converts the null object to identifiers of any type. - * @tparam Entity Type of entity identifier. - * @return The null representation for the given identifier. - */ - template - [[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT { - return Entity{entt_traits::entity_mask}; - } - - /** - * @brief Compares two null objects. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==(const null_t &) const ENTT_NOEXCEPT { - return true; - } - - /** - * @brief Compares two null objects. - * @return False in all cases. - */ - [[nodiscard]] constexpr bool operator!=(const null_t &) const ENTT_NOEXCEPT { - return false; - } - - /** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @return False if the two elements differ, true otherwise. - */ - template - [[nodiscard]] constexpr bool operator==(const Entity &entity) const ENTT_NOEXCEPT { - return (to_integral(entity) & entt_traits::entity_mask) == to_integral(static_cast(*this)); - } - - /** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @return True if the two elements differ, false otherwise. - */ - template - [[nodiscard]] constexpr bool operator!=(const Entity &entity) const ENTT_NOEXCEPT { - return !(entity == *this); - } -}; - - -/** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @param other A null object yet to be converted. - * @return False if the two elements differ, true otherwise. - */ -template -[[nodiscard]] constexpr bool operator==(const Entity &entity, const null_t &other) ENTT_NOEXCEPT { - return other.operator==(entity); -} - - -/** - * @brief Compares a null object and an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier with which to compare. - * @param other A null object yet to be converted. - * @return True if the two elements differ, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const Entity &entity, const null_t &other) ENTT_NOEXCEPT { - return !(other == entity); -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Compile-time constant for null entities. - * - * There exist implicit conversions from this variable to entity identifiers of - * any allowed type. Similarly, there exist comparision operators between the - * null entity and any other entity identifier. - */ -inline constexpr null_t null{}; - - -} - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_ENTITY_FWD_HPP -#define ENTT_ENTITY_FWD_HPP - - -// #include "../core/fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - - - -namespace entt { - - -template -class basic_sparse_set; - - -template -class basic_storage; - - -template -class basic_registry; - - -template -class basic_view; - - -template -class basic_runtime_view; - - -template -class basic_group; - - -template -class basic_observer; - - -template -class basic_organizer; - - -template -struct basic_handle; - - -template -class basic_snapshot; - - -template -class basic_snapshot_loader; - - -template -class basic_continuous_loader; - - -/*! @brief Default entity identifier. */ -enum class entity: id_type {}; - - -/*! @brief Alias declaration for the most common use case. */ -using sparse_set = basic_sparse_set; - - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using storage = basic_storage; - - -/*! @brief Alias declaration for the most common use case. */ -using registry = basic_registry; - - -/*! @brief Alias declaration for the most common use case. */ -using observer = basic_observer; - - -/*! @brief Alias declaration for the most common use case. */ -using organizer = basic_organizer; - - -/*! @brief Alias declaration for the most common use case. */ -using handle = basic_handle; - - -/*! @brief Alias declaration for the most common use case. */ -using const_handle = basic_handle; - - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using handle_view = basic_handle; - - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using const_handle_view = basic_handle; - - -/*! @brief Alias declaration for the most common use case. */ -using snapshot = basic_snapshot; - - -/*! @brief Alias declaration for the most common use case. */ -using snapshot_loader = basic_snapshot_loader; - - -/*! @brief Alias declaration for the most common use case. */ -using continuous_loader = basic_continuous_loader; - - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using view = basic_view; - - -/*! @brief Alias declaration for the most common use case. */ -using runtime_view = basic_runtime_view; - - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using group = basic_group; - - -} - - -#endif - -// #include "sparse_set.hpp" -#ifndef ENTT_ENTITY_SPARSE_SET_HPP -#define ENTT_ENTITY_SPARSE_SET_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" -#ifndef ENTT_CORE_ALGORITHM_HPP -#define ENTT_CORE_ALGORITHM_HPP - - -#include -#include -#include -#include -#include -// #include "utility.hpp" -#ifndef ENTT_CORE_UTILITY_HPP -#define ENTT_CORE_UTILITY_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -/*! @brief Identity function object (waiting for C++20). */ -struct identity { - /** - * @brief Returns its argument unchanged. - * @tparam Type Type of the argument. - * @param value The actual argument. - * @return The submitted value as-is. - */ - template - [[nodiscard]] constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT { - return std::forward(value); - } -}; - - -/** - * @brief Constant utility to disambiguate overloaded members of a class. - * @tparam Type Type of the desired overload. - * @tparam Class Type of class to which the member belongs. - * @param member A valid pointer to a member. - * @return Pointer to the member. - */ -template -[[nodiscard]] constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; } - - -/** - * @brief Constant utility to disambiguate overloaded functions. - * @tparam Func Function type of the desired overload. - * @param func A valid pointer to a function. - * @return Pointer to the function. - */ -template -[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; } - - -/** - * @brief Helper type for visitors. - * @tparam Func Types of function objects. - */ -template -struct overloaded: Func... { - using Func::operator()...; -}; - - -/** - * @brief Deduction guide. - * @tparam Func Types of function objects. - */ -template -overloaded(Func...) --> overloaded; - - -/** - * @brief Basic implementation of a y-combinator. - * @tparam Func Type of a potentially recursive function. - */ -template -struct y_combinator { - /** - * @brief Constructs a y-combinator from a given function. - * @param recursive A potentially recursive function. - */ - y_combinator(Func recursive): - func{std::move(recursive)} - {} - - /** - * @brief Invokes a y-combinator and therefore its underlying function. - * @tparam Args Types of arguments to use to invoke the underlying function. - * @param args Parameters to use to invoke the underlying function. - * @return Return value of the underlying function, if any. - */ - template - decltype(auto) operator()(Args &&... args) const { - return func(*this, std::forward(args)...); - } - - /*! @copydoc operator()() */ - template - decltype(auto) operator()(Args &&... args) { - return func(*this, std::forward(args)...); - } - -private: - Func func; -}; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Function object to wrap `std::sort` in a class type. - * - * Unfortunately, `std::sort` cannot be passed as template argument to a class - * template or a function template.
- * This class fills the gap by wrapping some flavors of `std::sort` in a - * function object. - */ -struct std_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam It Type of random access iterator. - * @tparam Compare Type of comparison function object. - * @tparam Args Types of arguments to forward to the sort function. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - * @param args Arguments to forward to the sort function, if any. - */ - template, typename... Args> - void operator()(It first, It last, Compare compare = Compare{}, Args &&... args) const { - std::sort(std::forward(args)..., std::move(first), std::move(last), std::move(compare)); - } -}; - - -/*! @brief Function object for performing insertion sort. */ -struct insertion_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam It Type of random access iterator. - * @tparam Compare Type of comparison function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - */ - template> - void operator()(It first, It last, Compare compare = Compare{}) const { - if(first < last) { - for(auto it = first + 1; it < last; ++it) { - auto value = std::move(*it); - auto pre = it; - - for(; pre > first && compare(value, *(pre-1)); --pre) { - *pre = std::move(*(pre-1)); - } - - *pre = std::move(value); - } - } - } -}; - - -/** - * @brief Function object for performing LSD radix sort. - * @tparam Bit Number of bits processed per pass. - * @tparam N Maximum number of bits to sort. - */ -template -struct radix_sort { - static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass"); - - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given _getter_ to access the - * actual data to be sorted. - * - * This implementation is inspired by the online book - * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). - * - * @tparam It Type of random access iterator. - * @tparam Getter Type of _getter_ function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param getter A valid _getter_ function object. - */ - template - void operator()(It first, It last, Getter getter = Getter{}) const { - if(first < last) { - static constexpr auto mask = (1 << Bit) - 1; - static constexpr auto buckets = 1 << Bit; - static constexpr auto passes = N / Bit; - - using value_type = typename std::iterator_traits::value_type; - std::vector aux(std::distance(first, last)); - - auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) { - std::size_t index[buckets]{}; - std::size_t count[buckets]{}; - - for(auto it = from; it != to; ++it) { - ++count[(getter(*it) >> start) & mask]; - } - - for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { - index[pos + 1u] = index[pos] + count[pos]; - } - - for(auto it = from; it != to; ++it) { - out[index[(getter(*it) >> start) & mask]++] = std::move(*it); - } - }; - - for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) { - part(first, last, aux.begin(), pass * Bit); - part(aux.begin(), aux.end(), first, (pass + 1) * Bit); - } - - if constexpr(passes & 1) { - part(first, last, aux.begin(), (passes - 1) * Bit); - std::move(aux.begin(), aux.end(), first); - } - } - } -}; - - -} - - -#endif - -// #include "entity.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Basic sparse set implementation. - * - * Sparse set or packed array or whatever is the name users give it.
- * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a - * _packed_ one; one used for direct access through contiguous memory, the other - * one used to get the data through an extra level of indirection.
- * This is largely used by the registry to offer users the fastest access ever - * to the components. Views and groups in general are almost entirely designed - * around sparse sets. - * - * This type of data structure is widely documented in the literature and on the - * web. This is nothing more than a customized implementation suitable for the - * purpose of the framework. - * - * @note - * Internal data structures arrange elements to maximize performance. There are - * no guarantees that entities are returned in the insertion order when iterate - * a sparse set. Do not make assumption on the order in any case. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_sparse_set { - static constexpr auto page_size = ENTT_PAGE_SIZE; - - using traits_type = entt_traits; - using page_type = std::unique_ptr; - - class sparse_set_iterator final { - friend class basic_sparse_set; - - using packed_type = std::vector; - using index_type = typename traits_type::difference_type; - - sparse_set_iterator(const packed_type &ref, const index_type idx) ENTT_NOEXCEPT - : packed{&ref}, index{idx} - {} - - public: - using difference_type = index_type; - using value_type = Entity; - using pointer = const value_type *; - using reference = const value_type &; - using iterator_category = std::random_access_iterator_tag; - - sparse_set_iterator() ENTT_NOEXCEPT = default; - - sparse_set_iterator & operator++() ENTT_NOEXCEPT { - return --index, *this; - } - - sparse_set_iterator operator++(int) ENTT_NOEXCEPT { - iterator orig = *this; - return ++(*this), orig; - } - - sparse_set_iterator & operator--() ENTT_NOEXCEPT { - return ++index, *this; - } - - sparse_set_iterator operator--(int) ENTT_NOEXCEPT { - sparse_set_iterator orig = *this; - return operator--(), orig; - } - - sparse_set_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { - index -= value; - return *this; - } - - sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT { - sparse_set_iterator copy = *this; - return (copy += value); - } - - sparse_set_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { - return (*this += -value); - } - - sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT { - return (*this + -value); - } - - difference_type operator-(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return other.index - index; - } - - [[nodiscard]] reference operator[](const difference_type value) const { - const auto pos = size_type(index-value-1u); - return (*packed)[pos]; - } - - [[nodiscard]] bool operator==(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return other.index == index; - } - - [[nodiscard]] bool operator!=(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] bool operator<(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return index > other.index; - } - - [[nodiscard]] bool operator>(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return index < other.index; - } - - [[nodiscard]] bool operator<=(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return !(*this > other); - } - - [[nodiscard]] bool operator>=(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return !(*this < other); - } - - [[nodiscard]] pointer operator->() const { - const auto pos = size_type(index-1u); - return &(*packed)[pos]; - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - const packed_type *packed; - index_type index; - }; - - [[nodiscard]] auto page(const Entity entt) const ENTT_NOEXCEPT { - return size_type{(to_integral(entt) & traits_type::entity_mask) / page_size}; - } - - [[nodiscard]] auto offset(const Entity entt) const ENTT_NOEXCEPT { - return size_type{to_integral(entt) & (page_size - 1)}; - } - - [[nodiscard]] page_type & assure(const std::size_t pos) { - if(!(pos < sparse.size())) { - sparse.resize(pos+1); - } - - if(!sparse[pos]) { - sparse[pos].reset(new entity_type[page_size]); - // null is safe in all cases for our purposes - for(auto *first = sparse[pos].get(), *last = first + page_size; first != last; ++first) { - *first = null; - } - } - - return sparse[pos]; - } - -protected: - /*! @brief Swaps two entities in the internal packed array. */ - virtual void swap_at(const std::size_t, const std::size_t) {} - - /*! @brief Attempts to remove an entity from the internal packed array. */ - virtual void swap_and_pop(const std::size_t, void *) {} - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = sparse_set_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = const entity_type *; - - /*! @brief Default constructor. */ - basic_sparse_set() = default; - - /*! @brief Default move constructor. */ - basic_sparse_set(basic_sparse_set &&) = default; - - /*! @brief Default destructor. */ - virtual ~basic_sparse_set() = default; - - /*! @brief Default move assignment operator. @return This sparse set. */ - basic_sparse_set & operator=(basic_sparse_set &&) = default; - - /** - * @brief Increases the capacity of a sparse set. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @param cap Desired capacity. - */ - void reserve(const size_type cap) { - packed.reserve(cap); - } - - /** - * @brief Returns the number of elements that a sparse set has currently - * allocated space for. - * @return Capacity of the sparse set. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return packed.capacity(); - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - // conservative approach - if(packed.empty()) { - sparse.clear(); - } - - sparse.shrink_to_fit(); - packed.shrink_to_fit(); - } - - /** - * @brief Returns the extent of a sparse set. - * - * The extent of a sparse set is also the size of the internal sparse array. - * There is no guarantee that the internal packed array has the same size. - * Usually the size of the internal sparse array is equal or greater than - * the one of the internal packed array. - * - * @return Extent of the sparse set. - */ - [[nodiscard]] size_type extent() const ENTT_NOEXCEPT { - return sparse.size() * page_size; - } - - /** - * @brief Returns the number of elements in a sparse set. - * - * The number of elements is also the size of the internal packed array. - * There is no guarantee that the internal sparse array has the same size. - * Usually the size of the internal sparse array is equal or greater than - * the one of the internal packed array. - * - * @return Number of elements. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return packed.size(); - } - - /** - * @brief Checks whether a sparse set is empty. - * @return True if the sparse set is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return packed.empty(); - } - - /** - * @brief Direct access to the internal packed array. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @note - * Entities are in the reverse order as returned by the `begin`/`end` - * iterators. - * - * @return A pointer to the internal packed array. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return packed.data(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first entity of the internal packed - * array. If the sparse set is empty, the returned iterator will be equal to - * `end()`. - * - * @return An iterator to the first entity of the internal packed array. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = packed.size(); - return iterator{packed, pos}; - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last entity in - * the internal packed array. Attempting to dereference the returned - * iterator results in undefined behavior. - * - * @return An iterator to the element following the last entity of the - * internal packed array. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{packed, {}}; - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * The returned iterator points to the first entity of the reversed internal - * packed array. If the sparse set is empty, the returned iterator will be - * equal to `rend()`. - * - * @return An iterator to the first entity of the reversed internal packed - * array. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return packed.data(); - } - - /** - * @brief Returns a reverse iterator to the end. - * - * The returned iterator points to the element following the last entity in - * the reversed internal packed array. Attempting to dereference the - * returned iterator results in undefined behavior. - * - * @return An iterator to the element following the last entity of the - * reversed internal packed array. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return rbegin() + packed.size(); - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - return contains(entt) ? --(end() - index(entt)) : end(); - } - - /** - * @brief Checks if a sparse set contains an entity. - * @param entt A valid entity identifier. - * @return True if the sparse set contains the entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - const auto curr = page(entt); - // testing against null permits to avoid accessing the packed array - return (curr < sparse.size() && sparse[curr] && sparse[curr][offset(entt)] != null); - } - - /** - * @brief Returns the position of an entity in a sparse set. - * - * @warning - * Attempting to get the position of an entity that doesn't belong to the - * sparse set results in undefined behavior. - * - * @param entt A valid entity identifier. - * @return The position of the entity in the sparse set. - */ - [[nodiscard]] size_type index(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - return size_type{to_integral(sparse[page(entt)][offset(entt)])}; - } - - /** - * @brief Returns the entity at specified location, with bounds checking. - * @param pos The position for which to return the entity. - * @return The entity at specified location if any, a null entity otherwise. - */ - [[nodiscard]] entity_type at(const size_type pos) const { - return pos < packed.size() ? packed[pos] : null; - } - - /** - * @brief Returns the entity at specified location, without bounds checking. - * @param pos The position for which to return the entity. - * @return The entity at specified location. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - ENTT_ASSERT(pos < packed.size()); - return packed[pos]; - } - - /** - * @brief Assigns an entity to a sparse set. - * - * @warning - * Attempting to assign an entity that already belongs to the sparse set - * results in undefined behavior. - * - * @param entt A valid entity identifier. - */ - void emplace(const entity_type entt) { - ENTT_ASSERT(!contains(entt)); - assure(page(entt))[offset(entt)] = entity_type{static_cast(packed.size())}; - packed.push_back(entt); - } - - /** - * @brief Assigns one or more entities to a sparse set. - * - * @warning - * Attempting to assign an entity that already belongs to the sparse set - * results in undefined behavior. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void insert(It first, It last) { - auto next = static_cast(packed.size()); - packed.insert(packed.end(), first, last); - - for(; first != last; ++first) { - ENTT_ASSERT(!contains(*first)); - assure(page(*first))[offset(*first)] = entity_type{next++}; - } - } - - /** - * @brief Removes an entity from a sparse set. - * - * @warning - * Attempting to remove an entity that doesn't belong to the sparse set - * results in undefined behavior. - * - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void remove(const entity_type entt, void *ud = nullptr) { - ENTT_ASSERT(contains(entt)); - auto &ref = sparse[page(entt)][offset(entt)]; - - // last chance to use the entity for derived classes and mixins, if any - swap_and_pop(size_type{to_integral(ref)}, ud); - - const auto other = packed.back(); - sparse[page(other)][offset(other)] = ref; - // if it looks weird, imagine what the subtle bugs it prevents are - ENTT_ASSERT((packed.back() = entt, true)); - packed[size_type{to_integral(ref)}] = other; - ref = null; - - packed.pop_back(); - } - - /** - * @brief Removes multiple entities from a pool. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - template - void remove(It first, It last, void *ud = nullptr) { - for(; first != last; ++first) { - remove(*first, ud); - } - } - - /** - * @copybrief swap_at - * - * For what it's worth, this function affects both the internal sparse array - * and the internal packed array. Users should not care of that anyway. - * - * @warning - * Attempting to swap entities that don't belong to the sparse set results - * in undefined behavior. - * - * @param lhs A valid entity identifier. - * @param rhs A valid entity identifier. - */ - void swap(const entity_type lhs, const entity_type rhs) { - const auto from = index(lhs); - const auto to = index(rhs); - std::swap(sparse[page(lhs)][offset(lhs)], sparse[page(rhs)][offset(rhs)]); - std::swap(packed[from], packed[to]); - swap_at(from, to); - } - - /** - * @brief Sort the first count elements according to the given comparison - * function. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param count Number of elements to sort. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) { - ENTT_ASSERT(!(count > size())); - - algo(packed.rend() - count, packed.rend(), std::move(compare), std::forward(args)...); - - for(size_type pos{}; pos < count; ++pos) { - auto curr = pos; - auto next = index(packed[curr]); - - while(curr != next) { - const auto idx = index(packed[next]); - const auto entt = packed[curr]; - - swap_at(next, idx); - sparse[page(entt)][offset(entt)] = entity_type{static_cast(curr)}; - - curr = next; - next = idx; - } - } - } - - /** - * @brief Sort all elements according to the given comparison function. - * - * @sa sort_n - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - sort_n(size(), std::move(compare), std::move(algo), std::forward(args)...); - } - - /** - * @brief Sort entities according to their order in another sparse set. - * - * Entities that are part of both the sparse sets are ordered internally - * according to the order they have in `other`. All the other entities goes - * to the end of the list and there are no guarantees on their order.
- * In other terms, this function can be used to impose the same order on two - * sets by using one of them as a master and the other one as a slave. - * - * Iterating the sparse set with a couple of iterators returns elements in - * the expected order after a call to `respect`. See `begin` and `end` for - * more details. - * - * @param other The sparse sets that imposes the order of the entities. - */ - void respect(const basic_sparse_set &other) { - const auto to = other.end(); - auto from = other.begin(); - - size_type pos = packed.size() - 1; - - while(pos && from != to) { - if(contains(*from)) { - if(*from != packed[pos]) { - swap(packed[pos], *from); - } - - --pos; - } - - ++from; - } - } - - /** - * @brief Clears a sparse set. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void clear(void *ud = nullptr) ENTT_NOEXCEPT { - remove(begin(), end(), ud); - } - -private: - std::vector sparse; - std::vector packed; -}; - - -} - - -#endif - -// #include "storage.hpp" -#ifndef ENTT_ENTITY_STORAGE_HPP -#define ENTT_ENTITY_STORAGE_HPP - - -#include -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "../core/type_traits.hpp" - -// #include "../signal/sigh.hpp" -#ifndef ENTT_SIGNAL_SIGH_HPP -#define ENTT_SIGNAL_SIGH_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "delegate.hpp" -#ifndef ENTT_SIGNAL_DELEGATE_HPP -#define ENTT_SIGNAL_DELEGATE_HPP - - -#include -#include -#include -#include -#include -// #include "../core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - -// #include "../config/config.h" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Type Class:: *, Other &&...) -> Type(*)(); - - -template -using function_pointer_t = decltype(internal::function_pointer(std::declval()...)); - - -template -[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) { - return std::index_sequence_for{}; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/*! @brief Used to wrap a function or a member of a specified type. */ -template -struct connect_arg_t {}; - - -/*! @brief Constant of type connect_arg_t used to disambiguate calls. */ -template -inline constexpr connect_arg_t connect_arg{}; - - -/** - * @brief Basic delegate implementation. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - */ -template -class delegate; - - -/** - * @brief Utility class to use to send around functions and members. - * - * Unmanaged delegate for function pointers and members. Users of this class are - * in charge of disconnecting instances before deleting them. - * - * A delegate can be used as a general purpose invoker without memory overhead - * for free functions possibly with payloads and bound or unbound members. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class delegate { - template - [[nodiscard]] auto wrap(std::index_sequence) ENTT_NOEXCEPT { - return [](const void *, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - return static_cast(std::invoke(Candidate, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type &, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, *curr, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type *, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, curr, std::forward>>(std::get(arguments))...)); - }; - } - -public: - /*! @brief Function type of the contained target. */ - using function_type = Ret(const void *, Args...); - /*! @brief Function type of the delegate. */ - using type = Ret(Args...); - /*! @brief Return type of the delegate. */ - using result_type = Ret; - - /*! @brief Default constructor. */ - delegate() ENTT_NOEXCEPT - : fn{nullptr}, data{nullptr} - {} - - /** - * @brief Constructs a delegate and connects a free function or an unbound - * member. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - delegate(connect_arg_t) ENTT_NOEXCEPT { - connect(); - } - - /** - * @brief Constructs a delegate and connects a free function with payload or - * a bound member. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - delegate(connect_arg_t, Type &&value_or_instance) ENTT_NOEXCEPT { - connect(std::forward(value_or_instance)); - } - - /** - * @brief Constructs a delegate and connects an user defined function with - * optional payload. - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - connect(function, payload); - } - - /** - * @brief Connects a free function or an unbound member to a delegate. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - void connect() ENTT_NOEXCEPT { - data = nullptr; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *, Args... args) -> Ret { - return Ret(std::invoke(Candidate, std::forward(args)...)); - }; - } else if constexpr(std::is_member_pointer_v) { - fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); - } else { - fn = wrap(internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the delegate.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the delegate itself. - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid reference that fits the purpose. - */ - template - void connect(Type &value_or_instance) ENTT_NOEXCEPT { - data = &value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, *curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * @sa connect(Type &) - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - */ - template - void connect(Type *value_or_instance) ENTT_NOEXCEPT { - data = value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects an user defined function with optional payload to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of an instance overcomes - * the one of the delegate.
- * The payload is returned as the first argument to the target function in - * all cases. - * - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - fn = function; - data = payload; - } - - /** - * @brief Resets a delegate. - * - * After a reset, a delegate cannot be invoked anymore. - */ - void reset() ENTT_NOEXCEPT { - fn = nullptr; - data = nullptr; - } - - /** - * @brief Returns the instance or the payload linked to a delegate, if any. - * @return An opaque pointer to the underlying data. - */ - [[nodiscard]] const void * instance() const ENTT_NOEXCEPT { - return data; - } - - /** - * @brief Triggers a delegate. - * - * The delegate invokes the underlying function and returns the result. - * - * @warning - * Attempting to trigger an invalid delegate results in undefined - * behavior. - * - * @param args Arguments to use to invoke the underlying function. - * @return The value returned by the underlying function. - */ - Ret operator()(Args... args) const { - ENTT_ASSERT(static_cast(*this)); - return fn(data, std::forward(args)...); - } - - /** - * @brief Checks whether a delegate actually stores a listener. - * @return False if the delegate is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - // no need to test also data - return !(fn == nullptr); - } - - /** - * @brief Compares the contents of two delegates. - * @param other Delegate with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const delegate &other) const ENTT_NOEXCEPT { - return fn == other.fn && data == other.data; - } - -private: - function_type *fn; - const void *data; -}; - - -/** - * @brief Compares the contents of two delegates. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @param lhs A valid delegate object. - * @param rhs A valid delegate object. - * @return True if the two contents differ, false otherwise. - */ -template -[[nodiscard]] bool operator!=(const delegate &lhs, const delegate &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - */ -template -delegate(connect_arg_t) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - */ -template -delegate(connect_arg_t, Type &&) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) --> delegate; - - -} - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_SIGNAL_FWD_HPP -#define ENTT_SIGNAL_FWD_HPP - - -namespace entt { - - -template -class delegate; - - -class dispatcher; - - -template -class emitter; - - -class connection; - - -struct scoped_connection; - - -template -class sink; - - -template -class sigh; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Sink class. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - */ -template -class sink; - - -/** - * @brief Unmanaged signal handler. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - */ -template -class sigh; - - -/** - * @brief Unmanaged signal handler. - * - * It works directly with references to classes and pointers to member functions - * as well as pointers to free functions. Users of this class are in charge of - * disconnecting instances before deleting them. - * - * This class serves mainly two purposes: - * - * * Creating signals to use later to notify a bunch of listeners. - * * Collecting results from a set of functions like in a voting system. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class sigh { - /*! @brief A sink is allowed to modify a signal. */ - friend class sink; - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Sink type. */ - using sink_type = sink; - - /** - * @brief Instance type when it comes to connecting member functions. - * @tparam Class Type of class to which the member function belongs. - */ - template - using instance_type = Class *; - - /** - * @brief Number of listeners connected to the signal. - * @return Number of listeners currently connected. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return calls.size(); - } - - /** - * @brief Returns false if at least a listener is connected to the signal. - * @return True if the signal has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return calls.empty(); - } - - /** - * @brief Triggers a signal. - * - * All the listeners are notified. Order isn't guaranteed. - * - * @param args Arguments to use to invoke listeners. - */ - void publish(Args... args) const { - for(auto &&call: std::as_const(calls)) { - call(args...); - } - } - - /** - * @brief Collects return values from the listeners. - * - * The collector must expose a call operator with the following properties: - * - * * The return type is either `void` or such that it's convertible to - * `bool`. In the second case, a true value will stop the iteration. - * * The list of parameters is empty if `Ret` is `void`, otherwise it - * contains a single element such that `Ret` is convertible to it. - * - * @tparam Func Type of collector to use, if any. - * @param func A valid function object. - * @param args Arguments to use to invoke listeners. - */ - template - void collect(Func func, Args... args) const { - for(auto &&call: calls) { - if constexpr(std::is_void_v) { - if constexpr(std::is_invocable_r_v) { - call(args...); - if(func()) { break; } - } else { - call(args...); - func(); - } - } else { - if constexpr(std::is_invocable_r_v) { - if(func(call(args...))) { break; } - } else { - func(call(args...)); - } - } - } - } - -private: - std::vector> calls; -}; - - -/** - * @brief Connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it. - */ -class connection { - /*! @brief A sink is allowed to create connection objects. */ - template - friend class sink; - - connection(delegate fn, void *ref) - : disconnect{fn}, signal{ref} - {} - -public: - /*! @brief Default constructor. */ - connection() = default; - - /** - * @brief Checks whether a connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(disconnect); - } - - /*! @brief Breaks the connection. */ - void release() { - if(disconnect) { - disconnect(signal); - disconnect.reset(); - } - } - -private: - delegate disconnect; - void *signal{}; -}; - - -/** - * @brief Scoped connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it.
- * A scoped connection automatically breaks the link between the two objects - * when it goes out of scope. - */ -struct scoped_connection { - /*! @brief Default constructor. */ - scoped_connection() = default; - - /** - * @brief Constructs a scoped connection from a basic connection. - * @param other A valid connection object. - */ - scoped_connection(const connection &other) - : conn{other} - {} - - /*! @brief Default copy constructor, deleted on purpose. */ - scoped_connection(const scoped_connection &) = delete; - - /*! @brief Automatically breaks the link on destruction. */ - ~scoped_connection() { - conn.release(); - } - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This scoped connection. - */ - scoped_connection & operator=(const scoped_connection &) = delete; - - /** - * @brief Acquires a connection. - * @param other The connection object to acquire. - * @return This scoped connection. - */ - scoped_connection & operator=(connection other) { - conn = std::move(other); - return *this; - } - - /** - * @brief Checks whether a scoped connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(conn); - } - - /*! @brief Breaks the connection. */ - void release() { - conn.release(); - } - -private: - connection conn; -}; - - -/** - * @brief Sink class. - * - * A sink is used to connect listeners to signals and to disconnect them.
- * The function type for a listener is the one of the signal to which it - * belongs. - * - * The clear separation between a signal and a sink permits to store the former - * as private data member without exposing the publish functionality to the - * users of the class. - * - * @warning - * Lifetime of a sink must not overcome that of the signal to which it refers. - * In any other case, attempting to use a sink results in undefined behavior. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class sink { - using signal_type = sigh; - using difference_type = typename std::iterator_traits::difference_type; - - template - static void release(Type value_or_instance, void *signal) { - sink{*static_cast(signal)}.disconnect(value_or_instance); - } - - template - static void release(void *signal) { - sink{*static_cast(signal)}.disconnect(); - } - -public: - /** - * @brief Constructs a sink that is allowed to modify a given signal. - * @param ref A valid reference to a signal object. - */ - sink(sigh &ref) ENTT_NOEXCEPT - : offset{}, - signal{&ref} - {} - - /** - * @brief Returns false if at least a listener is connected to the sink. - * @return True if the sink has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return signal->calls.empty(); - } - - /** - * @brief Returns a sink that connects before a given free function or an - * unbound member. - * @tparam Function A valid free function pointer. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before() { - delegate call{}; - call.template connect(); - - const auto &calls = signal->calls; - const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); - - sink other{*this}; - other.offset = std::distance(it, calls.cend()); - return other; - } - - /** - * @brief Returns a sink that connects before a free function with payload - * or a bound member. - * @tparam Candidate Member or free function to look for. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type &&value_or_instance) { - delegate call{}; - call.template connect(value_or_instance); - - const auto &calls = signal->calls; - const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); - - sink other{*this}; - other.offset = std::distance(it, calls.cend()); - return other; - } - - /** - * @brief Returns a sink that connects before a given instance or specific - * payload. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type &value_or_instance) { - return before(&value_or_instance); - } - - /** - * @brief Returns a sink that connects before a given instance or specific - * payload. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type *value_or_instance) { - sink other{*this}; - - if(value_or_instance) { - const auto &calls = signal->calls; - const auto it = std::find_if(calls.cbegin(), calls.cend(), [value_or_instance](const auto &delegate) { - return delegate.instance() == value_or_instance; - }); - - other.offset = std::distance(it, calls.cend()); - } - - return other; - } - - /** - * @brief Returns a sink that connects before anything else. - * @return A properly initialized sink object. - */ - [[nodiscard]] sink before() { - sink other{*this}; - other.offset = signal->calls.size(); - return other; - } - - /** - * @brief Connects a free function or an unbound member to a signal. - * - * The signal handler performs checks to avoid multiple connections for the - * same function. - * - * @tparam Candidate Function or member to connect to the signal. - * @return A properly initialized connection object. - */ - template - connection connect() { - disconnect(); - - delegate call{}; - call.template connect(); - signal->calls.insert(signal->calls.end() - offset, std::move(call)); - - delegate conn{}; - conn.template connect<&release>(); - return { std::move(conn), signal }; - } - - /** - * @brief Connects a free function with payload or a bound member to a - * signal. - * - * The signal isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the signal. On the other side, the signal handler performs - * checks to avoid multiple connections for the same function.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the signal itself. - * - * @tparam Candidate Function or member to connect to the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized connection object. - */ - template - connection connect(Type &&value_or_instance) { - disconnect(value_or_instance); - - delegate call{}; - call.template connect(value_or_instance); - signal->calls.insert(signal->calls.end() - offset, std::move(call)); - - delegate conn{}; - conn.template connect<&release>(value_or_instance); - return { std::move(conn), signal }; - } - - /** - * @brief Disconnects a free function or an unbound member from a signal. - * @tparam Candidate Function or member to disconnect from the signal. - */ - template - void disconnect() { - auto &calls = signal->calls; - delegate call{}; - call.template connect(); - calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); - } - - /** - * @brief Disconnects a free function with payload or a bound member from a - * signal. - * @tparam Candidate Function or member to disconnect from the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &&value_or_instance) { - auto &calls = signal->calls; - delegate call{}; - call.template connect(value_or_instance); - calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &value_or_instance) { - disconnect(&value_or_instance); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type *value_or_instance) { - if(value_or_instance) { - auto &calls = signal->calls; - calls.erase(std::remove_if(calls.begin(), calls.end(), [value_or_instance](const auto &delegate) { - return delegate.instance() == value_or_instance; - }), calls.end()); - } - } - - /*! @brief Disconnects all the listeners from a signal. */ - void disconnect() { - signal->calls.clear(); - } - -private: - difference_type offset; - signal_type *signal; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the function type of a sink directly from the signal it - * refers to. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -sink(sigh &) --> sink; - - -} - - -#endif - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "sparse_set.hpp" - - - -namespace entt { - - -/** - * @brief Basic storage implementation. - * - * This class is a refinement of a sparse set that associates an object to an - * entity. The main purpose of this class is to extend sparse sets to store - * components in a registry. It guarantees fast access both to the elements and - * to the entities. - * - * @note - * Entities and objects have the same order. It's guaranteed both in case of raw - * access (either to entities or objects) and when using random or input access - * iterators. - * - * @note - * Internal data structures arrange elements to maximize performance. There are - * no guarantees that objects are returned in the insertion order when iterate - * a storage. Do not make assumption on the order in any case. - * - * @warning - * Empty types aren't explicitly instantiated. Therefore, many of the functions - * normally available for non-empty types will not be available for empty ones. - * - * @sa sparse_set - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects assigned to the entities. - */ -template -class basic_storage: public basic_sparse_set { - static_assert(std::is_move_constructible_v && std::is_move_assignable_v, "The managed type must be at least move constructible and assignable"); - - using underlying_type = basic_sparse_set; - using traits_type = entt_traits; - - template - class storage_iterator final { - friend class basic_storage; - - using instance_type = constness_as_t, Value>; - using index_type = typename traits_type::difference_type; - - storage_iterator(instance_type &ref, const index_type idx) ENTT_NOEXCEPT - : instances{&ref}, index{idx} - {} - - public: - using difference_type = index_type; - using value_type = Value; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::random_access_iterator_tag; - - storage_iterator() ENTT_NOEXCEPT = default; - - storage_iterator & operator++() ENTT_NOEXCEPT { - return --index, *this; - } - - storage_iterator operator++(int) ENTT_NOEXCEPT { - storage_iterator orig = *this; - return ++(*this), orig; - } - - storage_iterator & operator--() ENTT_NOEXCEPT { - return ++index, *this; - } - - storage_iterator operator--(int) ENTT_NOEXCEPT { - storage_iterator orig = *this; - return operator--(), orig; - } - - storage_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { - index -= value; - return *this; - } - - storage_iterator operator+(const difference_type value) const ENTT_NOEXCEPT { - storage_iterator copy = *this; - return (copy += value); - } - - storage_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { - return (*this += -value); - } - - storage_iterator operator-(const difference_type value) const ENTT_NOEXCEPT { - return (*this + -value); - } - - difference_type operator-(const storage_iterator &other) const ENTT_NOEXCEPT { - return other.index - index; - } - - [[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT { - const auto pos = size_type(index-value-1); - return (*instances)[pos]; - } - - [[nodiscard]] bool operator==(const storage_iterator &other) const ENTT_NOEXCEPT { - return other.index == index; - } - - [[nodiscard]] bool operator!=(const storage_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] bool operator<(const storage_iterator &other) const ENTT_NOEXCEPT { - return index > other.index; - } - - [[nodiscard]] bool operator>(const storage_iterator &other) const ENTT_NOEXCEPT { - return index < other.index; - } - - [[nodiscard]] bool operator<=(const storage_iterator &other) const ENTT_NOEXCEPT { - return !(*this > other); - } - - [[nodiscard]] bool operator>=(const storage_iterator &other) const ENTT_NOEXCEPT { - return !(*this < other); - } - - [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { - const auto pos = size_type(index-1u); - return &(*instances)[pos]; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return *operator->(); - } - - private: - instance_type *instances; - index_type index; - }; - -protected: - /** - * @copybrief basic_sparse_set::swap_at - * @param lhs A valid position of an entity within storage. - * @param rhs A valid position of an entity within storage. - */ - void swap_at(const std::size_t lhs, const std::size_t rhs) { - std::swap(instances[lhs], instances[rhs]); - } - - /** - * @copybrief basic_sparse_set::swap_and_pop - * @param pos A valid position of an entity within storage. - */ - void swap_and_pop(const std::size_t pos, void *) { - auto other = std::move(instances.back()); - instances[pos] = std::move(other); - instances.pop_back(); - } - -public: - /*! @brief Type of the objects assigned to entities. */ - using value_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = storage_iterator; - /*! @brief Constant random access iterator type. */ - using const_iterator = storage_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = Type *; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = const Type *; - - /** - * @brief Increases the capacity of a storage. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @param cap Desired capacity. - */ - void reserve(const size_type cap) { - underlying_type::reserve(cap); - instances.reserve(cap); - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - underlying_type::shrink_to_fit(); - instances.shrink_to_fit(); - } - - /** - * @brief Direct access to the array of objects. - * - * The returned pointer is such that range `[raw(), raw() + size())` is - * always a valid range, even if the container is empty. - * - * @note - * Objects are in the reverse order as returned by the `begin`/`end` - * iterators. - * - * @return A pointer to the array of objects. - */ - [[nodiscard]] const value_type * raw() const ENTT_NOEXCEPT { - return instances.data(); - } - - /*! @copydoc raw */ - [[nodiscard]] value_type * raw() ENTT_NOEXCEPT { - return const_cast(std::as_const(*this).raw()); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first instance of the internal array. - * If the storage is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first instance of the internal array. - */ - [[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = underlying_type::size(); - return const_iterator{instances, pos}; - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = underlying_type::size(); - return iterator{instances, pos}; - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last instance - * of the internal array. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the element following the last instance of the - * internal array. - */ - [[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT { - return const_iterator{instances, {}}; - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const ENTT_NOEXCEPT { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() ENTT_NOEXCEPT { - return iterator{instances, {}}; - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * The returned iterator points to the first instance of the reversed - * internal array. If the storage is empty, the returned iterator will be - * equal to `rend()`. - * - * @return An iterator to the first instance of the reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crbegin() const ENTT_NOEXCEPT { - return instances.data(); - } - - /*! @copydoc crbegin */ - [[nodiscard]] const_reverse_iterator rbegin() const ENTT_NOEXCEPT { - return crbegin(); - } - - /*! @copydoc rbegin */ - [[nodiscard]] reverse_iterator rbegin() ENTT_NOEXCEPT { - return instances.data(); - } - - /** - * @brief Returns a reverse iterator to the end. - * - * The returned iterator points to the element following the last instance - * of the reversed internal array. Attempting to dereference the returned - * iterator results in undefined behavior. - * - * @return An iterator to the element following the last instance of the - * reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crend() const ENTT_NOEXCEPT { - return crbegin() + instances.size(); - } - - /*! @copydoc crend */ - [[nodiscard]] const_reverse_iterator rend() const ENTT_NOEXCEPT { - return crend(); - } - - /*! @copydoc rend */ - [[nodiscard]] reverse_iterator rend() ENTT_NOEXCEPT { - return rbegin() + instances.size(); - } - - /** - * @brief Returns the object assigned to an entity. - * - * @warning - * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. - * - * @param entt A valid entity identifier. - * @return The object assigned to the entity. - */ - [[nodiscard]] const value_type & get(const entity_type entt) const { - return instances[underlying_type::index(entt)]; - } - - /*! @copydoc get */ - [[nodiscard]] value_type & get(const entity_type entt) { - return const_cast(std::as_const(*this).get(entt)); - } - - /** - * @brief Assigns an entity to a storage and constructs its object. - * - * This version accept both types that can be constructed in place directly - * and types like aggregates that do not work well with a placement new as - * performed usually under the hood during an _emplace back_. - * - * @warning - * Attempting to use an entity that already belongs to the storage results - * in undefined behavior. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entt A valid entity identifier. - * @param args Parameters to use to construct an object for the entity. - * @return A reference to the newly created object. - */ - template - value_type & emplace(const entity_type entt, Args &&... args) { - if constexpr(std::is_aggregate_v) { - instances.push_back(Type{std::forward(args)...}); - } else { - instances.emplace_back(std::forward(args)...); - } - - // entity goes after component in case constructor throws - underlying_type::emplace(entt); - return instances.back(); - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the updated instance. - */ - template - decltype(auto) patch(const entity_type entity, Func &&... func) { - auto &&instance = instances[this->index(entity)]; - (std::forward(func)(instance), ...); - return instance; - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given instance. - * - * @warning - * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param value An instance of the object to construct. - */ - template - void insert(It first, It last, const value_type &value = {}) { - instances.insert(instances.end(), std::distance(first, last), value); - // entities go after components in case constructors throw - underlying_type::insert(first, last); - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given range. - * - * @sa construct - * - * @tparam EIt Type of input iterator. - * @tparam CIt Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param from An iterator to the first element of the range of objects. - * @param to An iterator past the last element of the range of objects. - */ - template - void insert(EIt first, EIt last, CIt from, CIt to) { - instances.insert(instances.end(), from, to); - // entities go after components in case constructors throw - underlying_type::insert(first, last); - } - - /** - * @brief Sort elements according to the given comparison function. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * bool(const Type &, const Type &); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @warning - * Empty types are never instantiated. Therefore, only comparison function - * objects that require to return entities rather than components are - * accepted. - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param count Number of elements to sort. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) { - if constexpr(std::is_invocable_v) { - underlying_type::sort_n(count, [this, compare = std::move(compare)](const auto lhs, const auto rhs) { - return compare(std::as_const(instances[underlying_type::index(lhs)]), std::as_const(instances[underlying_type::index(rhs)])); - }, std::move(algo), std::forward(args)...); - } else { - underlying_type::sort_n(count, std::move(compare), std::move(algo), std::forward(args)...); - } - } - - /** - * @brief Sort all elements according to the given comparison function. - * - * @sa sort_n - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - sort_n(this->size(), std::move(compare), std::move(algo), std::forward(args)...); - } - -private: - std::vector instances; -}; - - -/*! @copydoc basic_storage */ -template -class basic_storage>>: public basic_sparse_set { - using underlying_type = basic_sparse_set; - -public: - /*! @brief Type of the objects assigned to entities. */ - using value_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - - /** - * @brief Fake get function. - * - * @warning - * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. - * - * @param entt A valid entity identifier. - */ - void get([[maybe_unused]] const entity_type entt) const { - ENTT_ASSERT(this->contains(entt)); - } - - /** - * @brief Assigns an entity to a storage and constructs its object. - * - * @warning - * Attempting to use an entity that already belongs to the storage results - * in undefined behavior. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entt A valid entity identifier. - * @param args Parameters to use to construct an object for the entity. - */ - template - void emplace(const entity_type entt, Args &&... args) { - [[maybe_unused]] value_type instance{std::forward(args)...}; - underlying_type::emplace(entt); - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - */ - template - void patch([[maybe_unused]] const entity_type entity, Func &&... func) { - ENTT_ASSERT(this->contains(entity)); - (std::forward(func)(), ...); - } - - /** - * @brief Assigns one or more entities to a storage. - * - * @warning - * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void insert(It first, It last, const value_type & = {}) { - underlying_type::insert(first, last); - } -}; - - -/** - * @brief Mixin type to use to wrap basic storage classes. - * @tparam Type The type of the underlying storage. - */ -template -struct storage_adapter_mixin: Type { - static_assert(std::is_same_v>, "Invalid object type"); - - /*! @brief Type of the objects assigned to entities. */ - using value_type = typename Type::value_type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename Type::entity_type; - - /** - * @brief Assigns entities to a storage. - * @tparam Args Types of arguments to use to construct the object. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the object. - * @return A reference to the newly created object. - */ - template - decltype(auto) emplace(basic_registry &, const entity_type entity, Args &&... args) { - return Type::emplace(entity, std::forward(args)...); - } - - /** - * @brief Assigns entities to a storage. - * @tparam It Type of input iterator. - * @tparam Args Types of arguments to use to construct the objects assigned - * to the entities. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param args Parameters to use to initialize the objects assigned to the - * entities. - */ - template - void insert(basic_registry &, It first, It last, Args &&... args) { - Type::insert(first, last, std::forward(args)...); - } - - /** - * @brief Patches the given instance for an entity. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the patched instance. - */ - template - decltype(auto) patch(basic_registry &, const entity_type entity, Func &&... func) { - return Type::patch(entity, std::forward(func)...); - } -}; - - -/** - * @brief Mixin type to use to add signal support to storage types. - * @tparam Type The type of the underlying storage. - */ -template -class sigh_storage_mixin final: public Type { - /** - * @copybrief basic_sparse_set::swap_and_pop - * @param pos A valid position of an entity within storage. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void swap_and_pop(const std::size_t pos, void *ud) final { - ENTT_ASSERT(ud != nullptr); - const auto entity = basic_sparse_set::operator[](pos); - destruction.publish(*static_cast *>(ud), entity); - // the position may have changed due to the actions of a listener - Type::swap_and_pop(this->index(entity), ud); - } - -public: - /*! @brief Underlying value type. */ - using value_type = typename Type::value_type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename Type::entity_type; - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever a new instance is created and assigned to an entity.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, entity_type); - * @endcode - * - * Listeners are invoked **after** the object has been assigned to the - * entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_construct() ENTT_NOEXCEPT { - return sink{construction}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is explicitly updated.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, entity_type); - * @endcode - * - * Listeners are invoked **after** the object has been updated. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_update() ENTT_NOEXCEPT { - return sink{update}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is removed from an entity and thus destroyed.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, entity_type); - * @endcode - * - * Listeners are invoked **before** the object has been removed from the - * entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_destroy() ENTT_NOEXCEPT { - return sink{destruction}; - } - - /** - * @brief Assigns entities to a storage. - * @tparam Args Types of arguments to use to construct the object. - * @param owner The registry that issued the request. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the object. - * @return A reference to the newly created object. - */ - template - decltype(auto) emplace(basic_registry &owner, const entity_type entity, Args &&... args) { - Type::emplace(entity, std::forward(args)...); - construction.publish(owner, entity); - return this->get(entity); - } - - /** - * @brief Assigns entities to a storage. - * @tparam It Type of input iterator. - * @tparam Args Types of arguments to use to construct the objects assigned - * to the entities. - * @param owner The registry that issued the request. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param args Parameters to use to initialize the objects assigned to the - * entities. - */ - template - void insert(basic_registry &owner, It first, It last, Args &&... args) { - Type::insert(first, last, std::forward(args)...); - - if(!construction.empty()) { - for(; first != last; ++first) { - construction.publish(owner, *first); - } - } - } - - /** - * @brief Patches the given instance for an entity. - * @tparam Func Types of the function objects to invoke. - * @param owner The registry that issued the request. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the patched instance. - */ - template - decltype(auto) patch(basic_registry &owner, const entity_type entity, Func &&... func) { - Type::patch(entity, std::forward(func)...); - update.publish(owner, entity); - return this->get(entity); - } - -private: - sigh &, const entity_type)> construction{}; - sigh &, const entity_type)> destruction{}; - sigh &, const entity_type)> update{}; -}; - - -/** - * @brief Defines the component-to-storage conversion. - * - * Formally: - * - * * If the component type is a non-const one, the member typedef type is the - * declared storage type. - * * If the component type is a const one, the member typedef type is the - * declared storage type, except it has a const-qualifier added. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects assigned to the entities. - */ -template -struct storage_traits { - /*! @brief Resulting type after component-to-storage conversion. */ - using storage_type = sigh_storage_mixin>; -}; - - -/** - * @brief Gets the element assigned to an entity from a storage, if any. - * @tparam Type Storage type. - * @param container A valid instance of a storage class. - * @param entity A valid entity identifier. - * @return A possibly empty tuple containing the requested element. - */ -template -[[nodiscard]] auto get_as_tuple([[maybe_unused]] Type &container, [[maybe_unused]] const typename Type::entity_type entity) { - static_assert(std::is_same_v, typename storage_traits::storage_type>, "Invalid storage"); - - if constexpr(std::is_void_v) { - return std::make_tuple(); - } else { - return std::forward_as_tuple(container.get(entity)); - } -} - - -} - - -#endif - -// #include "utility.hpp" -#ifndef ENTT_ENTITY_UTILITY_HPP -#define ENTT_ENTITY_UTILITY_HPP - - -// #include "../core/type_traits.hpp" - - - -namespace entt { - - -/** - * @brief Alias for exclusion lists. - * @tparam Type List of types. - */ -template -struct exclude_t: type_list {}; - - -/** - * @brief Variable template for exclusion lists. - * @tparam Type List of types. - */ -template -inline constexpr exclude_t exclude{}; - - -/** - * @brief Alias for lists of observed components. - * @tparam Type List of types. - */ -template -struct get_t: type_list{}; - - -/** - * @brief Variable template for lists of observed components. - * @tparam Type List of types. - */ -template -inline constexpr get_t get{}; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Group. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class basic_group; - - -/** - * @brief Non-owning group. - * - * A non-owning group returns all entities and only the entities that have at - * least the given components. Moreover, it's guaranteed that the entity list - * is tightly packed in memory for fast iterations. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the group in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Groups share references to the underlying data structures of the registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by all the - * groups.
- * Moreover, sorting a non-owning group affects all the instances of the same - * group (it means that users don't have to call `sort` on each instance to sort - * all of them because they _share_ entities and components). - * - * @warning - * Lifetime of a group must not overcome that of the registry that generated it. - * In any other case, attempting to use a group results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Exclude Types of components used to filter the group. - * @tparam Get Type of components observed by the group. - */ -template -class basic_group, get_t> final { - /*! @brief A registry is allowed to create groups. */ - friend class basic_registry; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable_group final { - friend class basic_group, get_t>; - - template - class iterable_group_iterator final { - friend class iterable_group; - - template - iterable_group_iterator(It from, const std::tuple *...> &args) ENTT_NOEXCEPT - : it{from}, - pools{args} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_group_iterator & operator++() ENTT_NOEXCEPT { - return ++it, *this; - } - - iterable_group_iterator operator++(int) ENTT_NOEXCEPT { - iterable_group_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - const auto entt = *it; - return std::tuple_cat(std::make_tuple(entt), get_as_tuple(*std::get *>(pools), entt)...); - } - - [[nodiscard]] bool operator==(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple *...> pools; - }; - - iterable_group(basic_sparse_set * const ref, const std::tuple *...> &cpools) - : handler{ref}, - pools{cpools} - {} - - public: - using iterator = iterable_group_iterator::iterator>; - using reverse_iterator = iterable_group_iterator::reverse_iterator>; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return handler ? iterator{handler->begin(), pools} : iterator{{}, pools}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return handler ? iterator{handler->end(), pools} : iterator{{}, pools}; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return handler ? reverse_iterator{handler->rbegin(), pools} : reverse_iterator{{}, pools}; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return handler ? reverse_iterator{handler->rend(), pools} : reverse_iterator{{}, pools}; - } - - private: - basic_sparse_set * const handler; - const std::tuple *...> pools; - }; - - basic_group(basic_sparse_set &ref, storage_type &... gpool) ENTT_NOEXCEPT - : handler{&ref}, - pools{&gpool...} - {} - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = typename basic_sparse_set::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_sparse_set::reverse_iterator; - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() ENTT_NOEXCEPT - : handler{} - {} - - /** - * @brief Returns the number of entities that have the given components. - * @return Number of entities that have the given components. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return *this ? handler->size() : size_type{}; - } - - /** - * @brief Returns the number of elements that a group has currently - * allocated space for. - * @return Capacity of the group. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return *this ? handler->capacity() : size_type{}; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - if(*this) { - handler->shrink_to_fit(); - } - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return !*this || handler->empty(); - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return *this ? handler->data() : nullptr; - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * The returned iterator points to the first entity of the group. If the - * group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return *this ? handler->begin() : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the group. - * - * The returned iterator points to the entity following the last entity of - * the group. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * group. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return *this ? handler->end() : iterator{}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed group. - * - * The returned iterator points to the first entity of the reversed group. - * If the group is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed group. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return *this ? handler->rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * group. - * - * The returned iterator points to the entity following the last entity of - * the reversed group. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed group. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return *this ? handler->rend() : reverse_iterator{}; - } - - /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the group, if any. - * @return The last entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = *this ? handler->find(entt) : iterator{}; - return it != end() && *it == entt ? it : end(); - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[pos]; - } - - /** - * @brief Checks if a group is properly initialized. - * @return True if the group is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return handler != nullptr; - } - - /** - * @brief Checks if a group contains an entity. - * @param entt A valid entity identifier. - * @return True if the group contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return *this && handler->contains(entt); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the group - * results in undefined behavior. - * - * @tparam Component Types of components to get. - * @param entt A valid entity identifier. - * @return The components assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Component) == 0) { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } else if constexpr(sizeof...(Component) == 1) { - return (std::get *>(pools)->get(entt), ...); - } else { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty components. The - * _constness_ of the components is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entt: *this) { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); - } else { - std::apply(func, get(entt)); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ the group. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty components. The _constness_ of the - * components is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the group. - */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{handler, pools}; - } - - /** - * @brief Sort a group according to the given comparison function. - * - * Sort the group so that iterating it with a couple of iterators returns - * entities and components in the expected order. See `begin` and `end` for - * more details. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(std::tuple, std::tuple); - * bool(const Component &..., const Component &...); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Component` are such that they are iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Component Optional types of components to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - if(*this) { - if constexpr(sizeof...(Component) == 0) { - static_assert(std::is_invocable_v, "Invalid comparison function"); - handler->sort(std::move(compare), std::move(algo), std::forward(args)...); - } else if constexpr(sizeof...(Component) == 1) { - handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare((std::get *>(pools)->get(lhs), ...), (std::get *>(pools)->get(rhs), ...)); - }, std::move(algo), std::forward(args)...); - } else { - handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare(std::forward_as_tuple(std::get *>(pools)->get(lhs)...), std::forward_as_tuple(std::get *>(pools)->get(rhs)...)); - }, std::move(algo), std::forward(args)...); - } - } - } - - /** - * @brief Sort the shared pool of entities according to the given component. - * - * Non-owning groups of the same type share with the registry a pool of - * entities with its own order that doesn't depend on the order of any pool - * of components. Users can order the underlying data structure so that it - * respects the order of the pool of the given component. - * - * @note - * The shared pool of entities and thus its order is affected by the changes - * to each and every pool that it tracks. Therefore changes to those pools - * can quickly ruin the order imposed to the pool of entities shared between - * the non-owning groups. - * - * @tparam Component Type of component to use to impose the order. - */ - template - void sort() const { - if(*this) { - handler->respect(*std::get *>(pools)); - } - } - -private: - basic_sparse_set * const handler; - const std::tuple *...> pools; -}; - - -/** - * @brief Owning group. - * - * Owning groups return all entities and only the entities that have at least - * the given components. Moreover: - * - * * It's guaranteed that the entity list is tightly packed in memory for fast - * iterations. - * * It's guaranteed that the lists of owned components are tightly packed in - * memory for even faster iterations and to allow direct access. - * * They stay true to the order of the owned components and all instances have - * the same order in memory. - * - * The more types of components are owned by a group, the faster it is to - * iterate them. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the group in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Groups share references to the underlying data structures of the registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by all the - * groups. - * Moreover, sorting an owning group affects all the instance of the same group - * (it means that users don't have to call `sort` on each instance to sort all - * of them because they share the underlying data structure). - * - * @warning - * Lifetime of a group must not overcome that of the registry that generated it. - * In any other case, attempting to use a group results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Exclude Types of components used to filter the group. - * @tparam Get Types of components observed by the group. - * @tparam Owned Types of components owned by the group. - */ -template -class basic_group, get_t, Owned...> final { - /*! @brief A registry is allowed to create groups. */ - friend class basic_registry; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable_group final { - friend class basic_group, get_t, Owned...>; - - template - class iterable_group_iterator; - - template - class iterable_group_iterator> final { - friend class iterable_group; - - template - iterable_group_iterator(It from, const std::tuple &other, const std::tuple *...> &cpools) ENTT_NOEXCEPT - : it{from}, - owned{std::get(other)...}, - get{cpools} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_group_iterator & operator++() ENTT_NOEXCEPT { - return ++it, (++std::get(owned), ...), *this; - } - - iterable_group_iterator operator++(int) ENTT_NOEXCEPT { - iterable_group_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat( - std::make_tuple(*it), - std::forward_as_tuple(*std::get(owned)...), - get_as_tuple(*std::get *>(get), *it)... - ); - } - - [[nodiscard]] bool operator==(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple owned; - std::tuple *...> get; - }; - - iterable_group(std::tuple *..., storage_type *...> cpools, const std::size_t * const extent) - : pools{cpools}, - length{extent} - {} - - public: - using iterator = iterable_group_iterator< - typename basic_sparse_set::iterator, - type_list_cat_t>().get({}))>, type_list<>, type_list>().end())>>...> - >; - using reverse_iterator = iterable_group_iterator< - typename basic_sparse_set::reverse_iterator, - type_list_cat_t>().get({}))>, type_list<>, type_list>().rbegin())>>...> - >; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return length ? iterator{ - std::get<0>(pools)->basic_sparse_set::end() - *length, - std::make_tuple((std::get *>(pools)->end() - *length)...), - std::make_tuple(std::get *>(pools)...) - } : iterator{{}, std::make_tuple(decltype(std::get *>(pools)->end()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return length ? iterator{ - std::get<0>(pools)->basic_sparse_set::end(), - std::make_tuple((std::get *>(pools)->end())...), - std::make_tuple(std::get *>(pools)...) - } : iterator{{}, std::make_tuple(decltype(std::get *>(pools)->end()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return length ? reverse_iterator{ - std::get<0>(pools)->basic_sparse_set::rbegin(), - std::make_tuple((std::get *>(pools)->rbegin())...), - std::make_tuple(std::get *>(pools)...) - } : reverse_iterator{{}, std::make_tuple(decltype(std::get *>(pools)->rbegin()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return length ? reverse_iterator{ - std::get<0>(pools)->basic_sparse_set::rbegin() + *length, - std::make_tuple((std::get *>(pools)->rbegin() + *length)...), - std::make_tuple(std::get *>(pools)...) - } : reverse_iterator{{}, std::make_tuple(decltype(std::get *>(pools)->rbegin()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - private: - const std::tuple *..., storage_type *...> pools; - const std::size_t * const length; - }; - - basic_group(const std::size_t &extent, storage_type &... opool, storage_type &... gpool) ENTT_NOEXCEPT - : pools{&opool..., &gpool...}, - length{&extent} - {} - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = typename basic_sparse_set::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_sparse_set::reverse_iterator; - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() ENTT_NOEXCEPT - : length{} - {} - - /** - * @brief Returns the number of entities that have the given components. - * @return Number of entities that have the given components. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return *this ? *length : size_type{}; - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return !*this || !*length; - } - - /** - * @brief Direct access to the list of components of a given pool. - * - * The returned pointer is such that range - * `[raw(), raw() + size())` is always a valid range, - * even if the container is empty.
- * - * @warning - * This function is only available for owned types. - * - * @tparam Component Type of component in which one is interested. - * @return A pointer to the array of components. - */ - template - [[nodiscard]] Component * raw() const ENTT_NOEXCEPT { - static_assert((std::is_same_v || ...), "Non-owned type"); - auto *cpool = std::get *>(pools); - return cpool ? cpool->raw() : nullptr; - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return *this ? std::get<0>(pools)->data() : nullptr; - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * The returned iterator points to the first entity of the group. If the - * group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return *this ? (std::get<0>(pools)->basic_sparse_set::end() - *length) : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the group. - * - * The returned iterator points to the entity following the last entity of - * the group. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * group. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return *this ? std::get<0>(pools)->basic_sparse_set::end() : iterator{}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed group. - * - * The returned iterator points to the first entity of the reversed group. - * If the group is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed group. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return *this ? std::get<0>(pools)->basic_sparse_set::rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * group. - * - * The returned iterator points to the entity following the last entity of - * the reversed group. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed group. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return *this ? (std::get<0>(pools)->basic_sparse_set::rbegin() + *length) : reverse_iterator{}; - } - - /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the group, if any. - * @return The last entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = *this ? std::get<0>(pools)->find(entt) : iterator{}; - return it != end() && it >= begin() && *it == entt ? it : end(); - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[pos]; - } - - /** - * @brief Checks if a group is properly initialized. - * @return True if the group is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return length != nullptr; - } - - /** - * @brief Checks if a group contains an entity. - * @param entt A valid entity identifier. - * @return True if the group contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return *this && std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < (*length)); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the group - * results in undefined behavior. - * - * @tparam Component Types of components to get. - * @param entt A valid entity identifier. - * @return The components assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Component) == 0) { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)..., get_as_tuple(*std::get *>(pools), entt)...); - } else if constexpr(sizeof...(Component) == 1) { - return (std::get *>(pools)->get(entt), ...); - } else { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty components. The - * _constness_ of the components is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(auto args: each()) { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, args); - } else { - std::apply([&func](auto, auto &&... less) { func(std::forward(less)...); }, args); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ the group. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty components. The _constness_ of the - * components is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the group. - */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{pools, length}; - } - - /** - * @brief Sort a group according to the given comparison function. - * - * Sort the group so that iterating it with a couple of iterators returns - * entities and components in the expected order. See `begin` and `end` for - * more details. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(std::tuple, std::tuple); - * bool(const Component &, const Component &); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Component` are either owned types or not but still such that they - * are iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Component Optional types of components to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) const { - auto *cpool = std::get<0>(pools); - - if constexpr(sizeof...(Component) == 0) { - static_assert(std::is_invocable_v, "Invalid comparison function"); - cpool->sort_n(*length, std::move(compare), std::move(algo), std::forward(args)...); - } else if constexpr(sizeof...(Component) == 1) { - cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare((std::get *>(pools)->get(lhs), ...), (std::get *>(pools)->get(rhs), ...)); - }, std::move(algo), std::forward(args)...); - } else { - cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare(std::forward_as_tuple(std::get *>(pools)->get(lhs)...), std::forward_as_tuple(std::get *>(pools)->get(rhs)...)); - }, std::move(algo), std::forward(args)...); - } - - [this](auto *head, auto *... other) { - for(auto next = *length; next; --next) { - const auto pos = next - 1; - [[maybe_unused]] const auto entt = head->data()[pos]; - (other->swap(other->data()[pos], entt), ...); - } - }(std::get *>(pools)...); - } - -private: - const std::tuple *..., storage_type *...> pools; - const size_type * const length; -}; - - -} - - -#endif - -// #include "entity/handle.hpp" -#ifndef ENTT_ENTITY_HANDLE_HPP -#define ENTT_ENTITY_HANDLE_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "fwd.hpp" - -// #include "registry.hpp" -#ifndef ENTT_ENTITY_REGISTRY_HPP -#define ENTT_ENTITY_REGISTRY_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "../core/any.hpp" -#ifndef ENTT_CORE_ANY_HPP -#define ENTT_CORE_ANY_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - -// #include "type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "hashed_string.hpp" -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct fnv1a_traits; - - -template<> -struct fnv1a_traits { - using type = std::uint32_t; - static constexpr std::uint32_t offset = 2166136261; - static constexpr std::uint32_t prime = 16777619; -}; - - -template<> -struct fnv1a_traits { - using type = std::uint64_t; - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string { - using traits_type = internal::fnv1a_traits; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {} - const Char *str; - }; - - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT { - auto value = traits_type::offset; - - while(*curr != 0) { - value = (value ^ static_cast(*(curr++))) * traits_type::prime; - } - - return value; - } - -public: - /*! @brief Character type. */ - using value_type = Char; - /*! @brief Unsigned integer type. */ - using hash_type = id_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifer. - * @param size Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT { - id_type partial{traits_type::offset}; - while(size--) { partial = (partial^(str++)[0])*traits_type::prime; } - return partial; - } - - /** - * @brief Returns directly the numeric representation of a string. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * const auto value = basic_hashed_string::to_value("my.png"); - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - * @return The numeric representation of the string. - */ - template - [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT { - return helper(str); - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { - return helper(wrapper.str); - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() ENTT_NOEXCEPT - : str{nullptr}, hash{} - {} - - /** - * @brief Constructs a hashed string from an array of const characters. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * basic_hashed_string hs{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param curr Human-readable identifer. - */ - template - constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT - : str{curr}, hash{helper(curr)} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT - : str{wrapper.str}, hash{helper(wrapper.str)} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - [[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT { - return str; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { - return hash; - } - - /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const value_type *str; - hash_type hash; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the character type of the hashed string directly from a - * human-readable identifer provided to the constructor. - * - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ -template -basic_hashed_string(const Char (&str)[N]) --> basic_hashed_string; - - -/** - * @brief Compares two hashed strings. - * @tparam Char Character type. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const basic_hashed_string &lhs, const basic_hashed_string &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - - -inline namespace literals { - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_string{str}; -} - - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_wstring{str}; -} - - -} - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief A SBO friendly, type-safe container for single values of any type. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_any { - enum class operation { COPY, MOVE, DTOR, COMP, ADDR, CADDR, REF, CREF, TYPE }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void *(const operation, const basic_any &, const void *); - - template - static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v; - - template - [[nodiscard]] static bool compare(const void *lhs, const void *rhs) { - if constexpr(!std::is_function_v && is_equality_comparable_v) { - return *static_cast(lhs) == *static_cast(rhs); - } else { - return lhs == rhs; - } - } - - template - static Type & as(const void *to) { - return *const_cast(static_cast(to)); - } - - template - static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(std::is_void_v) { - switch(op) { - case operation::COPY: - case operation::MOVE: - case operation::REF: - case operation::CREF: - as(to).vtable = from.vtable; - break; - default: - break; - } - } else if constexpr(std::is_lvalue_reference_v) { - using base_type = std::decay_t; - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to) = *static_cast(from.instance); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - as(to).vtable = from.vtable; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - as(to).vtable = from.vtable; - break; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = std::exchange(as(&from).instance, nullptr); - as(to).vtable = from.vtable; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } - - return nullptr; - } - - template - void initialize([[maybe_unused]] Args &&... args) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - if constexpr(std::is_aggregate_v) { - new (&storage) Type{std::forward(args)...}; - } else { - new (&storage) Type(std::forward(args)...); - } - } else { - if constexpr(std::is_aggregate_v) { - instance = new Type{std::forward(args)...}; - } else { - instance = new Type(std::forward(args)...); - } - } - } - } - -public: - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : basic_any{std::in_place_type} - {} - - /** - * @brief Constructs an any by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_any(std::in_place_type_t, Args &&... args) - : instance{}, - vtable{&basic_vtable} - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs an any that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - basic_any(std::reference_wrapper value) ENTT_NOEXCEPT - : basic_any{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs an any from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template, basic_any>>> - basic_any(Type &&value) - : basic_any{std::in_place_type>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any &other) - : basic_any{std::in_place_type} - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{std::in_place_type} - { - other.vtable(operation::MOVE, other, this); - } - - /*! @brief Frees the internal storage, whatever it means. */ - ~basic_any() { - vtable(operation::DTOR, *this, nullptr); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This any object. - */ - basic_any & operator=(const basic_any &other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::COPY, other, this); - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This any object. - */ - basic_any & operator=(basic_any &&other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { - emplace(value.get()); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - std::enable_if_t, basic_any>, basic_any &> - operator=(Type &&value) { - emplace>(std::forward(value)); - return *this; - } - - /** - * @brief Returns the type of the contained object. - * @return The type of the contained object, if any. - */ - [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info{}; - vtable(operation::TYPE, *this, &info); - return info; - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return vtable(operation::CADDR, *this, nullptr); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return const_cast(vtable(operation::ADDR, *this, nullptr)); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - } - - /** - * @brief Returns false if a wrapper is empty, true otherwise. - * @return False if the wrapper is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(vtable(operation::CADDR, *this, nullptr) == nullptr); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - bool operator==(const basic_any &other) const ENTT_NOEXCEPT { - return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); - } - - /** - * @brief Aliasing constructor. - * @return An any that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::REF, *this, &ref); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::CREF, *this, &ref); - return ref; - } - -private: - union { const void *instance; storage_type storage; }; - vtable_type *vtable; -}; - - -/** - * @brief Checks if two wrappers differ in their content. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param lhs A wrapper, either empty or not. - * @param rhs A wrapper, either empty or not. - * @return True if the two wrappers differ in their content, false otherwise. - */ -template -[[nodiscard]] inline bool operator!=(const basic_any &lhs, const basic_any &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Performs type-safe access to the contained object. - * @tparam Type Type to which conversion is required. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param data Target any object. - * @return The element converted to the requested type. - */ -template -Type any_cast(const basic_any &data) ENTT_NOEXCEPT { - const auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &&data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(std::move(*instance)); -} - - -/*! @copydoc any_cast */ -template -const Type * any_cast(const basic_any *data) ENTT_NOEXCEPT { - return (data->type() == type_id() ? static_cast(data->data()) : nullptr); -} - - -/*! @copydoc any_cast */ -template -Type * any_cast(basic_any *data) ENTT_NOEXCEPT { - // last attempt to make wrappers for const references return their values - return (data->type() == type_id() ? static_cast(static_cast, Type> *>(data)->data()) : nullptr); -} - - -} - - -#endif - -// #include "../core/fwd.hpp" - -// #include "../core/type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" - -// #include "hashed_string.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "../core/type_traits.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "group.hpp" -#ifndef ENTT_ENTITY_GROUP_HPP -#define ENTT_ENTITY_GROUP_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "sparse_set.hpp" - -// #include "storage.hpp" - -// #include "utility.hpp" - - - -namespace entt { - - -/** - * @brief Group. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class basic_group; - - -/** - * @brief Non-owning group. - * - * A non-owning group returns all entities and only the entities that have at - * least the given components. Moreover, it's guaranteed that the entity list - * is tightly packed in memory for fast iterations. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the group in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Groups share references to the underlying data structures of the registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by all the - * groups.
- * Moreover, sorting a non-owning group affects all the instances of the same - * group (it means that users don't have to call `sort` on each instance to sort - * all of them because they _share_ entities and components). - * - * @warning - * Lifetime of a group must not overcome that of the registry that generated it. - * In any other case, attempting to use a group results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Exclude Types of components used to filter the group. - * @tparam Get Type of components observed by the group. - */ -template -class basic_group, get_t> final { - /*! @brief A registry is allowed to create groups. */ - friend class basic_registry; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable_group final { - friend class basic_group, get_t>; - - template - class iterable_group_iterator final { - friend class iterable_group; - - template - iterable_group_iterator(It from, const std::tuple *...> &args) ENTT_NOEXCEPT - : it{from}, - pools{args} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_group_iterator & operator++() ENTT_NOEXCEPT { - return ++it, *this; - } - - iterable_group_iterator operator++(int) ENTT_NOEXCEPT { - iterable_group_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - const auto entt = *it; - return std::tuple_cat(std::make_tuple(entt), get_as_tuple(*std::get *>(pools), entt)...); - } - - [[nodiscard]] bool operator==(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple *...> pools; - }; - - iterable_group(basic_sparse_set * const ref, const std::tuple *...> &cpools) - : handler{ref}, - pools{cpools} - {} - - public: - using iterator = iterable_group_iterator::iterator>; - using reverse_iterator = iterable_group_iterator::reverse_iterator>; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return handler ? iterator{handler->begin(), pools} : iterator{{}, pools}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return handler ? iterator{handler->end(), pools} : iterator{{}, pools}; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return handler ? reverse_iterator{handler->rbegin(), pools} : reverse_iterator{{}, pools}; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return handler ? reverse_iterator{handler->rend(), pools} : reverse_iterator{{}, pools}; - } - - private: - basic_sparse_set * const handler; - const std::tuple *...> pools; - }; - - basic_group(basic_sparse_set &ref, storage_type &... gpool) ENTT_NOEXCEPT - : handler{&ref}, - pools{&gpool...} - {} - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = typename basic_sparse_set::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_sparse_set::reverse_iterator; - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() ENTT_NOEXCEPT - : handler{} - {} - - /** - * @brief Returns the number of entities that have the given components. - * @return Number of entities that have the given components. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return *this ? handler->size() : size_type{}; - } - - /** - * @brief Returns the number of elements that a group has currently - * allocated space for. - * @return Capacity of the group. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return *this ? handler->capacity() : size_type{}; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - if(*this) { - handler->shrink_to_fit(); - } - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return !*this || handler->empty(); - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return *this ? handler->data() : nullptr; - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * The returned iterator points to the first entity of the group. If the - * group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return *this ? handler->begin() : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the group. - * - * The returned iterator points to the entity following the last entity of - * the group. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * group. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return *this ? handler->end() : iterator{}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed group. - * - * The returned iterator points to the first entity of the reversed group. - * If the group is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed group. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return *this ? handler->rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * group. - * - * The returned iterator points to the entity following the last entity of - * the reversed group. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed group. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return *this ? handler->rend() : reverse_iterator{}; - } - - /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the group, if any. - * @return The last entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = *this ? handler->find(entt) : iterator{}; - return it != end() && *it == entt ? it : end(); - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[pos]; - } - - /** - * @brief Checks if a group is properly initialized. - * @return True if the group is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return handler != nullptr; - } - - /** - * @brief Checks if a group contains an entity. - * @param entt A valid entity identifier. - * @return True if the group contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return *this && handler->contains(entt); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the group - * results in undefined behavior. - * - * @tparam Component Types of components to get. - * @param entt A valid entity identifier. - * @return The components assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Component) == 0) { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } else if constexpr(sizeof...(Component) == 1) { - return (std::get *>(pools)->get(entt), ...); - } else { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty components. The - * _constness_ of the components is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entt: *this) { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); - } else { - std::apply(func, get(entt)); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ the group. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty components. The _constness_ of the - * components is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the group. - */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{handler, pools}; - } - - /** - * @brief Sort a group according to the given comparison function. - * - * Sort the group so that iterating it with a couple of iterators returns - * entities and components in the expected order. See `begin` and `end` for - * more details. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(std::tuple, std::tuple); - * bool(const Component &..., const Component &...); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Component` are such that they are iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Component Optional types of components to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - if(*this) { - if constexpr(sizeof...(Component) == 0) { - static_assert(std::is_invocable_v, "Invalid comparison function"); - handler->sort(std::move(compare), std::move(algo), std::forward(args)...); - } else if constexpr(sizeof...(Component) == 1) { - handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare((std::get *>(pools)->get(lhs), ...), (std::get *>(pools)->get(rhs), ...)); - }, std::move(algo), std::forward(args)...); - } else { - handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare(std::forward_as_tuple(std::get *>(pools)->get(lhs)...), std::forward_as_tuple(std::get *>(pools)->get(rhs)...)); - }, std::move(algo), std::forward(args)...); - } - } - } - - /** - * @brief Sort the shared pool of entities according to the given component. - * - * Non-owning groups of the same type share with the registry a pool of - * entities with its own order that doesn't depend on the order of any pool - * of components. Users can order the underlying data structure so that it - * respects the order of the pool of the given component. - * - * @note - * The shared pool of entities and thus its order is affected by the changes - * to each and every pool that it tracks. Therefore changes to those pools - * can quickly ruin the order imposed to the pool of entities shared between - * the non-owning groups. - * - * @tparam Component Type of component to use to impose the order. - */ - template - void sort() const { - if(*this) { - handler->respect(*std::get *>(pools)); - } - } - -private: - basic_sparse_set * const handler; - const std::tuple *...> pools; -}; - - -/** - * @brief Owning group. - * - * Owning groups return all entities and only the entities that have at least - * the given components. Moreover: - * - * * It's guaranteed that the entity list is tightly packed in memory for fast - * iterations. - * * It's guaranteed that the lists of owned components are tightly packed in - * memory for even faster iterations and to allow direct access. - * * They stay true to the order of the owned components and all instances have - * the same order in memory. - * - * The more types of components are owned by a group, the faster it is to - * iterate them. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the group in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Groups share references to the underlying data structures of the registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by all the - * groups. - * Moreover, sorting an owning group affects all the instance of the same group - * (it means that users don't have to call `sort` on each instance to sort all - * of them because they share the underlying data structure). - * - * @warning - * Lifetime of a group must not overcome that of the registry that generated it. - * In any other case, attempting to use a group results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Exclude Types of components used to filter the group. - * @tparam Get Types of components observed by the group. - * @tparam Owned Types of components owned by the group. - */ -template -class basic_group, get_t, Owned...> final { - /*! @brief A registry is allowed to create groups. */ - friend class basic_registry; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable_group final { - friend class basic_group, get_t, Owned...>; - - template - class iterable_group_iterator; - - template - class iterable_group_iterator> final { - friend class iterable_group; - - template - iterable_group_iterator(It from, const std::tuple &other, const std::tuple *...> &cpools) ENTT_NOEXCEPT - : it{from}, - owned{std::get(other)...}, - get{cpools} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_group_iterator & operator++() ENTT_NOEXCEPT { - return ++it, (++std::get(owned), ...), *this; - } - - iterable_group_iterator operator++(int) ENTT_NOEXCEPT { - iterable_group_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat( - std::make_tuple(*it), - std::forward_as_tuple(*std::get(owned)...), - get_as_tuple(*std::get *>(get), *it)... - ); - } - - [[nodiscard]] bool operator==(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_group_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple owned; - std::tuple *...> get; - }; - - iterable_group(std::tuple *..., storage_type *...> cpools, const std::size_t * const extent) - : pools{cpools}, - length{extent} - {} - - public: - using iterator = iterable_group_iterator< - typename basic_sparse_set::iterator, - type_list_cat_t>().get({}))>, type_list<>, type_list>().end())>>...> - >; - using reverse_iterator = iterable_group_iterator< - typename basic_sparse_set::reverse_iterator, - type_list_cat_t>().get({}))>, type_list<>, type_list>().rbegin())>>...> - >; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return length ? iterator{ - std::get<0>(pools)->basic_sparse_set::end() - *length, - std::make_tuple((std::get *>(pools)->end() - *length)...), - std::make_tuple(std::get *>(pools)...) - } : iterator{{}, std::make_tuple(decltype(std::get *>(pools)->end()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return length ? iterator{ - std::get<0>(pools)->basic_sparse_set::end(), - std::make_tuple((std::get *>(pools)->end())...), - std::make_tuple(std::get *>(pools)...) - } : iterator{{}, std::make_tuple(decltype(std::get *>(pools)->end()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return length ? reverse_iterator{ - std::get<0>(pools)->basic_sparse_set::rbegin(), - std::make_tuple((std::get *>(pools)->rbegin())...), - std::make_tuple(std::get *>(pools)...) - } : reverse_iterator{{}, std::make_tuple(decltype(std::get *>(pools)->rbegin()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return length ? reverse_iterator{ - std::get<0>(pools)->basic_sparse_set::rbegin() + *length, - std::make_tuple((std::get *>(pools)->rbegin() + *length)...), - std::make_tuple(std::get *>(pools)...) - } : reverse_iterator{{}, std::make_tuple(decltype(std::get *>(pools)->rbegin()){}...), std::make_tuple(std::get *>(pools)...)}; - } - - private: - const std::tuple *..., storage_type *...> pools; - const std::size_t * const length; - }; - - basic_group(const std::size_t &extent, storage_type &... opool, storage_type &... gpool) ENTT_NOEXCEPT - : pools{&opool..., &gpool...}, - length{&extent} - {} - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = typename basic_sparse_set::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_sparse_set::reverse_iterator; - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() ENTT_NOEXCEPT - : length{} - {} - - /** - * @brief Returns the number of entities that have the given components. - * @return Number of entities that have the given components. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return *this ? *length : size_type{}; - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return !*this || !*length; - } - - /** - * @brief Direct access to the list of components of a given pool. - * - * The returned pointer is such that range - * `[raw(), raw() + size())` is always a valid range, - * even if the container is empty.
- * - * @warning - * This function is only available for owned types. - * - * @tparam Component Type of component in which one is interested. - * @return A pointer to the array of components. - */ - template - [[nodiscard]] Component * raw() const ENTT_NOEXCEPT { - static_assert((std::is_same_v || ...), "Non-owned type"); - auto *cpool = std::get *>(pools); - return cpool ? cpool->raw() : nullptr; - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return *this ? std::get<0>(pools)->data() : nullptr; - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * The returned iterator points to the first entity of the group. If the - * group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return *this ? (std::get<0>(pools)->basic_sparse_set::end() - *length) : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the group. - * - * The returned iterator points to the entity following the last entity of - * the group. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * group. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return *this ? std::get<0>(pools)->basic_sparse_set::end() : iterator{}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed group. - * - * The returned iterator points to the first entity of the reversed group. - * If the group is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed group. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return *this ? std::get<0>(pools)->basic_sparse_set::rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * group. - * - * The returned iterator points to the entity following the last entity of - * the reversed group. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed group. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return *this ? (std::get<0>(pools)->basic_sparse_set::rbegin() + *length) : reverse_iterator{}; - } - - /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the group, if any. - * @return The last entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = *this ? std::get<0>(pools)->find(entt) : iterator{}; - return it != end() && it >= begin() && *it == entt ? it : end(); - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[pos]; - } - - /** - * @brief Checks if a group is properly initialized. - * @return True if the group is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return length != nullptr; - } - - /** - * @brief Checks if a group contains an entity. - * @param entt A valid entity identifier. - * @return True if the group contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return *this && std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < (*length)); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the group - * results in undefined behavior. - * - * @tparam Component Types of components to get. - * @param entt A valid entity identifier. - * @return The components assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Component) == 0) { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)..., get_as_tuple(*std::get *>(pools), entt)...); - } else if constexpr(sizeof...(Component) == 1) { - return (std::get *>(pools)->get(entt), ...); - } else { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty components. The - * _constness_ of the components is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(auto args: each()) { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, args); - } else { - std::apply([&func](auto, auto &&... less) { func(std::forward(less)...); }, args); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ the group. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty components. The _constness_ of the - * components is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the group. - */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{pools, length}; - } - - /** - * @brief Sort a group according to the given comparison function. - * - * Sort the group so that iterating it with a couple of iterators returns - * entities and components in the expected order. See `begin` and `end` for - * more details. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(std::tuple, std::tuple); - * bool(const Component &, const Component &); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Component` are either owned types or not but still such that they - * are iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Component Optional types of components to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) const { - auto *cpool = std::get<0>(pools); - - if constexpr(sizeof...(Component) == 0) { - static_assert(std::is_invocable_v, "Invalid comparison function"); - cpool->sort_n(*length, std::move(compare), std::move(algo), std::forward(args)...); - } else if constexpr(sizeof...(Component) == 1) { - cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare((std::get *>(pools)->get(lhs), ...), (std::get *>(pools)->get(rhs), ...)); - }, std::move(algo), std::forward(args)...); - } else { - cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { - return compare(std::forward_as_tuple(std::get *>(pools)->get(lhs)...), std::forward_as_tuple(std::get *>(pools)->get(rhs)...)); - }, std::move(algo), std::forward(args)...); - } - - [this](auto *head, auto *... other) { - for(auto next = *length; next; --next) { - const auto pos = next - 1; - [[maybe_unused]] const auto entt = head->data()[pos]; - (other->swap(other->data()[pos], entt), ...); - } - }(std::get *>(pools)...); - } - -private: - const std::tuple *..., storage_type *...> pools; - const size_type * const length; -}; - - -} - - -#endif - -// #include "poly_storage.hpp" -#ifndef ENTT_ENTITY_POLY_STORAGE_HPP -#define ENTT_ENTITY_POLY_STORAGE_HPP - - -#include -#include -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "../poly/poly.hpp" -#ifndef ENTT_POLY_POLY_HPP -#define ENTT_POLY_POLY_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "../core/any.hpp" -#ifndef ENTT_CORE_ANY_HPP -#define ENTT_CORE_ANY_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - -// #include "type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "hashed_string.hpp" -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct fnv1a_traits; - - -template<> -struct fnv1a_traits { - using type = std::uint32_t; - static constexpr std::uint32_t offset = 2166136261; - static constexpr std::uint32_t prime = 16777619; -}; - - -template<> -struct fnv1a_traits { - using type = std::uint64_t; - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string { - using traits_type = internal::fnv1a_traits; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {} - const Char *str; - }; - - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT { - auto value = traits_type::offset; - - while(*curr != 0) { - value = (value ^ static_cast(*(curr++))) * traits_type::prime; - } - - return value; - } - -public: - /*! @brief Character type. */ - using value_type = Char; - /*! @brief Unsigned integer type. */ - using hash_type = id_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifer. - * @param size Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT { - id_type partial{traits_type::offset}; - while(size--) { partial = (partial^(str++)[0])*traits_type::prime; } - return partial; - } - - /** - * @brief Returns directly the numeric representation of a string. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * const auto value = basic_hashed_string::to_value("my.png"); - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - * @return The numeric representation of the string. - */ - template - [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT { - return helper(str); - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { - return helper(wrapper.str); - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() ENTT_NOEXCEPT - : str{nullptr}, hash{} - {} - - /** - * @brief Constructs a hashed string from an array of const characters. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * basic_hashed_string hs{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param curr Human-readable identifer. - */ - template - constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT - : str{curr}, hash{helper(curr)} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT - : str{wrapper.str}, hash{helper(wrapper.str)} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - [[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT { - return str; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { - return hash; - } - - /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const value_type *str; - hash_type hash; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the character type of the hashed string directly from a - * human-readable identifer provided to the constructor. - * - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ -template -basic_hashed_string(const Char (&str)[N]) --> basic_hashed_string; - - -/** - * @brief Compares two hashed strings. - * @tparam Char Character type. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const basic_hashed_string &lhs, const basic_hashed_string &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - - -inline namespace literals { - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_string{str}; -} - - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_wstring{str}; -} - - -} - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief A SBO friendly, type-safe container for single values of any type. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_any { - enum class operation { COPY, MOVE, DTOR, COMP, ADDR, CADDR, REF, CREF, TYPE }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void *(const operation, const basic_any &, const void *); - - template - static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v; - - template - [[nodiscard]] static bool compare(const void *lhs, const void *rhs) { - if constexpr(!std::is_function_v && is_equality_comparable_v) { - return *static_cast(lhs) == *static_cast(rhs); - } else { - return lhs == rhs; - } - } - - template - static Type & as(const void *to) { - return *const_cast(static_cast(to)); - } - - template - static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(std::is_void_v) { - switch(op) { - case operation::COPY: - case operation::MOVE: - case operation::REF: - case operation::CREF: - as(to).vtable = from.vtable; - break; - default: - break; - } - } else if constexpr(std::is_lvalue_reference_v) { - using base_type = std::decay_t; - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to) = *static_cast(from.instance); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - as(to).vtable = from.vtable; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - as(to).vtable = from.vtable; - break; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = std::exchange(as(&from).instance, nullptr); - as(to).vtable = from.vtable; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } - - return nullptr; - } - - template - void initialize([[maybe_unused]] Args &&... args) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - if constexpr(std::is_aggregate_v) { - new (&storage) Type{std::forward(args)...}; - } else { - new (&storage) Type(std::forward(args)...); - } - } else { - if constexpr(std::is_aggregate_v) { - instance = new Type{std::forward(args)...}; - } else { - instance = new Type(std::forward(args)...); - } - } - } - } - -public: - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : basic_any{std::in_place_type} - {} - - /** - * @brief Constructs an any by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_any(std::in_place_type_t, Args &&... args) - : instance{}, - vtable{&basic_vtable} - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs an any that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - basic_any(std::reference_wrapper value) ENTT_NOEXCEPT - : basic_any{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs an any from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template, basic_any>>> - basic_any(Type &&value) - : basic_any{std::in_place_type>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any &other) - : basic_any{std::in_place_type} - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{std::in_place_type} - { - other.vtable(operation::MOVE, other, this); - } - - /*! @brief Frees the internal storage, whatever it means. */ - ~basic_any() { - vtable(operation::DTOR, *this, nullptr); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This any object. - */ - basic_any & operator=(const basic_any &other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::COPY, other, this); - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This any object. - */ - basic_any & operator=(basic_any &&other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { - emplace(value.get()); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - std::enable_if_t, basic_any>, basic_any &> - operator=(Type &&value) { - emplace>(std::forward(value)); - return *this; - } - - /** - * @brief Returns the type of the contained object. - * @return The type of the contained object, if any. - */ - [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info{}; - vtable(operation::TYPE, *this, &info); - return info; - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return vtable(operation::CADDR, *this, nullptr); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return const_cast(vtable(operation::ADDR, *this, nullptr)); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - } - - /** - * @brief Returns false if a wrapper is empty, true otherwise. - * @return False if the wrapper is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(vtable(operation::CADDR, *this, nullptr) == nullptr); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - bool operator==(const basic_any &other) const ENTT_NOEXCEPT { - return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); - } - - /** - * @brief Aliasing constructor. - * @return An any that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::REF, *this, &ref); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::CREF, *this, &ref); - return ref; - } - -private: - union { const void *instance; storage_type storage; }; - vtable_type *vtable; -}; - - -/** - * @brief Checks if two wrappers differ in their content. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param lhs A wrapper, either empty or not. - * @param rhs A wrapper, either empty or not. - * @return True if the two wrappers differ in their content, false otherwise. - */ -template -[[nodiscard]] inline bool operator!=(const basic_any &lhs, const basic_any &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Performs type-safe access to the contained object. - * @tparam Type Type to which conversion is required. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param data Target any object. - * @return The element converted to the requested type. - */ -template -Type any_cast(const basic_any &data) ENTT_NOEXCEPT { - const auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &&data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(std::move(*instance)); -} - - -/*! @copydoc any_cast */ -template -const Type * any_cast(const basic_any *data) ENTT_NOEXCEPT { - return (data->type() == type_id() ? static_cast(data->data()) : nullptr); -} - - -/*! @copydoc any_cast */ -template -Type * any_cast(basic_any *data) ENTT_NOEXCEPT { - // last attempt to make wrappers for const references return their values - return (data->type() == type_id() ? static_cast(static_cast, Type> *>(data)->data()) : nullptr); -} - - -} - - -#endif - -// #include "../core/type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" - -// #include "hashed_string.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "../core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_POLY_FWD_HPP -#define ENTT_POLY_FWD_HPP - - -#include - - -namespace entt { - - -template)> -class basic_poly; - - -/** - * @brief Alias declaration for the most common use case. - * @tparam Concept Concept descriptor. - */ -template -using poly = basic_poly; - - -} - - -#endif - - - -namespace entt { - - -/*! @brief Inspector class used to infer the type of the virtual table. */ -struct poly_inspector { - /** - * @brief Generic conversion operator (definition only). - * @tparam Type Type to which conversion is requested. - */ - template - operator Type &&() const; - - /** - * @brief Dummy invocation function (definition only). - * @tparam Member Index of the function to invoke. - * @tparam Args Types of arguments to pass to the function. - * @param args The arguments to pass to the function. - * @return A poly inspector convertible to any type. - */ - template - poly_inspector invoke(Args &&... args) const; - - /*! @copydoc invoke */ - template - poly_inspector invoke(Args &&... args); -}; - - -/** - * @brief Static virtual table factory. - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - */ -template -class poly_vtable { - using inspector = typename Concept::template type; - - template - static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(basic_any &, Args...); - - template - static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const basic_any &, Args...); - - template - static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const basic_any &, Args...); - - template - static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(basic_any &, Args...); - - template - static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const basic_any &, Args...); - - template - static auto make_vtable(value_list) - -> decltype(std::make_tuple(vtable_entry(Candidate)...)); - - template - [[nodiscard]] static constexpr auto make_vtable(type_list) { - if constexpr(sizeof...(Func) == 0) { - return decltype(make_vtable(typename Concept::template impl{})){}; - } else if constexpr((std::is_function_v && ...)) { - return decltype(std::make_tuple(vtable_entry(std::declval())...)){}; - } - } - - template - static void fill_vtable_entry(Ret(* &entry)(Any &, Args...)) { - if constexpr(std::is_invocable_r_v) { - entry = +[](Any &, Args... args) -> Ret { - return std::invoke(Candidate, std::forward(args)...); - }; - } else { - entry = +[](Any &instance, Args... args) -> Ret { - return static_cast(std::invoke(Candidate, any_cast &>(instance), std::forward(args)...)); - }; - } - } - - template - [[nodiscard]] static auto fill_vtable(std::index_sequence) { - type impl{}; - (fill_vtable_entry>>(std::get(impl)), ...); - return impl; - } - -public: - /*! @brief Virtual table type. */ - using type = decltype(make_vtable(Concept{})); - - /** - * @brief Returns a static virtual table for a specific concept and type. - * @tparam Type The type for which to generate the virtual table. - * @return A static virtual table for the given concept and type. - */ - template - [[nodiscard]] static const auto * instance() { - static_assert(std::is_same_v>, "Type differs from its decayed form"); - static const auto vtable = fill_vtable(std::make_index_sequence::size>{}); - return &vtable; - } -}; - - -/** - * @brief Poly base class used to inject functionalities into concepts. - * @tparam Poly The outermost poly class. - */ -template -struct poly_base { - /** - * @brief Invokes a function from the static virtual table. - * @tparam Member Index of the function to invoke. - * @tparam Args Types of arguments to pass to the function. - * @param self A reference to the poly object that made the call. - * @param args The arguments to pass to the function. - * @return The return value of the invoked function, if any. - */ - template - [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&... args) const { - const auto &poly = static_cast(self); - return std::get(*poly.vtable)(poly.storage, std::forward(args)...); - } - - /*! @copydoc invoke */ - template - [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&... args) { - auto &poly = static_cast(self); - return std::get(*poly.vtable)(poly.storage, std::forward(args)...); - } -}; - - -/** - * @brief Shortcut for calling `poly_base::invoke`. - * @tparam Member Index of the function to invoke. - * @tparam Poly A fully defined poly object. - * @tparam Args Types of arguments to pass to the function. - * @param self A reference to the poly object that made the call. - * @param args The arguments to pass to the function. - * @return The return value of the invoked function, if any. - */ -template -decltype(auto) poly_call(Poly &&self, Args &&... args) { - return std::forward(self).template invoke(self, std::forward(args)...); -} - - -/** - * @brief Static polymorphism made simple and within everyone's reach. - * - * Static polymorphism is a very powerful tool in C++, albeit sometimes - * cumbersome to obtain.
- * This class aims to make it simple and easy to use. - * - * @note - * Both deduced and defined static virtual tables are supported.
- * Moreover, the `poly` class template also works with unmanaged objects. - * - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_poly: private Concept::template type>> { - /*! @brief A poly base is allowed to snoop into a poly object. */ - friend struct poly_base; - - using vtable_type = typename poly_vtable::type; - -public: - /*! @brief Concept type. */ - using concept_type = typename Concept::template type>; - - /*! @brief Default constructor. */ - basic_poly() ENTT_NOEXCEPT - : storage{}, - vtable{} - {} - - /** - * @brief Constructs a poly by directly initializing the new object. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_poly(std::in_place_type_t, Args &&... args) - : storage{std::in_place_type, std::forward(args)...}, - vtable{poly_vtable::template instance>>()} - {} - - /** - * @brief Constructs a poly that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the poly. - * @param value An instance of an object to use to initialize the poly. - */ - template - basic_poly(std::reference_wrapper value) - : basic_poly{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs a poly from a given value. - * @tparam Type Type of object to use to initialize the poly. - * @param value An instance of an object to use to initialize the poly. - */ - template>, basic_poly>>> - basic_poly(Type &&value) ENTT_NOEXCEPT - : basic_poly{std::in_place_type>>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_poly(const basic_poly &other) = default; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_poly(basic_poly &&other) ENTT_NOEXCEPT - : basic_poly{} - { - swap(*this, other); - } - - /** - * @brief Assignment operator. - * @param other The instance to assign from. - * @return This poly object. - */ - basic_poly & operator=(basic_poly other) { - swap(other, *this); - return *this; - } - - /** - * @brief Returns the type of the contained object. - * @return The type of the contained object, if any. - */ - [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - return storage.type(); - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return storage.data(); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return storage.data(); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - *this = basic_poly{std::in_place_type, std::forward(args)...}; - } - - /*! @brief Destroys contained object */ - void reset() { - *this = basic_poly{}; - } - - /** - * @brief Returns false if a poly is empty, true otherwise. - * @return False if the poly is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(vtable == nullptr); - } - - /** - * @brief Returns a pointer to the underlying concept. - * @return A pointer to the underlying concept. - */ - [[nodiscard]] concept_type * operator->() ENTT_NOEXCEPT { - return this; - } - - /*! @copydoc operator-> */ - [[nodiscard]] const concept_type * operator->() const ENTT_NOEXCEPT { - return this; - } - - /** - * @brief Swaps two poly objects. - * @param lhs A valid poly object. - * @param rhs A valid poly object. - */ - friend void swap(basic_poly &lhs, basic_poly &rhs) { - using std::swap; - swap(lhs.storage, rhs.storage); - swap(lhs.vtable, rhs.vtable); - } - - /** - * @brief Aliasing constructor. - * @return A poly that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_poly as_ref() ENTT_NOEXCEPT { - basic_poly ref = std::as_const(*this).as_ref(); - ref.storage = storage.as_ref(); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_poly as_ref() const ENTT_NOEXCEPT { - basic_poly ref{}; - ref.storage = storage.as_ref(); - ref.vtable = vtable; - return ref; - } - -private: - basic_any storage; - const vtable_type *vtable; -}; - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Basic poly storage implementation. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct Storage: type_list { - /** - * @brief Concept definition. - * @tparam Base Opaque base class from which to inherit. - */ - template - struct type: Base { - /** - * @brief Returns a type info for the contained objects. - * @return The type info for the contained objects. - */ - type_info value_type() const ENTT_NOEXCEPT { - return poly_call<0>(*this); - } - }; - - /** - * @brief Concept implementation. - * @tparam Type Type for which to generate an implementation. - */ - template - using impl = value_list<&type_id>; -}; - - -/** - * @brief Defines the poly storage type associate with a given entity type. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct poly_storage_traits { - /*! @brief Poly storage type for the given entity type. */ - using storage_type = poly>; -}; - - -} - - -#endif - -// #include "runtime_view.hpp" -#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP -#define ENTT_ENTITY_RUNTIME_VIEW_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "sparse_set.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Runtime view. - * - * Runtime views iterate over those entities that have at least all the given - * components in their bags. During initialization, a runtime view looks at the - * number of entities available for each component and picks up a reference to - * the smallest set of candidate entities in order to get a performance boost - * when iterate.
- * Order of elements during iterations are highly dependent on the order of the - * underlying data structures. See sparse_set and its specializations for more - * details. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all the other cases, modifying the pools of the given components in any - * way invalidates all the iterators and using them results in undefined - * behavior. - * - * @note - * Views share references to the underlying data structures of the registry that - * generated them. Therefore any change to the entities and to the components - * made by means of the registry are immediately reflected by the views, unless - * a pool was missing when the view was built (in this case, the view won't - * have a valid reference and won't be updated accordingly). - * - * @warning - * Lifetime of a view must not overcome that of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_runtime_view final { - using underlying_iterator = typename basic_sparse_set::iterator; - - class view_iterator final { - friend class basic_runtime_view; - - view_iterator(const std::vector *> &cpools, const std::vector *> &ignore, underlying_iterator curr) ENTT_NOEXCEPT - : pools{&cpools}, - filter{&ignore}, - it{curr} - { - if(it != (*pools)[0]->end() && !valid()) { - ++(*this); - } - } - - [[nodiscard]] bool valid() const { - return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); }) - && std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); }); - } - - public: - using difference_type = typename underlying_iterator::difference_type; - using value_type = typename underlying_iterator::value_type; - using pointer = typename underlying_iterator::pointer; - using reference = typename underlying_iterator::reference; - using iterator_category = std::bidirectional_iterator_tag; - - view_iterator() ENTT_NOEXCEPT = default; - - view_iterator & operator++() { - while(++it != (*pools)[0]->end() && !valid()); - return *this; - } - - view_iterator operator++(int) { - view_iterator orig = *this; - return ++(*this), orig; - } - - view_iterator & operator--() ENTT_NOEXCEPT { - while(--it != (*pools)[0]->begin() && !valid()); - return *this; - } - - view_iterator operator--(int) ENTT_NOEXCEPT { - view_iterator orig = *this; - return operator--(), orig; - } - - [[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] pointer operator->() const { - return it.operator->(); - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - const std::vector *> *pools; - const std::vector *> *filter; - underlying_iterator it; - }; - - [[nodiscard]] bool valid() const { - return !pools.empty() && pools.front(); - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Bidirectional iterator type. */ - using iterator = view_iterator; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_runtime_view() ENTT_NOEXCEPT - : pools{}, - filter{} - {} - - /** - * @brief Constructs a runtime view from a set of storage classes. - * @param cpools The storage for the types to iterate. - * @param epools The storage for the types used to filter the view. - */ - basic_runtime_view(std::vector *> cpools, std::vector *> epools) ENTT_NOEXCEPT - : pools{std::move(cpools)}, - filter{std::move(epools)} - { - const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) { - return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size()); - }); - - // brings the best candidate (if any) on front of the vector - std::rotate(pools.begin(), it, pools.end()); - } - - /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. - */ - [[nodiscard]] size_type size_hint() const { - return valid() ? pools.front()->size() : size_type{}; - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @return An iterator to the first entity that has the given components. - */ - [[nodiscard]] iterator begin() const { - return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - [[nodiscard]] iterator end() const { - return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{}; - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); }) - && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); }); - } - - /** - * @brief Iterates entities and applies the given function object to them. - * - * The function object is invoked for each entity. It is provided only with - * the entity itself. To get the components, users can use the registry with - * which the view was built.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entity: *this) { - func(entity); - } - } - -private: - std::vector *> pools; - std::vector *> filter; -}; - - -} - - -#endif - -// #include "sparse_set.hpp" - -// #include "storage.hpp" - -// #include "utility.hpp" - -// #include "view.hpp" -#ifndef ENTT_ENTITY_VIEW_HPP -#define ENTT_ENTITY_VIEW_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "sparse_set.hpp" - -// #include "storage.hpp" - -// #include "utility.hpp" - - - -namespace entt { - - -/** - * @brief View. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class basic_view; - - -/** - * @brief Multi component view. - * - * Multi component views iterate over those entities that have at least all the - * given components in their bags. During initialization, a multi component view - * looks at the number of entities available for each component and uses the - * smallest set in order to get a performance boost when iterate. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the view in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Views share references to the underlying data structures of the registry that - * generated them. Therefore any change to the entities and to the components - * made by means of the registry are immediately reflected by views. - * - * @warning - * Lifetime of a view must not overcome that of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Exclude Types of components used to filter the view. - * @tparam Component Types of components iterated by the view. - */ -template -class basic_view, Component...> final { - template - using storage_type = constness_as_t>::storage_type, Comp>; - - using unchecked_type = std::array *, (sizeof...(Component) - 1)>; - - template - class view_iterator final { - friend class basic_view, Component...>; - - view_iterator(It from, It to, It curr, unchecked_type other, const std::tuple *...> &ignore) ENTT_NOEXCEPT - : first{from}, - last{to}, - it{curr}, - unchecked{other}, - filter{ignore} - { - if(it != last && !valid()) { - ++(*this); - } - } - - [[nodiscard]] bool valid() const { - const auto entt = *it; - - return std::all_of(unchecked.cbegin(), unchecked.cend(), [entt](const basic_sparse_set *curr) { return curr->contains(entt); }) - && !(std::get *>(filter)->contains(entt) || ...); - } - - public: - using difference_type = typename std::iterator_traits::difference_type; - using value_type = typename std::iterator_traits::value_type; - using pointer = typename std::iterator_traits::pointer; - using reference = typename std::iterator_traits::reference; - using iterator_category = std::bidirectional_iterator_tag; - - view_iterator() ENTT_NOEXCEPT - : view_iterator{{}, {}, {}, {}, {}} - {} - - view_iterator & operator++() ENTT_NOEXCEPT { - while(++it != last && !valid()); - return *this; - } - - view_iterator operator++(int) ENTT_NOEXCEPT { - view_iterator orig = *this; - return ++(*this), orig; - } - - view_iterator & operator--() ENTT_NOEXCEPT { - while(--it != first && !valid()); - return *this; - } - - view_iterator operator--(int) ENTT_NOEXCEPT { - view_iterator orig = *this; - return operator--(), orig; - } - - [[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] pointer operator->() const { - return &*it; - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - It first; - It last; - It it; - unchecked_type unchecked; - std::tuple *...> filter; - }; - - class iterable_view final { - friend class basic_view, Component...>; - - template - class iterable_view_iterator final { - friend class iterable_view; - - iterable_view_iterator(It from, const basic_view *parent) ENTT_NOEXCEPT - : it{from}, - view{parent} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_view_iterator & operator++() ENTT_NOEXCEPT { - return ++it, *this; - } - - iterable_view_iterator operator++(int) ENTT_NOEXCEPT { - iterable_view_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat(std::make_tuple(*it), view->get(*it)); - } - - [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - const basic_view *view; - }; - - iterable_view(const basic_view &parent) - : view{parent} - {} - - public: - using iterator = iterable_view_iterator::iterator>>; - using reverse_iterator = iterable_view_iterator::reverse_iterator>>; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return { view.begin(), &view }; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return { view.end(), &view }; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return { view.rbegin(), &view }; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return { view.rend(), &view }; - } - - private: - const basic_view view; - }; - - [[nodiscard]] const basic_sparse_set * candidate() const ENTT_NOEXCEPT { - return (std::min)({ static_cast *>(std::get *>(pools))... }, [](const auto *lhs, const auto *rhs) { - return lhs->size() < rhs->size(); - }); - } - - [[nodiscard]] unchecked_type unchecked(const basic_sparse_set *cpool) const { - std::size_t pos{}; - unchecked_type other{}; - (static_cast(std::get *>(pools) == cpool ? void() : void(other[pos++] = std::get *>(pools))), ...); - return other; - } - - template - [[nodiscard]] auto dispatch_get([[maybe_unused]] It &it, [[maybe_unused]] const Entity entt) const { - if constexpr(std::is_same_v::value_type, typename storage_type::value_type>) { - return std::forward_as_tuple(*it); - } else { - return get_as_tuple(*std::get *>(pools), entt); - } - } - - template - void traverse(Func func) const { - if constexpr(std::is_void_v *>(pools)->get({}))>) { - for(const auto entt: static_cast &>(*std::get *>(pools))) { - if(((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && !(std::get *>(filter)->contains(entt) || ...)) - { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); - } else { - std::apply(func, get(entt)); - } - } - } - } else { - auto it = std::get *>(pools)->begin(); - - for(const auto entt: static_cast &>(*std::get *>(pools))) { - if(((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && !(std::get *>(filter)->contains(entt) || ...)) - { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get(it, entt)...)); - } else { - std::apply(func, std::tuple_cat(dispatch_get(it, entt)...)); - } - } - - ++it; - } - } - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Bidirectional iterator type. */ - using iterator = view_iterator::iterator>; - /*! @brief Reverse iterator type. */ - using reverse_iterator = view_iterator::reverse_iterator>; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view() ENTT_NOEXCEPT - : view{} - {} - - /** - * @brief Constructs a multi-type view from a set of storage classes. - * @param component The storage for the types to iterate. - * @param epool The storage for the types used to filter the view. - */ - basic_view(storage_type &... component, const storage_type &... epool) ENTT_NOEXCEPT - : pools{&component...}, - filter{&epool...}, - view{candidate()} - {} - - /** - * @brief Forces the type to use to drive iterations. - * @tparam Comp Type of component to use to drive the iteration. - */ - template - void use() const ENTT_NOEXCEPT { - view = std::get *>(pools); - } - - /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. - */ - [[nodiscard]] size_type size_hint() const ENTT_NOEXCEPT { - return view->size(); - } - - /** - * @brief Returns an iterator to the first entity of the view. - * - * The returned iterator points to the first entity of the view. If the view - * is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the view. - */ - [[nodiscard]] iterator begin() const { - return iterator{view->begin(), view->end(), view->begin(), unchecked(view), filter}; - } - - /** - * @brief Returns an iterator that is past the last entity of the view. - * - * The returned iterator points to the entity following the last entity of - * the view. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the view. - */ - [[nodiscard]] iterator end() const { - return iterator{view->begin(), view->end(), view->end(), unchecked(view), filter}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed view. - * - * The returned iterator points to the first entity of the reversed view. If - * the view is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed view. - */ - [[nodiscard]] reverse_iterator rbegin() const { - return reverse_iterator{view->rbegin(), view->rend(), view->rbegin(), unchecked(view), filter}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * view. - * - * The returned iterator points to the entity following the last entity of - * the reversed view. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed view. - */ - [[nodiscard]] reverse_iterator rend() const { - return reverse_iterator{view->rbegin(), view->rend(), view->rend(), unchecked(view), filter}; - } - - /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the view, if any. - * @return The last entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = iterator{view->begin(), view->end(), view->find(entt), unchecked(view), filter}; - return (it != end() && *it == entt) ? it : end(); - } - - /** - * @brief Checks if a view is properly initialized. - * @return True if the view is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return view != nullptr; - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return (std::get *>(pools)->contains(entt) && ...) && !(std::get *>(filter)->contains(entt) || ...); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior. - * - * @tparam Comp Types of components to get. - * @param entt A valid entity identifier. - * @return The components assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Comp) == 0) { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } else if constexpr(sizeof...(Comp) == 1) { - return (std::get *>(pools)->get(entt), ...); - } else { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty components. The - * _constness_ of the components is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - ((std::get *>(pools) == view ? traverse(std::move(func)) : void()), ...); - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The pool of the suggested component is used to lead the iterations. The - * returned entities will therefore respect the order of the pool associated - * with that type.
- * It is no longer guaranteed that the performance is the best possible, but - * there will be greater control over the order of iteration. - * - * @sa each - * - * @tparam Comp Type of component to use to drive the iteration. - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - use(); - traverse(std::move(func)); - } - - /** - * @brief Returns an iterable object to use to _visit_ the view. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty components. The _constness_ of the - * components is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the view. - */ - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - return iterable_view{*this}; - } - - /** - * @brief Returns an iterable object to use to _visit_ the view. - * - * The pool of the suggested component is used to lead the iterations. The - * returned elements will therefore respect the order of the pool associated - * with that type.
- * It is no longer guaranteed that the performance is the best possible, but - * there will be greater control over the order of iteration. - * - * @sa each - * - * @tparam Comp Type of component to use to drive the iteration. - * @return An iterable object to use to _visit_ the view. - */ - template - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - use(); - return iterable_view{*this}; - } - - /** - * @brief Combines two views in a _more specific_ one (friend function). - * @tparam Id A valid entity type (see entt_traits for more details). - * @tparam ELhs Filter list of the first view. - * @tparam CLhs Component list of the first view. - * @tparam ERhs Filter list of the second view. - * @tparam CRhs Component list of the second view. - * @return A more specific view. - */ - template - friend auto operator|(const basic_view, CLhs...> &, const basic_view, CRhs...> &); - -private: - const std::tuple *...> pools; - const std::tuple *...> filter; - mutable const basic_sparse_set *view; -}; - - -/** - * @brief Single component view specialization. - * - * Single component views are specialized in order to get a boost in terms of - * performance. This kind of views can access the underlying data structure - * directly and avoid superfluous checks. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given component are created and assigned to entities. - * * The entity currently pointed is modified (as an example, the given - * component is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pool iterated by the view in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Views share a reference to the underlying data structure of the registry that - * generated them. Therefore any change to the entities and to the components - * made by means of the registry are immediately reflected by views. - * - * @warning - * Lifetime of a view must not overcome that of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Type of component iterated by the view. - */ -template -class basic_view, Component> final { - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable_view { - friend class basic_view, Component>; - - template - class iterable_view_iterator { - friend class iterable_view; - - template - iterable_view_iterator(It... from, Discard...) ENTT_NOEXCEPT - : it{from...} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_view_iterator & operator++() ENTT_NOEXCEPT { - return (++std::get(it), ...), *this; - } - - iterable_view_iterator operator++(int) ENTT_NOEXCEPT { - iterable_view_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return { *std::get(it)... }; - } - - [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return std::get<0>(other.it) == std::get<0>(it); - } - - [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - std::tuple it; - }; - - iterable_view(storage_type &ref) - : pool{&ref} - {} - - public: - using iterator = std::conditional_t< - std::is_void_v().get({}))>, - iterable_view_iterator::iterator>, - iterable_view_iterator::iterator, decltype(std::declval().begin())> - >; - using reverse_iterator = std::conditional_t< - std::is_void_v().get({}))>, - iterable_view_iterator::reverse_iterator>, - iterable_view_iterator::reverse_iterator, decltype(std::declval().rbegin())> - >; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return iterator{pool->basic_sparse_set::begin(), pool->begin()}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{pool->basic_sparse_set::end(), pool->end()}; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return reverse_iterator{pool->basic_sparse_set::rbegin(), pool->rbegin()}; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return reverse_iterator{pool->basic_sparse_set::rend(), pool->rend()}; - } - - private: - storage_type * const pool; - }; - -public: - /*! @brief Type of component iterated by the view. */ - using raw_type = Component; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = typename basic_sparse_set::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_sparse_set::reverse_iterator; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view() ENTT_NOEXCEPT - : pools{}, - filter{} - {} - - /** - * @brief Constructs a single-type view from a storage class. - * @param ref The storage for the type to iterate. - */ - basic_view(storage_type &ref) ENTT_NOEXCEPT - : pools{&ref}, - filter{} - {} - - /** - * @brief Returns the number of entities that have the given component. - * @return Number of entities that have the given component. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return std::get<0>(pools)->size(); - } - - /** - * @brief Checks whether a view is empty. - * @return True if the view is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return std::get<0>(pools)->empty(); - } - - /** - * @brief Direct access to the list of components. - * - * The returned pointer is such that range `[raw(), raw() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of components. - */ - [[nodiscard]] raw_type * raw() const ENTT_NOEXCEPT { - return std::get<0>(pools)->raw(); - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return std::get<0>(pools)->data(); - } - - /** - * @brief Returns an iterator to the first entity of the view. - * - * The returned iterator points to the first entity of the view. If the view - * is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the view. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::begin(); - } - - /** - * @brief Returns an iterator that is past the last entity of the view. - * - * The returned iterator points to the entity following the last entity of - * the view. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the view. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::end(); - } - - /** - * @brief Returns an iterator to the first entity of the reversed view. - * - * The returned iterator points to the first entity of the reversed view. If - * the view is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed view. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::rbegin(); - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * view. - * - * The returned iterator points to the entity following the last entity of - * the reversed view. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed view. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::rend(); - } - - /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the view, if any. - * @return The last entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = std::get<0>(pools)->find(entt); - return it != end() && *it == entt ? it : end(); - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[pos]; - } - - /** - * @brief Checks if a view is properly initialized. - * @return True if the view is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return std::get<0>(pools) != nullptr; - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return std::get<0>(pools)->contains(entt); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior. - * - * @tparam Comp Types of components to get. - * @param entt A valid entity identifier. - * @return The component assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Comp) == 0) { - return get_as_tuple(*std::get<0>(pools), entt); - } else { - static_assert(std::is_same_v, "Invalid component type"); - return std::get<0>(pools)->get(entt); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a reference to the component if it's a non-empty one. - * The _constness_ of the component is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Component &); - * void(Component &); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - if constexpr(std::is_void_v(pools)->get({}))>) { - if constexpr(std::is_invocable_v) { - for(auto pos = size(); pos; --pos) { - func(); - } - } else { - for(auto entity: *this) { - func(entity); - } - } - } else { - if constexpr(is_applicable_v) { - for(const auto pack: each()) { - std::apply(func, pack); - } - } else { - for(auto &&component: *std::get<0>(pools)) { - func(component); - } - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ the view. - * - * The iterable object returns tuples that contain the current entity and a - * reference to its component if it's a non-empty one. The _constness_ of - * the component is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the view. - */ - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - return iterable_view{*std::get<0>(pools)}; - } - - /** - * @brief Combines two views in a _more specific_ one (friend function). - * @tparam Id A valid entity type (see entt_traits for more details). - * @tparam ELhs Filter list of the first view. - * @tparam CLhs Component list of the first view. - * @tparam ERhs Filter list of the second view. - * @tparam CRhs Component list of the second view. - * @return A more specific view. - */ - template - friend auto operator|(const basic_view, CLhs...> &, const basic_view, CRhs...> &); - -private: - const std::tuple pools; - const std::tuple<> filter; -}; - - -/** - * @brief Deduction guide. - * @tparam Storage Type of storage classes used to create the view. - * @param storage The storage for the types to iterate. - */ -template -basic_view(Storage &... storage) --> basic_view, entt::exclude_t<>, constness_as_t...>; - - -/** - * @brief Combines two views in a _more specific_ one. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam ELhs Filter list of the first view. - * @tparam CLhs Component list of the first view. - * @tparam ERhs Filter list of the second view. - * @tparam CRhs Component list of the second view. - * @param lhs A valid reference to the first view. - * @param rhs A valid reference to the second view. - * @return A more specific view. - */ -template -[[nodiscard]] auto operator|(const basic_view, CLhs...> &lhs, const basic_view, CRhs...> &rhs) { - using view_type = basic_view, CLhs..., CRhs...>; - return std::apply([](auto *... storage) { return view_type{*storage...}; }, std::tuple_cat(lhs.pools, rhs.pools, lhs.filter, rhs.filter)); -} - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Fast and reliable entity-component system. - * - * The registry is the core class of the entity-component framework.
- * It stores entities and arranges pools of components on a per request basis. - * By means of a registry, users can manage entities and components, then create - * views or groups to iterate them. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_registry { - using traits_type = entt_traits; - using poly_storage_type = typename poly_storage_traits::storage_type; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - struct pool_data { - poly_storage_type poly; - std::unique_ptr> pool{}; - }; - - template - struct group_handler; - - template - struct group_handler, get_t, Owned...> { - static_assert(std::conjunction_v>..., std::is_same>..., std::is_same>...>, "One or more component types are invalid"); - std::conditional_t, std::size_t> current{}; - - template - void maybe_valid_if(basic_registry &owner, const Entity entt) { - [[maybe_unused]] const auto cpools = std::make_tuple(owner.assure()...); - - const auto is_valid = ((std::is_same_v || std::get *>(cpools)->contains(entt)) && ...) - && ((std::is_same_v || owner.assure()->contains(entt)) && ...) - && ((std::is_same_v || !owner.assure()->contains(entt)) && ...); - - if constexpr(sizeof...(Owned) == 0) { - if(is_valid && !current.contains(entt)) { - current.emplace(entt); - } - } else { - if(is_valid && !(std::get<0>(cpools)->index(entt) < current)) { - const auto pos = current++; - (std::get *>(cpools)->swap(std::get *>(cpools)->data()[pos], entt), ...); - } - } - } - - void discard_if([[maybe_unused]] basic_registry &owner, const Entity entt) { - if constexpr(sizeof...(Owned) == 0) { - if(current.contains(entt)) { - current.remove(entt); - } - } else { - if(const auto cpools = std::make_tuple(owner.assure()...); std::get<0>(cpools)->contains(entt) && (std::get<0>(cpools)->index(entt) < current)) { - const auto pos = --current; - (std::get *>(cpools)->swap(std::get *>(cpools)->data()[pos], entt), ...); - } - } - } - }; - - struct group_data { - std::size_t size; - std::unique_ptr group; - bool (* owned)(const id_type) ENTT_NOEXCEPT; - bool (* get)(const id_type) ENTT_NOEXCEPT; - bool (* exclude)(const id_type) ENTT_NOEXCEPT; - }; - - template - [[nodiscard]] storage_type * assure() const { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - const auto index = type_seq::value(); - - if(!(index < pools.size())) { - pools.resize(size_type(index)+1u); - } - - if(auto &&pdata = pools[index]; !pdata.pool) { - pdata.pool.reset(new storage_type()); - pdata.poly.template emplace &>(*static_cast *>(pdata.pool.get())); - } - - return static_cast *>(pools[index].pool.get()); - } - - template - [[nodiscard]] const storage_type * pool_if_exists() const { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - const auto index = type_seq::value(); - return (!(index < pools.size()) || !pools[index].pool) ? nullptr : static_cast *>(pools[index].pool.get()); - } - - Entity generate_identifier() { - // traits_type::entity_mask is reserved to allow for null identifiers - ENTT_ASSERT(static_cast(entities.size()) < traits_type::entity_mask); - return entities.emplace_back(entity_type{static_cast(entities.size())}); - } - - Entity recycle_identifier() { - ENTT_ASSERT(available != null); - const auto curr = to_integral(available); - const auto version = to_integral(entities[curr]) & (traits_type::version_mask << traits_type::entity_shift); - available = entity_type{to_integral(entities[curr]) & traits_type::entity_mask}; - return entities[curr] = entity_type{curr | version}; - } - - void release_entity(const Entity entity, const typename traits_type::version_type version) { - const auto entt = to_integral(entity) & traits_type::entity_mask; - entities[entt] = entity_type{to_integral(available) | (typename traits_type::entity_type{version} << traits_type::entity_shift)}; - available = entity_type{entt}; - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Underlying version type. */ - using version_type = typename traits_type::version_type; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Poly storage type. */ - using poly_storage = typename poly_storage_traits::storage_type; - - /** - * @brief Returns the entity identifier without the version. - * @param entity An entity identifier, either valid or not. - * @return The entity identifier without the version. - */ - [[nodiscard]] static entity_type entity(const entity_type entity) ENTT_NOEXCEPT { - return entity_type{to_integral(entity) & traits_type::entity_mask}; - } - - /** - * @brief Returns the version stored along with an entity identifier. - * @param entity An entity identifier, either valid or not. - * @return The version stored along with the given entity identifier. - */ - [[nodiscard]] static version_type version(const entity_type entity) ENTT_NOEXCEPT { - return version_type(to_integral(entity) >> traits_type::entity_shift); - } - - /*! @brief Default constructor. */ - basic_registry() = default; - - /*! @brief Default move constructor. */ - basic_registry(basic_registry &&) = default; - - /*! @brief Default move assignment operator. @return This registry. */ - basic_registry & operator=(basic_registry &&) = default; - - /** - * @brief Prepares a pool for the given type if required. - * @tparam Component Type of component for which to prepare a pool. - */ - template - void prepare() { - // suppress the warning due to the [[nodiscard]] attribute - static_cast(assure()); - } - - /** - * @brief Returns a poly storage for a given type. - * @param info The type for which to return a poly storage. - * @return A valid poly storage if a pool for the given type exists, an - * empty and thus invalid element otherwise. - */ - poly_storage & storage(const type_info info) { - ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly); - return pools[info.seq()].poly; - } - - /*! @copydoc storage */ - const poly_storage & storage(const type_info info) const { - ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly); - return pools[info.seq()].poly; - } - - /** - * @brief Returns the number of existing components of the given type. - * @tparam Component Type of component of which to return the size. - * @return Number of existing components of the given type. - */ - template - [[nodiscard]] size_type size() const { - const auto *cpool = pool_if_exists(); - return cpool ? cpool->size() : size_type{}; - } - - /** - * @brief Returns the number of entities created so far. - * @return Number of entities created so far. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return entities.size(); - } - - /** - * @brief Returns the number of entities still in use. - * @return Number of entities still in use. - */ - [[nodiscard]] size_type alive() const { - auto sz = entities.size(); - - for(auto curr = available; curr != null; --sz) { - curr = entities[to_integral(curr) & traits_type::entity_mask]; - } - - return sz; - } - - /** - * @brief Increases the capacity of the registry or of the pools for the - * given components. - * - * If no components are specified, the capacity of the registry is - * increased, that is the number of entities it contains. Otherwise the - * capacity of the pools for the given components is increased.
- * In both cases, if the new capacity is greater than the current capacity, - * new storage is allocated, otherwise the method does nothing. - * - * @tparam Component Types of components for which to reserve storage. - * @param cap Desired capacity. - */ - template - void reserve(const size_type cap) { - if constexpr(sizeof...(Component) == 0) { - entities.reserve(cap); - } else { - (assure()->reserve(cap), ...); - } - } - - /** - * @brief Reserves enough space to store `count` pools. - * @param count Number of pools to reserve space for. - */ - void reserve_pools(const size_t count) { - pools.reserve(count); - } - - /** - * @brief Returns the capacity of the pool for the given component. - * @tparam Component Type of component in which one is interested. - * @return Capacity of the pool of the given component. - */ - template - [[nodiscard]] size_type capacity() const { - const auto *cpool = pool_if_exists(); - return cpool ? cpool->capacity() : size_type{}; - } - - /** - * @brief Returns the number of entities that a registry has currently - * allocated space for. - * @return Capacity of the registry. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return entities.capacity(); - } - - /** - * @brief Requests the removal of unused capacity for the given components. - * @tparam Component Types of components for which to reclaim unused - * capacity. - */ - template - void shrink_to_fit() { - (assure()->shrink_to_fit(), ...); - } - - /** - * @brief Checks whether the registry or the pools of the given components - * are empty. - * - * A registry is considered empty when it doesn't contain entities that are - * still in use. - * - * @tparam Component Types of components in which one is interested. - * @return True if the registry or the pools of the given components are - * empty, false otherwise. - */ - template - [[nodiscard]] bool empty() const { - if constexpr(sizeof...(Component) == 0) { - return !alive(); - } else { - return [](const auto *... cpool) { return ((!cpool || cpool->empty()) && ...); }(pool_if_exists()...); - } - } - - /** - * @brief Direct access to the list of entities of a registry. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @warning - * This list contains both valid and destroyed entities and isn't suitable - * for direct use. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return entities.data(); - } - - /** - * @brief Returns the head of the list of destroyed entities. - * - * This function is intended for use in conjunction with `assign`.
- * The returned entity has an invalid identifier in all cases. - * - * @return The head of the list of destroyed entities. - */ - [[nodiscard]] entity_type destroyed() const ENTT_NOEXCEPT { - return available; - } - - /** - * @brief Checks if an entity identifier refers to a valid entity. - * @param entity An entity identifier, either valid or not. - * @return True if the identifier is valid, false otherwise. - */ - [[nodiscard]] bool valid(const entity_type entity) const { - const auto pos = size_type(to_integral(entity) & traits_type::entity_mask); - return (pos < entities.size() && entities[pos] == entity); - } - - /** - * @brief Returns the actual version for an entity identifier. - * - * @warning - * Attempting to use an entity that doesn't belong to the registry results - * in undefined behavior. An entity belongs to the registry even if it has - * been previously destroyed and/or recycled. - * - * @param entity A valid entity identifier. - * @return Actual version for the given entity identifier. - */ - [[nodiscard]] version_type current(const entity_type entity) const { - const auto pos = size_type(to_integral(entity) & traits_type::entity_mask); - ENTT_ASSERT(pos < entities.size()); - return version(entities[pos]); - } - - /** - * @brief Creates a new entity and returns it. - * - * There are two kinds of possible entity identifiers: - * - * * Newly created ones in case no entities have been previously destroyed. - * * Recycled ones with updated versions. - * - * @return A valid entity identifier. - */ - entity_type create() { - return available == null ? generate_identifier() : recycle_identifier(); - } - - /** - * @brief Creates a new entity and returns it. - * - * @sa create - * - * If the requested entity isn't in use, the suggested identifier is created - * and returned. Otherwise, a new one will be generated for this purpose. - * - * @param hint A desired entity identifier. - * @return A valid entity identifier. - */ - [[nodiscard]] entity_type create(const entity_type hint) { - ENTT_ASSERT(hint != null); - entity_type entt; - - if(const auto req = (to_integral(hint) & traits_type::entity_mask); !(req < entities.size())) { - entities.reserve(size_type(req) + 1u); - - for(auto pos = entities.size(); pos < req; ++pos) { - release_entity(generate_identifier(), {}); - } - - entt = entities.emplace_back(hint); - } else if(const auto curr = (to_integral(entities[req]) & traits_type::entity_mask); req == curr) { - entt = create(); - } else { - auto *it = &available; - for(; (to_integral(*it) & traits_type::entity_mask) != req; it = &entities[to_integral(*it) & traits_type::entity_mask]); - *it = entity_type{curr | (to_integral(*it) & (traits_type::version_mask << traits_type::entity_shift))}; - entt = entities[req] = hint; - } - - return entt; - } - - /** - * @brief Assigns each element in a range an entity. - * - * @sa create - * - * @tparam It Type of forward iterator. - * @param first An iterator to the first element of the range to generate. - * @param last An iterator past the last element of the range to generate. - */ - template - void create(It first, It last) { - for(; available != null && first != last; ++first) { - *first = recycle_identifier(); - } - - for(; first != last; ++first) { - *first = generate_identifier(); - } - } - - /** - * @brief Assigns entities to an empty registry. - * - * This function is intended for use in conjunction with `data`, `size` and - * `destroyed`.
- * Don't try to inject ranges of randomly generated entities nor the _wrong_ - * head for the list of destroyed entities. There is no guarantee that a - * registry will continue to work properly in this case. - * - * @warning - * There must be no entities still alive for this to work properly. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param destroyed The head of the list of destroyed entities. - */ - template - void assign(It first, It last, const entity_type destroyed) { - ENTT_ASSERT(!alive()); - entities.assign(first, last); - available = destroyed; - } - - /** - * @brief Destroys an entity. - * - * When an entity is destroyed, its version is updated and the identifier - * can be recycled at any time. - * - * @sa remove_all - * - * @param entity A valid entity identifier. - */ - void destroy(const entity_type entity) { - destroy(entity, static_cast(version(entity) + 1u)); - } - - /** - * @brief Destroys an entity. - * - * If the entity isn't already destroyed, the suggested version is used - * instead of the implicitly generated one. - * - * @sa remove_all - * - * @param entity A valid entity identifier. - * @param version A desired version upon destruction. - */ - void destroy(const entity_type entity, const version_type version) { - remove_all(entity); - release_entity(entity, version); - } - - /** - * @brief Destroys all the entities in a range. - * - * @sa destroy - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void destroy(It first, It last) { - for(; first != last; ++first) { - destroy(*first); - } - } - - /** - * @brief Assigns the given component to an entity. - * - * A new instance of the given component is created and initialized with the - * arguments provided (the component must have a proper constructor or be of - * aggregate type). Then the component is assigned to the given entity. - * - * @warning - * Attempting to use an invalid entity or to assign a component to an entity - * that already owns it results in undefined behavior. - * - * @tparam Component Type of component to create. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - decltype(auto) emplace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity)); - return assure()->emplace(*this, entity, std::forward(args)...); - } - - /** - * @brief Assigns each entity in a range the given component. - * - * @sa emplace - * - * @tparam Component Type of component to create. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param value An instance of the component to assign. - */ - template - void insert(It first, It last, const Component &value = {}) { - ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); - assure()->insert(*this, first, last, value); - } - - /** - * @brief Assigns each entity in a range the given components. - * - * @sa emplace - * - * @tparam Component Type of component to create. - * @tparam EIt Type of input iterator. - * @tparam CIt Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param from An iterator to the first element of the range of components. - * @param to An iterator past the last element of the range of components. - */ - template - void insert(EIt first, EIt last, CIt from, CIt to) { - static_assert(std::is_constructible_v::value_type>, "Invalid value type"); - ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); - assure()->insert(*this, first, last, from, to); - } - - /** - * @brief Assigns or replaces the given component for an entity. - * - * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * auto &component = registry.all_of(entity) ? registry.replace(entity, args...) : registry.emplace(entity, args...); - * @endcode - * - * Prefer this function anyway because it has slightly better performance. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Type of component to assign or replace. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - decltype(auto) emplace_or_replace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity)); - auto *cpool = assure(); - - return cpool->contains(entity) - ? cpool->patch(*this, entity, [&args...](auto &... curr) { ((curr = Component{std::forward(args)...}), ...); }) - : cpool->emplace(*this, entity, std::forward(args)...); - } - - /** - * @brief Patches the given component for an entity. - * - * The signature of the functions should be equivalent to the following: - * - * @code{.cpp} - * void(Component &); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned. However, this function can be used to trigger an update signal - * for them. - * - * @warning - * Attempting to use an invalid entity or to patch a component of an entity - * that doesn't own it results in undefined behavior. - * - * @tparam Component Type of component to patch. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the patched component. - */ - template - decltype(auto) patch(const entity_type entity, Func &&... func) { - ENTT_ASSERT(valid(entity)); - return assure()->patch(*this, entity, std::forward(func)...); - } - - /** - * @brief Replaces the given component for an entity. - * - * A new instance of the given component is created and initialized with the - * arguments provided (the component must have a proper constructor or be of - * aggregate type). Then the component is assigned to the given entity. - * - * @warning - * Attempting to use an invalid entity or to replace a component of an - * entity that doesn't own it results in undefined behavior. - * - * @tparam Component Type of component to replace. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the component being replaced. - */ - template - decltype(auto) replace(const entity_type entity, Args &&... args) { - return assure()->patch(*this, entity, [&args...](auto &... curr) { ((curr = Component{std::forward(args)...}), ...); }); - } - - /** - * @brief Removes the given components from an entity. - * - * @warning - * Attempting to use an invalid entity or to remove a component from an - * entity that doesn't own it results in undefined behavior. - * - * @tparam Component Types of components to remove. - * @param entity A valid entity identifier. - */ - template - void remove(const entity_type entity) { - ENTT_ASSERT(valid(entity)); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - (assure()->remove(entity, this), ...); - } - - /** - * @brief Removes the given components from all the entities in a range. - * - * @sa remove - * - * @tparam Component Types of components to remove. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void remove(It first, It last) { - ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - (assure()->remove(first, last, this), ...); - } - - /** - * @brief Removes the given components from an entity. - * - * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * if(registry.all_of(entity)) { registry.remove(entity) } - * @endcode - * - * Prefer this function anyway because it has slightly better performance. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Types of components to remove. - * @param entity A valid entity identifier. - * @return The number of components actually removed. - */ - template - size_type remove_if_exists(const entity_type entity) { - ENTT_ASSERT(valid(entity)); - - return ([this, entity](auto *cpool) { - return cpool->contains(entity) ? (cpool->remove(entity, this), true) : false; - }(assure()) + ... + size_type{}); - } - - /** - * @brief Removes all the components from an entity and makes it orphaned. - * - * @warning - * In case there are listeners that observe the destruction of components - * and assign other components to the entity in their bodies, the result of - * invoking this function may not be as expected. In the worst case, it - * could lead to undefined behavior. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @param entity A valid entity identifier. - */ - void remove_all(const entity_type entity) { - ENTT_ASSERT(valid(entity)); - entity_type wrap[1u]{entity}; - - for(auto pos = pools.size(); pos; --pos) { - if(auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) { - pdata.pool->remove(std::begin(wrap), std::end(wrap), this); - } - } - } - - /** - * @brief Checks if an entity has all the given components. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Components for which to perform the check. - * @param entity A valid entity identifier. - * @return True if the entity has all the components, false otherwise. - */ - template - [[nodiscard]] bool all_of(const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - return [entity](const auto *... cpool) { return ((cpool && cpool->contains(entity)) && ...); }(pool_if_exists()...); - } - - /** - * @brief Checks if an entity has at least one of the given components. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Components for which to perform the check. - * @param entity A valid entity identifier. - * @return True if the entity has at least one of the given components, - * false otherwise. - */ - template - [[nodiscard]] bool any_of(const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - return [entity](const auto *... cpool) { return !((!cpool || !cpool->contains(entity)) && ...); }(pool_if_exists()...); - } - - /** - * @brief Returns references to the given components for an entity. - * - * @warning - * Attempting to use an invalid entity or to get a component from an entity - * that doesn't own it results in undefined behavior. - * - * @tparam Component Types of components to get. - * @param entity A valid entity identifier. - * @return References to the components owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - const auto *cpool = pool_if_exists...>(); - ENTT_ASSERT(cpool); - return cpool->get(entity); - } else { - return std::forward_as_tuple(get(entity)...); - } - } - - /*! @copydoc get */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - return (const_cast(assure>()->get(entity)), ...); - } else { - return std::forward_as_tuple(get(entity)...); - } - } - - /** - * @brief Returns a reference to the given component for an entity. - * - * In case the entity doesn't own the component, the parameters provided are - * used to construct it.
- * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * auto &component = registry.all_of(entity) ? registry.get(entity) : registry.emplace(entity, args...); - * @endcode - * - * Prefer this function anyway because it has slightly better performance. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Type of component to get. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return Reference to the component owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity)); - auto *cpool = assure(); - return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(*this, entity, std::forward(args)...); - } - - /** - * @brief Returns pointers to the given components for an entity. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @note - * The registry retains ownership of the pointed-to components. - * - * @tparam Component Types of components to get. - * @param entity A valid entity identifier. - * @return Pointers to the components owned by the entity. - */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - const auto *cpool = pool_if_exists...>(); - return (cpool && cpool->contains(entity)) ? &cpool->get(entity) : nullptr; - } else { - return std::make_tuple(try_get(entity)...); - } - } - - /*! @copydoc try_get */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - return (const_cast(std::as_const(*this).template try_get(entity)), ...); - } else { - return std::make_tuple(try_get(entity)...); - } - } - - /** - * @brief Clears a whole registry or the pools for the given components. - * @tparam Component Types of components to remove from their entities. - */ - template - void clear() { - if constexpr(sizeof...(Component) == 0) { - for(auto pos = pools.size(); pos; --pos) { - if(auto &pdata = pools[pos-1]; pdata.pool) { - pdata.pool->clear(this); - } - } - - each([this](const auto entity) { release_entity(entity, version(entity) + 1u); }); - } else { - ([this](auto *cpool) { - cpool->remove(cpool->basic_sparse_set::begin(), cpool->basic_sparse_set::end(), this); - }(assure()), ...); - } - } - - /** - * @brief Iterates all the entities that are still in use. - * - * The function object is invoked for each entity that is still in use.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const Entity); - * @endcode - * - * This function is fairly slow and should not be used frequently. However, - * it's useful for iterating all the entities still in use, regardless of - * their components. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - if(available == null) { - for(auto pos = entities.size(); pos; --pos) { - func(entities[pos-1]); - } - } else { - for(auto pos = entities.size(); pos; --pos) { - if(const auto entity = entities[pos - 1]; (to_integral(entity) & traits_type::entity_mask) == (pos - 1)) { - func(entity); - } - } - } - } - - /** - * @brief Checks if an entity has components assigned. - * @param entity A valid entity identifier. - * @return True if the entity has no components assigned, false otherwise. - */ - [[nodiscard]] bool orphan(const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - return std::none_of(pools.cbegin(), pools.cend(), [entity](auto &&pdata) { return pdata.pool && pdata.pool->contains(entity); }); - } - - /** - * @brief Iterates orphans and applies them the given function object. - * - * The function object is invoked for each entity that is still in use and - * has no components assigned.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const Entity); - * @endcode - * - * This function can be very slow and should not be used frequently. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void orphans(Func func) const { - each([this, &func](const auto entity) { - if(orphan(entity)) { - func(entity); - } - }); - } - - /** - * @brief Returns a sink object for the given component. - * - * The sink returned by this function can be used to receive notifications - * whenever a new instance of the given component is created and assigned to - * an entity.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** the component has been assigned to the - * entity. - * - * @sa sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_construct() { - return assure()->on_construct(); - } - - /** - * @brief Returns a sink object for the given component. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance of the given component is explicitly updated.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** the component has been updated. - * - * @sa sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_update() { - return assure()->on_update(); - } - - /** - * @brief Returns a sink object for the given component. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance of the given component is removed from an entity and - * thus destroyed.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **before** the component has been removed from the - * entity. - * - * @sa sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_destroy() { - return assure()->on_destroy(); - } - - /** - * @brief Returns a view for the given components. - * - * This kind of objects are created on the fly and share with the registry - * its internal data structures.
- * Feel free to discard a view after the use. Creating and destroying a view - * is an incredibly cheap operation because they do not require any type of - * initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Views do their best to iterate the smallest set of candidate entities. - * In particular: - * - * * Single component views are incredibly fast and iterate a packed array - * of entities, all of which has the given component. - * * Multi component views look at the number of entities available for each - * component and pick up a reference to the smallest set of candidates to - * test for the given components. - * - * Views in no way affect the functionalities of the registry nor those of - * the underlying pools. - * - * @note - * Multi component views are pretty fast. However their performance tend to - * degenerate when the number of components to iterate grows up and the most - * of the entities have all the given components.
- * To get a performance boost, consider using a group instead. - * - * @tparam Component Type of components used to construct the view. - * @tparam Exclude Types of components used to filter the view. - * @return A newly created view. - */ - template - [[nodiscard]] basic_view, Component...> view(exclude_t = {}) const { - static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - static_assert((std::is_const_v && ...), "Invalid non-const type"); - return { *assure>()..., *assure()... }; - } - - /*! @copydoc view */ - template - [[nodiscard]] basic_view, Component...> view(exclude_t = {}) { - static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - return { *assure>()..., *assure()... }; - } - - /** - * @brief Returns a runtime view for the given components. - * - * This kind of objects are created on the fly and share with the registry - * its internal data structures.
- * Users should throw away the view after use. Fortunately, creating and - * destroying a runtime view is an incredibly cheap operation because they - * do not require any type of initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Runtime views are to be used when users want to construct a view from - * some external inputs and don't know at compile-time what are the required - * components. - * - * @tparam ItComp Type of input iterator for the components to use to - * construct the view. - * @tparam ItExcl Type of input iterator for the components to use to filter - * the view. - * @param first An iterator to the first element of the range of components - * to use to construct the view. - * @param last An iterator past the last element of the range of components - * to use to construct the view. - * @param from An iterator to the first element of the range of components - * to use to filter the view. - * @param to An iterator past the last element of the range of components to - * use to filter the view. - * @return A newly created runtime view. - */ - template - [[nodiscard]] basic_runtime_view runtime_view(ItComp first, ItComp last, ItExcl from = {}, ItExcl to = {}) const { - std::vector *> component(std::distance(first, last)); - std::vector *> filter(std::distance(from, to)); - - std::transform(first, last, component.begin(), [this](const auto ctype) { - const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; }); - return it == pools.cend() ? nullptr : it->pool.get(); - }); - - std::transform(from, to, filter.begin(), [this](const auto ctype) { - const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; }); - return it == pools.cend() ? nullptr : it->pool.get(); - }); - - return { std::move(component), std::move(filter) }; - } - - /** - * @brief Returns a group for the given components. - * - * This kind of objects are created on the fly and share with the registry - * its internal data structures.
- * Feel free to discard a group after the use. Creating and destroying a - * group is an incredibly cheap operation because they do not require any - * type of initialization, but for the first time they are requested.
- * As a rule of thumb, storing a group should never be an option. - * - * Groups support exclusion lists and can own types of components. The more - * types are owned by a group, the faster it is to iterate entities and - * components.
- * However, groups also affect some features of the registry such as the - * creation and destruction of components, which will consequently be - * slightly slower (nothing that can be noticed in most cases). - * - * @note - * Pools of components that are owned by a group cannot be sorted anymore. - * The group takes the ownership of the pools and arrange components so as - * to iterate them as fast as possible. - * - * @tparam Owned Types of components owned by the group. - * @tparam Get Types of components observed by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t, Owned...> group(get_t, exclude_t = {}) { - static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only groups are not supported"); - static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed"); - - using handler_type = group_handler, get_t...>, std::remove_const_t...>; - - const auto cpools = std::make_tuple(assure>()..., assure>()...); - constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude); - handler_type *handler = nullptr; - - if(auto it = std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - return gdata.size == size - && (gdata.owned(type_hash>::value()) && ...) - && (gdata.get(type_hash>::value()) && ...) - && (gdata.exclude(type_hash::value()) && ...); - }); it != groups.cend()) - { - handler = static_cast(it->group.get()); - } - - if(!handler) { - group_data candidate = { - size, - { new handler_type{}, [](void *instance) { delete static_cast(instance); } }, - []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash>::value()) || ...); }, - []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash>::value()) || ...); }, - []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash::value()) || ...); }, - }; - - handler = static_cast(candidate.group.get()); - - const void *maybe_valid_if = nullptr; - const void *discard_if = nullptr; - - if constexpr(sizeof...(Owned) == 0) { - groups.push_back(std::move(candidate)); - } else { - ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - const auto overlapping = (0u + ... + gdata.owned(type_hash>::value())); - const auto sz = overlapping + (0u + ... + gdata.get(type_hash>::value())) + (0u + ... + gdata.exclude(type_hash::value())); - return !overlapping || ((sz == size) || (sz == gdata.size)); - })); - - const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - return !(0u + ... + gdata.owned(type_hash>::value())) || (size > gdata.size); - }); - - const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &gdata) { - return (0u + ... + gdata.owned(type_hash>::value())); - }); - - maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get()); - discard_if = (prev == groups.crend() ? discard_if : prev->group.get()); - groups.insert(next, std::move(candidate)); - } - - (on_construct>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if>>(*handler), ...); - (on_construct>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if>>(*handler), ...); - (on_destroy().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if>(*handler), ...); - - (on_destroy>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...); - (on_destroy>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...); - (on_construct().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...); - - if constexpr(sizeof...(Owned) == 0) { - for(const auto entity: view(exclude)) { - handler->current.emplace(entity); - } - } else { - // we cannot iterate backwards because we want to leave behind valid entities in case of owned types - for(auto *first = std::get<0>(cpools)->data(), *last = first + std::get<0>(cpools)->size(); first != last; ++first) { - handler->template maybe_valid_if...>>>(*this, *first); - } - } - } - - return { handler->current, *std::get> *>(cpools)..., *std::get> *>(cpools)... }; - } - - /** - * @brief Returns a group for the given components. - * - * @sa group - * - * @tparam Owned Types of components owned by the group. - * @tparam Get Types of components observed by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t, Owned...> group_if_exists(get_t, exclude_t = {}) const { - static_assert(std::conjunction_v..., std::is_const...>, "Invalid non-const type"); - - if(auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) { - return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude)) - && (gdata.owned(type_hash>::value()) && ...) - && (gdata.get(type_hash>::value()) && ...) - && (gdata.exclude(type_hash::value()) && ...); - }); it == groups.cend()) - { - return {}; - } else { - using handler_type = group_handler, get_t...>, std::remove_const_t...>; - return { static_cast(it->group.get())->current, *pool_if_exists>()... , *pool_if_exists>()... }; - } - } - - /** - * @brief Returns a group for the given components. - * - * @sa group - * - * @tparam Owned Types of components owned by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t<>, Owned...> group(exclude_t = {}) { - return group(get_t<>{}, exclude); - } - - /** - * @brief Returns a group for the given components. - * - * @sa group_if_exists - * - * @tparam Owned Types of components owned by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t<>, Owned...> group_if_exists(exclude_t = {}) const { - return group_if_exists(get_t<>{}, exclude); - } - - /** - * @brief Checks whether the given components belong to any group. - * @tparam Component Types of components in which one is interested. - * @return True if the pools of the given components are sortable, false - * otherwise. - */ - template - [[nodiscard]] bool sortable() const { - return std::none_of(groups.cbegin(), groups.cend(), [](auto &&gdata) { return (gdata.owned(type_hash>::value()) || ...); }); - } - - /** - * @brief Checks whether a group can be sorted. - * @tparam Owned Types of components owned by the group. - * @tparam Get Types of components observed by the group. - * @tparam Exclude Types of components used to filter the group. - * @return True if the group can be sorted, false otherwise. - */ - template - [[nodiscard]] bool sortable(const basic_group, get_t, Owned...> &) ENTT_NOEXCEPT { - constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude); - return std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - return (0u + ... + gdata.owned(type_hash>::value())) && (size < gdata.size); - }) == groups.cend(); - } - - /** - * @brief Sorts the pool of entities for the given component. - * - * The order of the elements in a pool is highly affected by assignments - * of components to entities and deletions. Components are arranged to - * maximize the performance during iterations and users should not make any - * assumption on the order.
- * This function can be used to impose an order to the elements in the pool - * of the given component. The order is kept valid until a component of the - * given type is assigned or removed from an entity. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * bool(const Component &, const Component &); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * The comparison funtion object received by the sort function object hasn't - * necessarily the type of the one passed along with the other parameters to - * this member function. - * - * @warning - * Pools of components owned by a group cannot be sorted. - * - * @tparam Component Type of components to sort. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - ENTT_ASSERT(sortable()); - assure()->sort(std::move(compare), std::move(algo), std::forward(args)...); - } - - /** - * @brief Sorts two pools of components in the same way. - * - * The order of the elements in a pool is highly affected by assignments - * of components to entities and deletions. Components are arranged to - * maximize the performance during iterations and users should not make any - * assumption on the order. - * - * It happens that different pools of components must be sorted the same way - * because of runtime and/or performance constraints. This function can be - * used to order a pool of components according to the order between the - * entities in another pool of components. - * - * @b How @b it @b works - * - * Being `A` and `B` the two sets where `B` is the master (the one the order - * of which rules) and `A` is the slave (the one to sort), after a call to - * this function an iterator for `A` will return the entities according to - * the following rules: - * - * * All the entities in `A` that are also in `B` are returned first - * according to the order they have in `B`. - * * All the entities in `A` that are not in `B` are returned in no - * particular order after all the other entities. - * - * Any subsequent change to `B` won't affect the order in `A`. - * - * @warning - * Pools of components owned by a group cannot be sorted. - * - * @tparam To Type of components to sort. - * @tparam From Type of components to use to sort. - */ - template - void sort() { - ENTT_ASSERT(sortable()); - assure()->respect(*assure()); - } - - /** - * @brief Visits an entity and returns the type info for its components. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const type_info); - * @endcode - * - * Returned identifiers are those of the components owned by the entity. - * - * @sa type_info - * - * @warning - * It's not specified whether a component attached to or removed from the - * given entity during the visit is returned or not to the caller. - * - * @tparam Func Type of the function object to invoke. - * @param entity A valid entity identifier. - * @param func A valid function object. - */ - template - void visit(entity_type entity, Func func) const { - for(auto pos = pools.size(); pos; --pos) { - if(const auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) { - func(pdata.poly->value_type()); - } - } - } - - /** - * @brief Visits a registry and returns the type info for its components. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const type_info); - * @endcode - * - * Returned identifiers are those of the components managed by the registry. - * - * @sa type_info - * - * @warning - * It's not specified whether a component for which a pool is created during - * the visit is returned or not to the caller. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void visit(Func func) const { - for(auto pos = pools.size(); pos; --pos) { - if(const auto &pdata = pools[pos-1]; pdata.pool) { - func(pdata.poly->value_type()); - } - } - } - - /** - * @brief Binds an object to the context of the registry. - * - * If the value already exists it is overwritten, otherwise a new instance - * of the given type is created and initialized with the arguments provided. - * - * @tparam Type Type of object to set. - * @tparam Args Types of arguments to use to construct the object. - * @param args Parameters to use to initialize the value. - * @return A reference to the newly created object. - */ - template - Type & set(Args &&... args) { - unset(); - vars.emplace_back(std::in_place_type, std::forward(args)...); - return any_cast(vars.back()); - } - - /** - * @brief Unsets a context variable if it exists. - * @tparam Type Type of object to set. - */ - template - void unset() { - vars.erase(std::remove_if(vars.begin(), vars.end(), [type = type_id()](auto &&var) { return var.type() == type; }), vars.end()); - } - - /** - * @brief Binds an object to the context of the registry. - * - * In case the context doesn't contain the given object, the parameters - * provided are used to construct it. - * - * @tparam Type Type of object to set. - * @tparam Args Types of arguments to use to construct the object. - * @param args Parameters to use to initialize the object. - * @return A reference to the object in the context of the registry. - */ - template - [[nodiscard]] Type & ctx_or_set(Args &&... args) { - auto *value = try_ctx(); - return value ? *value : set(std::forward(args)...); - } - - /** - * @brief Returns a pointer to an object in the context of the registry. - * @tparam Type Type of object to get. - * @return A pointer to the object if it exists in the context of the - * registry, a null pointer otherwise. - */ - template - [[nodiscard]] Type * try_ctx() const { - auto it = std::find_if(vars.cbegin(), vars.cend(), [type = type_id()](auto &&var) { return var.type() == type; }); - return it == vars.cend() ? nullptr : any_cast(&*it); - } - - /*! @copydoc try_ctx */ - template - [[nodiscard]] Type * try_ctx() { - auto it = std::find_if(vars.begin(), vars.end(), [type = type_id()](auto &&var) { return var.type() == type; }); - return it == vars.end() ? nullptr : any_cast(&*it); - } - - /** - * @brief Returns a reference to an object in the context of the registry. - * - * @warning - * Attempting to get a context variable that doesn't exist results in - * undefined behavior. - * - * @tparam Type Type of object to get. - * @return A valid reference to the object in the context of the registry. - */ - template - [[nodiscard]] Type & ctx() const { - auto it = std::find_if(vars.cbegin(), vars.cend(), [type = type_id()](auto &&var) { return var.type() == type; }); - ENTT_ASSERT(it != vars.cend()); - return any_cast(*it); - } - - /*! @copydoc ctx */ - template - [[nodiscard]] Type & ctx() { - auto it = std::find_if(vars.begin(), vars.end(), [type = type_id()](auto &&var) { return var.type() == type; }); - ENTT_ASSERT(it != vars.end()); - return any_cast(*it); - } - - /** - * @brief Visits a registry and returns the type info for its context - * variables. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const type_info); - * @endcode - * - * Returned identifiers are those of the context variables currently set. - * - * @sa type_info - * - * @warning - * It's not specified whether a context variable created during the visit is - * returned or not to the caller. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void ctx(Func func) const { - for(auto pos = vars.size(); pos; --pos) { - func(vars[pos-1].type()); - } - } - -private: - std::vector> vars{}; - mutable std::vector pools{}; - std::vector groups{}; - std::vector entities{}; - entity_type available{null}; -}; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Non-owning handle to an entity. - * - * Tiny wrapper around a registry and an entity. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Types to which to restrict the scope of a handle. - */ -template -struct basic_handle { - /*! @brief Underlying entity identifier. */ - using entity_type = std::remove_const_t; - /*! @brief Type of registry accepted by the handle. */ - using registry_type = constness_as_t, Entity>; - - /*! @brief Constructs an invalid handle. */ - basic_handle() ENTT_NOEXCEPT - : reg{}, entt{null} - {} - - /** - * @brief Constructs a handle from a given registry and entity. - * @param ref An instance of the registry class. - * @param value An entity identifier. - */ - basic_handle(registry_type &ref, entity_type value) ENTT_NOEXCEPT - : reg{&ref}, entt{value} - {} - - /** - * @brief Compares two handles. - * @tparam Args Template parameters of the handle with which to compare. - * @param other Handle with which to compare. - * @return True if both handles refer to the same registry and the same - * entity, false otherwise. - */ - template - [[nodiscard]] bool operator==(const basic_handle &other) const ENTT_NOEXCEPT { - return reg == other.registry() && entt == other.entity(); - } - - /** - * @brief Constructs a const handle from a non-const one. - * @tparam Other A valid entity type (see entt_traits for more details). - * @tparam Args Scope of the handle to construct. - * @return A const handle referring to the same registry and the same - * entity. - */ - template - operator basic_handle() const ENTT_NOEXCEPT { - static_assert( - (std::is_same_v || std::is_same_v, Entity>) - && (sizeof...(Type) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Type)) && ... && (type_list_contains_v, Args>))), - "Invalid conversion between different handles" - ); - - return reg ? basic_handle{*reg, entt} : basic_handle{}; - } - - /** - * @brief Converts a handle to its underlying entity. - * @return An entity identifier. - */ - [[nodiscard]] operator entity_type() const ENTT_NOEXCEPT { - return entity(); - } - - /** - * @brief Checks if a handle refers to non-null registry pointer and entity. - * @return True if the handle refers to non-null registry and entity, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return reg && reg->valid(entt); - } - - /** - * @brief Checks if a handle refers to a valid entity or not. - * @return True if the handle refers to a valid entity, false otherwise. - */ - [[nodiscard]] bool valid() const { - return reg->valid(entt); - } - - /** - * @brief Returns a pointer to the underlying registry, if any. - * @return A pointer to the underlying registry, if any. - */ - [[nodiscard]] registry_type * registry() const ENTT_NOEXCEPT { - return reg; - } - - /** - * @brief Returns the entity associated with a handle. - * @return The entity associated with the handle. - */ - [[nodiscard]] entity_type entity() const ENTT_NOEXCEPT { - return entt; - } - - /** - * @brief Destroys the entity associated with a handle. - * @sa basic_registry::destroy - */ - void destroy() { - reg->destroy(entt); - } - - /** - * @brief Destroys the entity associated with a handle. - * @sa basic_registry::destroy - * @param version A desired version upon destruction. - */ - void destroy(const typename registry_type::version_type version) { - reg->destroy(entt, version); - } - - /** - * @brief Assigns the given component to a handle. - * @sa basic_registry::emplace - * @tparam Component Type of component to create. - * @tparam Args Types of arguments to use to construct the component. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - decltype(auto) emplace(Args &&... args) const { - static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v), "Invalid type"); - return reg->template emplace(entt, std::forward(args)...); - } - - /** - * @brief Assigns or replaces the given component for a handle. - * @sa basic_registry::emplace_or_replace - * @tparam Component Type of component to assign or replace. - * @tparam Args Types of arguments to use to construct the component. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - decltype(auto) emplace_or_replace(Args &&... args) const { - static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v), "Invalid type"); - return reg->template emplace_or_replace(entt, std::forward(args)...); - } - - /** - * @brief Patches the given component for a handle. - * @sa basic_registry::patch - * @tparam Component Type of component to patch. - * @tparam Func Types of the function objects to invoke. - * @param func Valid function objects. - * @return A reference to the patched component. - */ - template - decltype(auto) patch(Func &&... func) const { - static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v), "Invalid type"); - return reg->template patch(entt, std::forward(func)...); - } - - /** - * @brief Replaces the given component for a handle. - * @sa basic_registry::replace - * @tparam Component Type of component to replace. - * @tparam Args Types of arguments to use to construct the component. - * @param args Parameters to use to initialize the component. - * @return A reference to the component being replaced. - */ - template - decltype(auto) replace(Args &&... args) const { - static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v), "Invalid type"); - return reg->template replace(entt, std::forward(args)...); - } - - /** - * @brief Removes the given components from a handle. - * @sa basic_registry::remove - * @tparam Component Types of components to remove. - */ - template - void remove() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); - reg->template remove(entt); - } - - /** - * @brief Removes the given components from a handle. - * @sa basic_registry::remove_if_exists - * @tparam Component Types of components to remove. - * @return The number of components actually removed. - */ - template - decltype(auto) remove_if_exists() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); - return reg->template remove_if_exists(entt); - } - - /** - * @brief Removes all the components from a handle and makes it orphaned. - * @sa basic_registry::remove_all - */ - void remove_all() const { - static_assert(sizeof...(Type) == 0, "Invalid operation"); - reg->remove_all(entt); - } - - /** - * @brief Checks if a handle has all the given components. - * @sa basic_registry::all_of - * @tparam Component Components for which to perform the check. - * @return True if the handle has all the components, false otherwise. - */ - template - [[nodiscard]] decltype(auto) all_of() const { - return reg->template all_of(entt); - } - - /** - * @brief Checks if a handle has at least one of the given components. - * @sa basic_registry::any_of - * @tparam Component Components for which to perform the check. - * @return True if the handle has at least one of the given components, - * false otherwise. - */ - template - [[nodiscard]] decltype(auto) any_of() const { - return reg->template any_of(entt); - } - - /** - * @brief Returns references to the given components for a handle. - * @sa basic_registry::get - * @tparam Component Types of components to get. - * @return References to the components owned by the handle. - */ - template - [[nodiscard]] decltype(auto) get() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); - return reg->template get(entt); - } - - /** - * @brief Returns a reference to the given component for a handle. - * @sa basic_registry::get_or_emplace - * @tparam Component Type of component to get. - * @tparam Args Types of arguments to use to construct the component. - * @param args Parameters to use to initialize the component. - * @return Reference to the component owned by the handle. - */ - template - [[nodiscard]] decltype(auto) get_or_emplace(Args &&... args) const { - static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v), "Invalid type"); - return reg->template get_or_emplace(entt, std::forward(args)...); - } - - /** - * @brief Returns pointers to the given components for a handle. - * @sa basic_registry::try_get - * @tparam Component Types of components to get. - * @return Pointers to the components owned by the handle. - */ - template - [[nodiscard]] auto try_get() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); - return reg->template try_get(entt); - } - - /** - * @brief Checks if a handle has components assigned. - * @return True if the handle has no components assigned, false otherwise. - */ - [[nodiscard]] bool orphan() const { - return reg->orphan(entt); - } - - /** - * @brief Visits a handle and returns the types for its components. - * @sa basic_registry::visit - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void visit(Func &&func) const { - reg->visit(entt, std::forward(func)); - } - -private: - registry_type *reg; - entity_type entt; -}; - - -/** - * @brief Compares two handles. - * @tparam Type A valid entity type (see entt_traits for more details). - * @tparam Other A valid entity type (see entt_traits for more details). - * @param lhs A valid handle. - * @param rhs A valid handle. - * @return False if both handles refer to the same registry and the same - * entity, true otherwise. - */ -template -bool operator!=(const basic_handle &lhs, const basic_handle &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -basic_handle(basic_registry &, Entity) --> basic_handle; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -basic_handle(const basic_registry &, Entity) --> basic_handle; - - -} - - -#endif - -// #include "entity/helper.hpp" -#ifndef ENTT_ENTITY_HELPER_HPP -#define ENTT_ENTITY_HELPER_HPP - - -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "../signal/delegate.hpp" -#ifndef ENTT_SIGNAL_DELEGATE_HPP -#define ENTT_SIGNAL_DELEGATE_HPP - - -#include -#include -#include -#include -#include -// #include "../core/type_traits.hpp" - -// #include "../config/config.h" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Type Class:: *, Other &&...) -> Type(*)(); - - -template -using function_pointer_t = decltype(internal::function_pointer(std::declval()...)); - - -template -[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) { - return std::index_sequence_for{}; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/*! @brief Used to wrap a function or a member of a specified type. */ -template -struct connect_arg_t {}; - - -/*! @brief Constant of type connect_arg_t used to disambiguate calls. */ -template -inline constexpr connect_arg_t connect_arg{}; - - -/** - * @brief Basic delegate implementation. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - */ -template -class delegate; - - -/** - * @brief Utility class to use to send around functions and members. - * - * Unmanaged delegate for function pointers and members. Users of this class are - * in charge of disconnecting instances before deleting them. - * - * A delegate can be used as a general purpose invoker without memory overhead - * for free functions possibly with payloads and bound or unbound members. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class delegate { - template - [[nodiscard]] auto wrap(std::index_sequence) ENTT_NOEXCEPT { - return [](const void *, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - return static_cast(std::invoke(Candidate, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type &, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, *curr, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type *, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, curr, std::forward>>(std::get(arguments))...)); - }; - } - -public: - /*! @brief Function type of the contained target. */ - using function_type = Ret(const void *, Args...); - /*! @brief Function type of the delegate. */ - using type = Ret(Args...); - /*! @brief Return type of the delegate. */ - using result_type = Ret; - - /*! @brief Default constructor. */ - delegate() ENTT_NOEXCEPT - : fn{nullptr}, data{nullptr} - {} - - /** - * @brief Constructs a delegate and connects a free function or an unbound - * member. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - delegate(connect_arg_t) ENTT_NOEXCEPT { - connect(); - } - - /** - * @brief Constructs a delegate and connects a free function with payload or - * a bound member. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - delegate(connect_arg_t, Type &&value_or_instance) ENTT_NOEXCEPT { - connect(std::forward(value_or_instance)); - } - - /** - * @brief Constructs a delegate and connects an user defined function with - * optional payload. - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - connect(function, payload); - } - - /** - * @brief Connects a free function or an unbound member to a delegate. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - void connect() ENTT_NOEXCEPT { - data = nullptr; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *, Args... args) -> Ret { - return Ret(std::invoke(Candidate, std::forward(args)...)); - }; - } else if constexpr(std::is_member_pointer_v) { - fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); - } else { - fn = wrap(internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the delegate.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the delegate itself. - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid reference that fits the purpose. - */ - template - void connect(Type &value_or_instance) ENTT_NOEXCEPT { - data = &value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, *curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * @sa connect(Type &) - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - */ - template - void connect(Type *value_or_instance) ENTT_NOEXCEPT { - data = value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects an user defined function with optional payload to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of an instance overcomes - * the one of the delegate.
- * The payload is returned as the first argument to the target function in - * all cases. - * - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - fn = function; - data = payload; - } - - /** - * @brief Resets a delegate. - * - * After a reset, a delegate cannot be invoked anymore. - */ - void reset() ENTT_NOEXCEPT { - fn = nullptr; - data = nullptr; - } - - /** - * @brief Returns the instance or the payload linked to a delegate, if any. - * @return An opaque pointer to the underlying data. - */ - [[nodiscard]] const void * instance() const ENTT_NOEXCEPT { - return data; - } - - /** - * @brief Triggers a delegate. - * - * The delegate invokes the underlying function and returns the result. - * - * @warning - * Attempting to trigger an invalid delegate results in undefined - * behavior. - * - * @param args Arguments to use to invoke the underlying function. - * @return The value returned by the underlying function. - */ - Ret operator()(Args... args) const { - ENTT_ASSERT(static_cast(*this)); - return fn(data, std::forward(args)...); - } - - /** - * @brief Checks whether a delegate actually stores a listener. - * @return False if the delegate is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - // no need to test also data - return !(fn == nullptr); - } - - /** - * @brief Compares the contents of two delegates. - * @param other Delegate with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const delegate &other) const ENTT_NOEXCEPT { - return fn == other.fn && data == other.data; - } - -private: - function_type *fn; - const void *data; -}; - - -/** - * @brief Compares the contents of two delegates. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @param lhs A valid delegate object. - * @param rhs A valid delegate object. - * @return True if the two contents differ, false otherwise. - */ -template -[[nodiscard]] bool operator!=(const delegate &lhs, const delegate &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - */ -template -delegate(connect_arg_t) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - */ -template -delegate(connect_arg_t, Type &&) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) --> delegate; - - -} - - -#endif - -// #include "registry.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Converts a registry to a view. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct as_view { - /*! @brief Underlying entity identifier. */ - using entity_type = std::remove_const_t; - /*! @brief Type of registry to convert. */ - using registry_type = constness_as_t, Entity>; - - /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. - */ - as_view(registry_type &source) ENTT_NOEXCEPT: reg{source} {} - - /** - * @brief Conversion function from a registry to a view. - * @tparam Exclude Types of components used to filter the view. - * @tparam Component Type of components used to construct the view. - * @return A newly created view. - */ - template - operator basic_view() const { - return reg.template view(Exclude{}); - } - -private: - registry_type ® -}; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_view(basic_registry &) -> as_view; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_view(const basic_registry &) -> as_view; - - -/** - * @brief Converts a registry to a group. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct as_group { - /*! @brief Underlying entity identifier. */ - using entity_type = std::remove_const_t; - /*! @brief Type of registry to convert. */ - using registry_type = constness_as_t, Entity>; - - /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. - */ - as_group(registry_type &source) ENTT_NOEXCEPT: reg{source} {} - - /** - * @brief Conversion function from a registry to a group. - * @tparam Exclude Types of components used to filter the group. - * @tparam Get Types of components observed by the group. - * @tparam Owned Types of components owned by the group. - * @return A newly created group. - */ - template - operator basic_group() const { - if constexpr(std::is_const_v) { - return reg.template group_if_exists(Get{}, Exclude{}); - } else { - return reg.template group(Get{}, Exclude{}); - } - } - -private: - registry_type ® -}; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_group(basic_registry &) -> as_group; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_group(const basic_registry &) -> as_group; - - - -/** - * @brief Helper to create a listener that directly invokes a member function. - * @tparam Member Member function to invoke on a component of the given type. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @param reg A registry that contains the given entity and its components. - * @param entt Entity from which to get the component. - */ -template -void invoke(basic_registry ®, const Entity entt) { - static_assert(std::is_member_function_pointer_v, "Invalid pointer to non-static member function"); - delegate &, const Entity)> func; - func.template connect(reg.template get>(entt)); - func(reg, entt); -} - - -/** - * @brief Returns the entity associated with a given component. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Type of component. - * @param reg A registry that contains the given entity and its components. - * @param component A valid component instance. - * @return The entity associated with the given component. - */ -template -Entity to_entity(const basic_registry ®, const Component &component) { - const auto view = reg.template view(); - return *(view.data() + (&component - view.raw())); -} - - -} - - -#endif - -// #include "entity/observer.hpp" -#ifndef ENTT_ENTITY_OBSERVER_HPP -#define ENTT_ENTITY_OBSERVER_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "../signal/delegate.hpp" - -// #include "registry.hpp" - -// #include "storage.hpp" - -// #include "utility.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/*! @brief Grouping matcher. */ -template -struct matcher {}; - - -/** - * @brief Collector. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -struct basic_collector; - - -/** - * @brief Collector. - * - * A collector contains a set of rules (literally, matchers) to use to track - * entities.
- * Its main purpose is to generate a descriptor that allows an observer to know - * how to connect to a registry. - */ -template<> -struct basic_collector<> { - /** - * @brief Adds a grouping matcher to the collector. - * @tparam AllOf Types of components tracked by the matcher. - * @tparam NoneOf Types of components used to filter out entities. - * @return The updated collector. - */ - template - static constexpr auto group(exclude_t = {}) ENTT_NOEXCEPT { - return basic_collector, type_list<>, type_list, AllOf...>>{}; - } - - /** - * @brief Adds an observing matcher to the collector. - * @tparam AnyOf Type of component for which changes should be detected. - * @return The updated collector. - */ - template - static constexpr auto update() ENTT_NOEXCEPT { - return basic_collector, type_list<>, AnyOf>>{}; - } -}; - -/** - * @brief Collector. - * @copydetails basic_collector<> - * @tparam Reject Untracked types used to filter out entities. - * @tparam Require Untracked types required by the matcher. - * @tparam Rule Specific details of the current matcher. - * @tparam Other Other matchers. - */ -template -struct basic_collector, type_list, Rule...>, Other...> { - /*! @brief Current matcher. */ - using current_type = matcher, type_list, Rule...>; - - /** - * @brief Adds a grouping matcher to the collector. - * @tparam AllOf Types of components tracked by the matcher. - * @tparam NoneOf Types of components used to filter out entities. - * @return The updated collector. - */ - template - static constexpr auto group(exclude_t = {}) ENTT_NOEXCEPT { - return basic_collector, type_list<>, type_list, AllOf...>, current_type, Other...>{}; - } - - /** - * @brief Adds an observing matcher to the collector. - * @tparam AnyOf Type of component for which changes should be detected. - * @return The updated collector. - */ - template - static constexpr auto update() ENTT_NOEXCEPT { - return basic_collector, type_list<>, AnyOf>, current_type, Other...>{}; - } - - /** - * @brief Updates the filter of the last added matcher. - * @tparam AllOf Types of components required by the matcher. - * @tparam NoneOf Types of components used to filter out entities. - * @return The updated collector. - */ - template - static constexpr auto where(exclude_t = {}) ENTT_NOEXCEPT { - using extended_type = matcher, type_list, Rule...>; - return basic_collector{}; - } -}; - - -/*! @brief Variable template used to ease the definition of collectors. */ -inline constexpr basic_collector<> collector{}; - - -/** - * @brief Observer. - * - * An observer returns all the entities and only the entities that fit the - * requirements of at least one matcher. Moreover, it's guaranteed that the - * entity list is tightly packed in memory for fast iterations.
- * In general, observers don't stay true to the order of any set of components. - * - * Observers work mainly with two types of matchers, provided through a - * collector: - * - * * Observing matcher: an observer will return at least all the living entities - * for which one or more of the given components have been updated and not yet - * destroyed. - * * Grouping matcher: an observer will return at least all the living entities - * that would have entered the given group if it existed and that would have - * not yet left it. - * - * If an entity respects the requirements of multiple matchers, it will be - * returned once and only once by the observer in any case. - * - * Matchers support also filtering by means of a _where_ clause that accepts - * both a list of types and an exclusion list.
- * Whenever a matcher finds that an entity matches its requirements, the - * condition of the filter is verified before to register the entity itself. - * Moreover, a registered entity isn't returned by the observer if the condition - * set by the filter is broken in the meantime. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all the other cases, modifying the pools of the given components in any - * way invalidates all the iterators and using them results in undefined - * behavior. - * - * @warning - * Lifetime of an observer doesn't necessarily have to overcome that of the - * registry to which it is connected. However, the observer must be disconnected - * from the registry before being destroyed to avoid crashes due to dangling - * pointers. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_observer { - using payload_type = std::uint32_t; - - template - struct matcher_handler; - - template - struct matcher_handler, type_list, AnyOf>> { - template - static void maybe_valid_if(basic_observer &obs, basic_registry ®, const Entity entt) { - if(reg.template all_of(entt) && !reg.template any_of(entt)) { - if(!obs.storage.contains(entt)) { - obs.storage.emplace(entt); - } - - obs.storage.get(entt) |= (1 << Index); - } - } - - template - static void discard_if(basic_observer &obs, basic_registry &, const Entity entt) { - if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) { - obs.storage.remove(entt); - } - } - - template - static void connect(basic_observer &obs, basic_registry ®) { - (reg.template on_destroy().template connect<&discard_if>(obs), ...); - (reg.template on_construct().template connect<&discard_if>(obs), ...); - reg.template on_update().template connect<&maybe_valid_if>(obs); - reg.template on_destroy().template connect<&discard_if>(obs); - } - - static void disconnect(basic_observer &obs, basic_registry ®) { - (reg.template on_destroy().disconnect(obs), ...); - (reg.template on_construct().disconnect(obs), ...); - reg.template on_update().disconnect(obs); - reg.template on_destroy().disconnect(obs); - } - }; - - template - struct matcher_handler, type_list, type_list, AllOf...>> { - template - static void maybe_valid_if(basic_observer &obs, basic_registry ®, const Entity entt) { - if([®, entt]() { - if constexpr(sizeof...(Ignore) == 0) { - return reg.template all_of(entt) && !reg.template any_of(entt); - } else { - return reg.template all_of(entt) && ((std::is_same_v || !reg.template any_of(entt)) && ...) && !reg.template any_of(entt); - } - }()) - { - if(!obs.storage.contains(entt)) { - obs.storage.emplace(entt); - } - - obs.storage.get(entt) |= (1 << Index); - } - } - - template - static void discard_if(basic_observer &obs, basic_registry &, const Entity entt) { - if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) { - obs.storage.remove(entt); - } - } - - template - static void connect(basic_observer &obs, basic_registry ®) { - (reg.template on_destroy().template connect<&discard_if>(obs), ...); - (reg.template on_construct().template connect<&discard_if>(obs), ...); - (reg.template on_construct().template connect<&maybe_valid_if>(obs), ...); - (reg.template on_destroy().template connect<&maybe_valid_if>(obs), ...); - (reg.template on_destroy().template connect<&discard_if>(obs), ...); - (reg.template on_construct().template connect<&discard_if>(obs), ...); - } - - static void disconnect(basic_observer &obs, basic_registry ®) { - (reg.template on_destroy().disconnect(obs), ...); - (reg.template on_construct().disconnect(obs), ...); - (reg.template on_construct().disconnect(obs), ...); - (reg.template on_destroy().disconnect(obs), ...); - (reg.template on_destroy().disconnect(obs), ...); - (reg.template on_construct().disconnect(obs), ...); - } - }; - - template - static void disconnect(basic_registry ®, basic_observer &obs) { - (matcher_handler::disconnect(obs, reg), ...); - } - - template - void connect(basic_registry ®, std::index_sequence) { - static_assert(sizeof...(Matcher) < std::numeric_limits::digits, "Too many matchers"); - (matcher_handler::template connect(*this, reg), ...); - release.template connect<&basic_observer::disconnect>(reg); - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = typename basic_sparse_set::iterator; - - /*! @brief Default constructor. */ - basic_observer() - : release{}, - storage{} - {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_observer(const basic_observer &) = delete; - /*! @brief Default move constructor, deleted on purpose. */ - basic_observer(basic_observer &&) = delete; - - /** - * @brief Creates an observer and connects it to a given registry. - * @tparam Matcher Types of matchers to use to initialize the observer. - * @param reg A valid reference to a registry. - */ - template - basic_observer(basic_registry ®, basic_collector) - : basic_observer{} - { - connect(reg, std::index_sequence_for{}); - } - - /*! @brief Default destructor. */ - ~basic_observer() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This observer. - */ - basic_observer & operator=(const basic_observer &) = delete; - - /** - * @brief Default move assignment operator, deleted on purpose. - * @return This observer. - */ - basic_observer & operator=(basic_observer &&) = delete; - - /** - * @brief Connects an observer to a given registry. - * @tparam Matcher Types of matchers to use to initialize the observer. - * @param reg A valid reference to a registry. - */ - template - void connect(basic_registry ®, basic_collector) { - disconnect(); - connect(reg, std::index_sequence_for{}); - storage.clear(); - } - - /*! @brief Disconnects an observer from the registry it keeps track of. */ - void disconnect() { - if(release) { - release(*this); - release.reset(); - } - } - - /** - * @brief Returns the number of elements in an observer. - * @return Number of elements. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return storage.size(); - } - - /** - * @brief Checks whether an observer is empty. - * @return True if the observer is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return storage.empty(); - } - - /** - * @brief Direct access to the list of entities of the observer. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @note - * Entities are in the reverse order as returned by the `begin`/`end` - * iterators. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return storage.data(); - } - - /** - * @brief Returns an iterator to the first entity of the observer. - * - * The returned iterator points to the first entity of the observer. If the - * container is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the observer. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return storage.basic_sparse_set::begin(); - } - - /** - * @brief Returns an iterator that is past the last entity of the observer. - * - * The returned iterator points to the entity following the last entity of - * the observer. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * observer. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return storage.basic_sparse_set::end(); - } - - /*! @brief Clears the underlying container. */ - void clear() ENTT_NOEXCEPT { - storage.clear(); - } - - /** - * @brief Iterates entities and applies the given function object to them. - * - * The function object is invoked for each entity.
- * The signature of the function must be equivalent to the following form: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entity: *this) { - func(entity); - } - } - - /** - * @brief Iterates entities and applies the given function object to them, - * then clears the observer. - * - * @sa each - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) { - std::as_const(*this).each(std::move(func)); - clear(); - } - -private: - delegate release; - basic_storage storage; -}; - - -} - - -#endif - -// #include "entity/organizer.hpp" -#ifndef ENTT_ENTITY_ORGANIZER_HPP -#define ENTT_ENTITY_ORGANIZER_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "fwd.hpp" - -// #include "helper.hpp" -#ifndef ENTT_ENTITY_HELPER_HPP -#define ENTT_ENTITY_HELPER_HPP - - -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "../signal/delegate.hpp" - -// #include "registry.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Converts a registry to a view. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct as_view { - /*! @brief Underlying entity identifier. */ - using entity_type = std::remove_const_t; - /*! @brief Type of registry to convert. */ - using registry_type = constness_as_t, Entity>; - - /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. - */ - as_view(registry_type &source) ENTT_NOEXCEPT: reg{source} {} - - /** - * @brief Conversion function from a registry to a view. - * @tparam Exclude Types of components used to filter the view. - * @tparam Component Type of components used to construct the view. - * @return A newly created view. - */ - template - operator basic_view() const { - return reg.template view(Exclude{}); - } - -private: - registry_type ® -}; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_view(basic_registry &) -> as_view; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_view(const basic_registry &) -> as_view; - - -/** - * @brief Converts a registry to a group. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct as_group { - /*! @brief Underlying entity identifier. */ - using entity_type = std::remove_const_t; - /*! @brief Type of registry to convert. */ - using registry_type = constness_as_t, Entity>; - - /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. - */ - as_group(registry_type &source) ENTT_NOEXCEPT: reg{source} {} - - /** - * @brief Conversion function from a registry to a group. - * @tparam Exclude Types of components used to filter the group. - * @tparam Get Types of components observed by the group. - * @tparam Owned Types of components owned by the group. - * @return A newly created group. - */ - template - operator basic_group() const { - if constexpr(std::is_const_v) { - return reg.template group_if_exists(Get{}, Exclude{}); - } else { - return reg.template group(Get{}, Exclude{}); - } - } - -private: - registry_type ® -}; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_group(basic_registry &) -> as_group; - - -/** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -as_group(const basic_registry &) -> as_group; - - - -/** - * @brief Helper to create a listener that directly invokes a member function. - * @tparam Member Member function to invoke on a component of the given type. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @param reg A registry that contains the given entity and its components. - * @param entt Entity from which to get the component. - */ -template -void invoke(basic_registry ®, const Entity entt) { - static_assert(std::is_member_function_pointer_v, "Invalid pointer to non-static member function"); - delegate &, const Entity)> func; - func.template connect(reg.template get>(entt)); - func(reg, entt); -} - - -/** - * @brief Returns the entity associated with a given component. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Type of component. - * @param reg A registry that contains the given entity and its components. - * @param component A valid component instance. - * @return The entity associated with the given component. - */ -template -Entity to_entity(const basic_registry ®, const Component &component) { - const auto view = reg.template view(); - return *(view.data() + (&component - view.raw())); -} - - -} - - -#endif - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct is_view: std::false_type {}; - -template -struct is_view, Component...>>: std::true_type {}; - -template -inline constexpr bool is_view_v = is_view::value; - - -template -struct unpack_type { - using ro = std::conditional_t< - type_list_contains_v> || (std::is_const_v && !type_list_contains_v>), - type_list>, - type_list<> - >; - - using rw = std::conditional_t< - type_list_contains_v> || (!std::is_const_v && !type_list_contains_v>), - type_list, - type_list<> - >; -}; - -template -struct unpack_type, type_list> { - using ro = type_list<>; - using rw = type_list<>; -}; - -template -struct unpack_type, type_list> - : unpack_type, type_list> -{}; - -template -struct unpack_type, Component...>, type_list> { - using ro = type_list_cat_t, typename unpack_type>::ro...>; - using rw = type_list_cat_t>::rw...>; -}; - -template -struct unpack_type, Component...>, type_list> - : unpack_type, Component...>, type_list> -{}; - - -template -struct resource; - -template -struct resource, type_list> { - using args = type_list...>; - using ro = type_list_cat_t>::ro..., typename unpack_type>::ro...>; - using rw = type_list_cat_t>::rw..., typename unpack_type>::rw...>; -}; - - -template -resource...>, type_list> free_function_to_resource(Ret(*)(Args...)); - -template -resource...>, type_list> constrained_function_to_resource(Ret(*)(Type &, Args...)); - -template -resource...>, type_list> constrained_function_to_resource(Ret(Class:: *)(Args...)); - -template -resource...>, type_list> constrained_function_to_resource(Ret(Class:: *)(Args...) const); - -template -resource, type_list> to_resource(); - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Utility class for creating a static task graph. - * - * This class offers minimal support (but sufficient in many cases) for creating - * an execution graph from functions and their requirements on resources.
- * Note that the resulting tasks aren't executed in any case. This isn't the - * goal of the tool. Instead, they are returned to the user in the form of a - * graph that allows for safe execution. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_organizer final { - using callback_type = void(const void *, entt::basic_registry &); - using prepare_type = void(entt::basic_registry &); - using dependency_type = std::size_t(const bool, type_info *, const std::size_t); - - struct vertex_data final { - std::size_t ro_count{}; - std::size_t rw_count{}; - const char *name{}; - const void *payload{}; - callback_type *callback{}; - dependency_type *dependency; - prepare_type *prepare{}; - type_info info{}; - }; - - template - [[nodiscard]] static decltype(auto) extract(basic_registry ®) { - if constexpr(std::is_same_v>) { - return reg; - } else if constexpr(internal::is_view_v) { - return as_view{reg}; - } else { - return reg.template ctx_or_set>(); - } - } - - template - [[nodiscard]] static auto to_args(basic_registry ®, type_list) { - return std::tuple(reg))...>(extract(reg)...); - } - - template - static std::size_t fill_dependencies(type_list, [[maybe_unused]] type_info *buffer, [[maybe_unused]] const std::size_t count) { - if constexpr(sizeof...(Type) == 0u) { - return {}; - } else { - type_info info[sizeof...(Type)]{type_id()...}; - const auto length = std::min(count, sizeof...(Type)); - std::copy_n(info, length, buffer); - return length; - } - } - - template - void track_dependencies(std::size_t index, const bool requires_registry, type_list, type_list) { - dependencies[type_hash>::value()].emplace_back(index, requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u)); - (dependencies[type_hash::value()].emplace_back(index, false), ...); - (dependencies[type_hash::value()].emplace_back(index, true), ...); - } - - [[nodiscard]] std::vector adjacency_matrix() { - const auto length = vertices.size(); - std::vector edges(length * length, false); - - // creates the ajacency matrix - for(const auto &deps: dependencies) { - const auto last = deps.second.cend(); - auto it = deps.second.cbegin(); - - while(it != last) { - if(it->second) { - // rw item - if(auto curr = it++; it != last) { - if(it->second) { - edges[curr->first * length + it->first] = true; - } else { - if(const auto next = std::find_if(it, last, [](const auto &elem) { return elem.second; }); next != last) { - for(; it != next; ++it) { - edges[curr->first * length + it->first] = true; - edges[it->first * length + next->first] = true; - } - } else { - for(; it != next; ++it) { - edges[curr->first * length + it->first] = true; - } - } - } - } - } else { - // ro item, possibly only on first iteration - if(const auto next = std::find_if(it, last, [](const auto &elem) { return elem.second; }); next != last) { - for(; it != next; ++it) { - edges[it->first * length + next->first] = true; - } - } else { - it = last; - } - } - } - } - - // computes the transitive closure - for(std::size_t vk{}; vk < length; ++vk) { - for(std::size_t vi{}; vi < length; ++vi) { - for(std::size_t vj{}; vj < length; ++vj) { - edges[vi * length + vj] = edges[vi * length + vj] || (edges[vi * length + vk] && edges[vk * length + vj]); - } - } - } - - // applies the transitive reduction - for(std::size_t vert{}; vert < length; ++vert) { - edges[vert * length + vert] = false; - } - - for(std::size_t vj{}; vj < length; ++vj) { - for(std::size_t vi{}; vi < length; ++vi) { - if(edges[vi * length + vj]) { - for(std::size_t vk{}; vk < length; ++vk) { - if(edges[vj * length + vk]) { - edges[vi * length + vk] = false; - } - } - } - } - } - - return edges; - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Raw task function type. */ - using function_type = callback_type; - - /*! @brief Vertex type of a task graph defined as an adjacency list. */ - struct vertex { - /** - * @brief Constructs a vertex of the task graph. - * @param vtype True if the vertex is a top-level one, false otherwise. - * @param data The data associated with the vertex. - * @param edges The indices of the children in the adjacency list. - */ - vertex(const bool vtype, vertex_data data, std::vector edges) - : is_top_level{vtype}, - node{std::move(data)}, - reachable{std::move(edges)} - {} - - /** - * @brief Fills a buffer with the type info objects for the writable - * resources of a vertex. - * @param buffer A buffer pre-allocated by the user. - * @param length The length of the user-supplied buffer. - * @return The number of type info objects written to the buffer. - */ - size_type ro_dependency(type_info *buffer, const std::size_t length) const ENTT_NOEXCEPT { - return node.dependency(false, buffer, length); - } - - /** - * @brief Fills a buffer with the type info objects for the read-only - * resources of a vertex. - * @param buffer A buffer pre-allocated by the user. - * @param length The length of the user-supplied buffer. - * @return The number of type info objects written to the buffer. - */ - size_type rw_dependency(type_info *buffer, const std::size_t length) const ENTT_NOEXCEPT { - return node.dependency(true, buffer, length); - } - - /** - * @brief Returns the number of read-only resources of a vertex. - * @return The number of read-only resources of the vertex. - */ - size_type ro_count() const ENTT_NOEXCEPT { - return node.ro_count; - } - - /** - * @brief Returns the number of writable resources of a vertex. - * @return The number of writable resources of the vertex. - */ - size_type rw_count() const ENTT_NOEXCEPT { - return node.rw_count; - } - - /** - * @brief Checks if a vertex is also a top-level one. - * @return True if the vertex is a top-level one, false otherwise. - */ - bool top_level() const ENTT_NOEXCEPT { - return is_top_level; - } - - /** - * @brief Returns a type info object associated with a vertex. - * @return A properly initialized type info object. - */ - type_info info() const ENTT_NOEXCEPT { - return node.info; - } - - /** - * @brief Returns a user defined name associated with a vertex, if any. - * @return The user defined name associated with the vertex, if any. - */ - const char * name() const ENTT_NOEXCEPT { - return node.name; - } - - /** - * @brief Returns the function associated with a vertex. - * @return The function associated with the vertex. - */ - function_type * callback() const ENTT_NOEXCEPT { - return node.callback; - } - - /** - * @brief Returns the payload associated with a vertex, if any. - * @return The payload associated with the vertex, if any. - */ - const void * data() const ENTT_NOEXCEPT { - return node.payload; - } - - /** - * @brief Returns the list of nodes reachable from a given vertex. - * @return The list of nodes reachable from the vertex. - */ - const std::vector & children() const ENTT_NOEXCEPT { - return reachable; - } - - /** - * @brief Prepares a registry and assures that all required resources - * are properly instantiated before using them. - * @param reg A valid registry. - */ - void prepare(basic_registry ®) const { - node.prepare ? node.prepare(reg) : void(); - } - - private: - bool is_top_level; - vertex_data node; - std::vector reachable; - }; - - /** - * @brief Adds a free function to the task list. - * @tparam Candidate Function to add to the task list. - * @tparam Req Additional requirements and/or override resource access mode. - * @param name Optional name to associate with the task. - */ - template - void emplace(const char *name = nullptr) { - using resource_type = decltype(internal::free_function_to_resource(Candidate)); - constexpr auto requires_registry = type_list_contains_v>; - - callback_type *callback = +[](const void *, basic_registry ®) { - std::apply(Candidate, to_args(reg, typename resource_type::args{})); - }; - - track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{}); - - vertices.push_back({ - resource_type::ro::size, - resource_type::rw::size, - name, - nullptr, - callback, - +[](const bool rw, type_info *buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, - +[](basic_registry ®) { void(to_args(reg, typename resource_type::args{})); }, - type_id>() - }); - } - - /** - * @brief Adds a free function with payload or a member function with an - * instance to the task list. - * @tparam Candidate Function or member to add to the task list. - * @tparam Req Additional requirements and/or override resource access mode. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @param name Optional name to associate with the task. - */ - template - void emplace(Type &value_or_instance, const char *name = nullptr) { - using resource_type = decltype(internal::constrained_function_to_resource(Candidate)); - constexpr auto requires_registry = type_list_contains_v>; - - callback_type *callback = +[](const void *payload, basic_registry ®) { - Type *curr = static_cast(const_cast *>(payload)); - std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{}))); - }; - - track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{}); - - vertices.push_back({ - resource_type::ro::size, - resource_type::rw::size, - name, - &value_or_instance, - callback, - +[](const bool rw, type_info *buffer, const std::size_t length) { - return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); - }, - +[](basic_registry ®) { - void(to_args(reg, typename resource_type::args{})); - }, - type_id>() - }); - } - - /** - * @brief Adds an user defined function with optional payload to the task - * list. - * @tparam Req Additional requirements and/or override resource access mode. - * @param func Function to add to the task list. - * @param payload User defined arbitrary data. - * @param name Optional name to associate with the task. - */ - template - void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) { - using resource_type = internal::resource, type_list>; - track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{}); - - vertices.push_back({ - resource_type::ro::size, - resource_type::rw::size, - name, - payload, - func, - +[](const bool rw, type_info *buffer, const std::size_t length) { - return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); - }, - nullptr, - type_info{} - }); - } - - /** - * @brief Generates a task graph for the current content. - * @return The adjacency list of the task graph. - */ - std::vector graph() { - const auto edges = adjacency_matrix(); - - // creates the adjacency list - std::vector adjacency_list{}; - adjacency_list.reserve(vertices.size()); - - for(std::size_t col{}, length = vertices.size(); col < length; ++col) { - std::vector reachable{}; - const auto row = col * length; - bool is_top_level = true; - - for(std::size_t next{}; next < length; ++next) { - if(edges[row + next]) { - reachable.push_back(next); - } - } - - for(std::size_t next{}; next < length && is_top_level; ++next) { - is_top_level = !edges[next * length + col]; - } - - adjacency_list.emplace_back(is_top_level, vertices[col], std::move(reachable)); - } - - return adjacency_list; - } - - /*! @brief Erases all elements from a container. */ - void clear() { - dependencies.clear(); - vertices.clear(); - } - -private: - std::unordered_map>> dependencies; - std::vector vertices; -}; - - -} - - -#endif - -// #include "entity/poly_storage.hpp" -#ifndef ENTT_ENTITY_POLY_STORAGE_HPP -#define ENTT_ENTITY_POLY_STORAGE_HPP - - -#include -#include -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "../poly/poly.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Basic poly storage implementation. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct Storage: type_list { - /** - * @brief Concept definition. - * @tparam Base Opaque base class from which to inherit. - */ - template - struct type: Base { - /** - * @brief Returns a type info for the contained objects. - * @return The type info for the contained objects. - */ - type_info value_type() const ENTT_NOEXCEPT { - return poly_call<0>(*this); - } - }; - - /** - * @brief Concept implementation. - * @tparam Type Type for which to generate an implementation. - */ - template - using impl = value_list<&type_id>; -}; - - -/** - * @brief Defines the poly storage type associate with a given entity type. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct poly_storage_traits { - /*! @brief Poly storage type for the given entity type. */ - using storage_type = poly>; -}; - - -} - - -#endif - -// #include "entity/registry.hpp" -#ifndef ENTT_ENTITY_REGISTRY_HPP -#define ENTT_ENTITY_REGISTRY_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "../core/any.hpp" - -// #include "../core/fwd.hpp" - -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "group.hpp" - -// #include "poly_storage.hpp" - -// #include "runtime_view.hpp" - -// #include "sparse_set.hpp" - -// #include "storage.hpp" - -// #include "utility.hpp" - -// #include "view.hpp" - - - -namespace entt { - - -/** - * @brief Fast and reliable entity-component system. - * - * The registry is the core class of the entity-component framework.
- * It stores entities and arranges pools of components on a per request basis. - * By means of a registry, users can manage entities and components, then create - * views or groups to iterate them. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_registry { - using traits_type = entt_traits; - using poly_storage_type = typename poly_storage_traits::storage_type; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - struct pool_data { - poly_storage_type poly; - std::unique_ptr> pool{}; - }; - - template - struct group_handler; - - template - struct group_handler, get_t, Owned...> { - static_assert(std::conjunction_v>..., std::is_same>..., std::is_same>...>, "One or more component types are invalid"); - std::conditional_t, std::size_t> current{}; - - template - void maybe_valid_if(basic_registry &owner, const Entity entt) { - [[maybe_unused]] const auto cpools = std::make_tuple(owner.assure()...); - - const auto is_valid = ((std::is_same_v || std::get *>(cpools)->contains(entt)) && ...) - && ((std::is_same_v || owner.assure()->contains(entt)) && ...) - && ((std::is_same_v || !owner.assure()->contains(entt)) && ...); - - if constexpr(sizeof...(Owned) == 0) { - if(is_valid && !current.contains(entt)) { - current.emplace(entt); - } - } else { - if(is_valid && !(std::get<0>(cpools)->index(entt) < current)) { - const auto pos = current++; - (std::get *>(cpools)->swap(std::get *>(cpools)->data()[pos], entt), ...); - } - } - } - - void discard_if([[maybe_unused]] basic_registry &owner, const Entity entt) { - if constexpr(sizeof...(Owned) == 0) { - if(current.contains(entt)) { - current.remove(entt); - } - } else { - if(const auto cpools = std::make_tuple(owner.assure()...); std::get<0>(cpools)->contains(entt) && (std::get<0>(cpools)->index(entt) < current)) { - const auto pos = --current; - (std::get *>(cpools)->swap(std::get *>(cpools)->data()[pos], entt), ...); - } - } - } - }; - - struct group_data { - std::size_t size; - std::unique_ptr group; - bool (* owned)(const id_type) ENTT_NOEXCEPT; - bool (* get)(const id_type) ENTT_NOEXCEPT; - bool (* exclude)(const id_type) ENTT_NOEXCEPT; - }; - - template - [[nodiscard]] storage_type * assure() const { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - const auto index = type_seq::value(); - - if(!(index < pools.size())) { - pools.resize(size_type(index)+1u); - } - - if(auto &&pdata = pools[index]; !pdata.pool) { - pdata.pool.reset(new storage_type()); - pdata.poly.template emplace &>(*static_cast *>(pdata.pool.get())); - } - - return static_cast *>(pools[index].pool.get()); - } - - template - [[nodiscard]] const storage_type * pool_if_exists() const { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - const auto index = type_seq::value(); - return (!(index < pools.size()) || !pools[index].pool) ? nullptr : static_cast *>(pools[index].pool.get()); - } - - Entity generate_identifier() { - // traits_type::entity_mask is reserved to allow for null identifiers - ENTT_ASSERT(static_cast(entities.size()) < traits_type::entity_mask); - return entities.emplace_back(entity_type{static_cast(entities.size())}); - } - - Entity recycle_identifier() { - ENTT_ASSERT(available != null); - const auto curr = to_integral(available); - const auto version = to_integral(entities[curr]) & (traits_type::version_mask << traits_type::entity_shift); - available = entity_type{to_integral(entities[curr]) & traits_type::entity_mask}; - return entities[curr] = entity_type{curr | version}; - } - - void release_entity(const Entity entity, const typename traits_type::version_type version) { - const auto entt = to_integral(entity) & traits_type::entity_mask; - entities[entt] = entity_type{to_integral(available) | (typename traits_type::entity_type{version} << traits_type::entity_shift)}; - available = entity_type{entt}; - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Underlying version type. */ - using version_type = typename traits_type::version_type; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Poly storage type. */ - using poly_storage = typename poly_storage_traits::storage_type; - - /** - * @brief Returns the entity identifier without the version. - * @param entity An entity identifier, either valid or not. - * @return The entity identifier without the version. - */ - [[nodiscard]] static entity_type entity(const entity_type entity) ENTT_NOEXCEPT { - return entity_type{to_integral(entity) & traits_type::entity_mask}; - } - - /** - * @brief Returns the version stored along with an entity identifier. - * @param entity An entity identifier, either valid or not. - * @return The version stored along with the given entity identifier. - */ - [[nodiscard]] static version_type version(const entity_type entity) ENTT_NOEXCEPT { - return version_type(to_integral(entity) >> traits_type::entity_shift); - } - - /*! @brief Default constructor. */ - basic_registry() = default; - - /*! @brief Default move constructor. */ - basic_registry(basic_registry &&) = default; - - /*! @brief Default move assignment operator. @return This registry. */ - basic_registry & operator=(basic_registry &&) = default; - - /** - * @brief Prepares a pool for the given type if required. - * @tparam Component Type of component for which to prepare a pool. - */ - template - void prepare() { - // suppress the warning due to the [[nodiscard]] attribute - static_cast(assure()); - } - - /** - * @brief Returns a poly storage for a given type. - * @param info The type for which to return a poly storage. - * @return A valid poly storage if a pool for the given type exists, an - * empty and thus invalid element otherwise. - */ - poly_storage & storage(const type_info info) { - ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly); - return pools[info.seq()].poly; - } - - /*! @copydoc storage */ - const poly_storage & storage(const type_info info) const { - ENTT_ASSERT(info.seq() < pools.size() && pools[info.seq()].poly); - return pools[info.seq()].poly; - } - - /** - * @brief Returns the number of existing components of the given type. - * @tparam Component Type of component of which to return the size. - * @return Number of existing components of the given type. - */ - template - [[nodiscard]] size_type size() const { - const auto *cpool = pool_if_exists(); - return cpool ? cpool->size() : size_type{}; - } - - /** - * @brief Returns the number of entities created so far. - * @return Number of entities created so far. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return entities.size(); - } - - /** - * @brief Returns the number of entities still in use. - * @return Number of entities still in use. - */ - [[nodiscard]] size_type alive() const { - auto sz = entities.size(); - - for(auto curr = available; curr != null; --sz) { - curr = entities[to_integral(curr) & traits_type::entity_mask]; - } - - return sz; - } - - /** - * @brief Increases the capacity of the registry or of the pools for the - * given components. - * - * If no components are specified, the capacity of the registry is - * increased, that is the number of entities it contains. Otherwise the - * capacity of the pools for the given components is increased.
- * In both cases, if the new capacity is greater than the current capacity, - * new storage is allocated, otherwise the method does nothing. - * - * @tparam Component Types of components for which to reserve storage. - * @param cap Desired capacity. - */ - template - void reserve(const size_type cap) { - if constexpr(sizeof...(Component) == 0) { - entities.reserve(cap); - } else { - (assure()->reserve(cap), ...); - } - } - - /** - * @brief Reserves enough space to store `count` pools. - * @param count Number of pools to reserve space for. - */ - void reserve_pools(const size_t count) { - pools.reserve(count); - } - - /** - * @brief Returns the capacity of the pool for the given component. - * @tparam Component Type of component in which one is interested. - * @return Capacity of the pool of the given component. - */ - template - [[nodiscard]] size_type capacity() const { - const auto *cpool = pool_if_exists(); - return cpool ? cpool->capacity() : size_type{}; - } - - /** - * @brief Returns the number of entities that a registry has currently - * allocated space for. - * @return Capacity of the registry. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return entities.capacity(); - } - - /** - * @brief Requests the removal of unused capacity for the given components. - * @tparam Component Types of components for which to reclaim unused - * capacity. - */ - template - void shrink_to_fit() { - (assure()->shrink_to_fit(), ...); - } - - /** - * @brief Checks whether the registry or the pools of the given components - * are empty. - * - * A registry is considered empty when it doesn't contain entities that are - * still in use. - * - * @tparam Component Types of components in which one is interested. - * @return True if the registry or the pools of the given components are - * empty, false otherwise. - */ - template - [[nodiscard]] bool empty() const { - if constexpr(sizeof...(Component) == 0) { - return !alive(); - } else { - return [](const auto *... cpool) { return ((!cpool || cpool->empty()) && ...); }(pool_if_exists()...); - } - } - - /** - * @brief Direct access to the list of entities of a registry. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @warning - * This list contains both valid and destroyed entities and isn't suitable - * for direct use. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return entities.data(); - } - - /** - * @brief Returns the head of the list of destroyed entities. - * - * This function is intended for use in conjunction with `assign`.
- * The returned entity has an invalid identifier in all cases. - * - * @return The head of the list of destroyed entities. - */ - [[nodiscard]] entity_type destroyed() const ENTT_NOEXCEPT { - return available; - } - - /** - * @brief Checks if an entity identifier refers to a valid entity. - * @param entity An entity identifier, either valid or not. - * @return True if the identifier is valid, false otherwise. - */ - [[nodiscard]] bool valid(const entity_type entity) const { - const auto pos = size_type(to_integral(entity) & traits_type::entity_mask); - return (pos < entities.size() && entities[pos] == entity); - } - - /** - * @brief Returns the actual version for an entity identifier. - * - * @warning - * Attempting to use an entity that doesn't belong to the registry results - * in undefined behavior. An entity belongs to the registry even if it has - * been previously destroyed and/or recycled. - * - * @param entity A valid entity identifier. - * @return Actual version for the given entity identifier. - */ - [[nodiscard]] version_type current(const entity_type entity) const { - const auto pos = size_type(to_integral(entity) & traits_type::entity_mask); - ENTT_ASSERT(pos < entities.size()); - return version(entities[pos]); - } - - /** - * @brief Creates a new entity and returns it. - * - * There are two kinds of possible entity identifiers: - * - * * Newly created ones in case no entities have been previously destroyed. - * * Recycled ones with updated versions. - * - * @return A valid entity identifier. - */ - entity_type create() { - return available == null ? generate_identifier() : recycle_identifier(); - } - - /** - * @brief Creates a new entity and returns it. - * - * @sa create - * - * If the requested entity isn't in use, the suggested identifier is created - * and returned. Otherwise, a new one will be generated for this purpose. - * - * @param hint A desired entity identifier. - * @return A valid entity identifier. - */ - [[nodiscard]] entity_type create(const entity_type hint) { - ENTT_ASSERT(hint != null); - entity_type entt; - - if(const auto req = (to_integral(hint) & traits_type::entity_mask); !(req < entities.size())) { - entities.reserve(size_type(req) + 1u); - - for(auto pos = entities.size(); pos < req; ++pos) { - release_entity(generate_identifier(), {}); - } - - entt = entities.emplace_back(hint); - } else if(const auto curr = (to_integral(entities[req]) & traits_type::entity_mask); req == curr) { - entt = create(); - } else { - auto *it = &available; - for(; (to_integral(*it) & traits_type::entity_mask) != req; it = &entities[to_integral(*it) & traits_type::entity_mask]); - *it = entity_type{curr | (to_integral(*it) & (traits_type::version_mask << traits_type::entity_shift))}; - entt = entities[req] = hint; - } - - return entt; - } - - /** - * @brief Assigns each element in a range an entity. - * - * @sa create - * - * @tparam It Type of forward iterator. - * @param first An iterator to the first element of the range to generate. - * @param last An iterator past the last element of the range to generate. - */ - template - void create(It first, It last) { - for(; available != null && first != last; ++first) { - *first = recycle_identifier(); - } - - for(; first != last; ++first) { - *first = generate_identifier(); - } - } - - /** - * @brief Assigns entities to an empty registry. - * - * This function is intended for use in conjunction with `data`, `size` and - * `destroyed`.
- * Don't try to inject ranges of randomly generated entities nor the _wrong_ - * head for the list of destroyed entities. There is no guarantee that a - * registry will continue to work properly in this case. - * - * @warning - * There must be no entities still alive for this to work properly. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param destroyed The head of the list of destroyed entities. - */ - template - void assign(It first, It last, const entity_type destroyed) { - ENTT_ASSERT(!alive()); - entities.assign(first, last); - available = destroyed; - } - - /** - * @brief Destroys an entity. - * - * When an entity is destroyed, its version is updated and the identifier - * can be recycled at any time. - * - * @sa remove_all - * - * @param entity A valid entity identifier. - */ - void destroy(const entity_type entity) { - destroy(entity, static_cast(version(entity) + 1u)); - } - - /** - * @brief Destroys an entity. - * - * If the entity isn't already destroyed, the suggested version is used - * instead of the implicitly generated one. - * - * @sa remove_all - * - * @param entity A valid entity identifier. - * @param version A desired version upon destruction. - */ - void destroy(const entity_type entity, const version_type version) { - remove_all(entity); - release_entity(entity, version); - } - - /** - * @brief Destroys all the entities in a range. - * - * @sa destroy - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void destroy(It first, It last) { - for(; first != last; ++first) { - destroy(*first); - } - } - - /** - * @brief Assigns the given component to an entity. - * - * A new instance of the given component is created and initialized with the - * arguments provided (the component must have a proper constructor or be of - * aggregate type). Then the component is assigned to the given entity. - * - * @warning - * Attempting to use an invalid entity or to assign a component to an entity - * that already owns it results in undefined behavior. - * - * @tparam Component Type of component to create. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - decltype(auto) emplace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity)); - return assure()->emplace(*this, entity, std::forward(args)...); - } - - /** - * @brief Assigns each entity in a range the given component. - * - * @sa emplace - * - * @tparam Component Type of component to create. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param value An instance of the component to assign. - */ - template - void insert(It first, It last, const Component &value = {}) { - ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); - assure()->insert(*this, first, last, value); - } - - /** - * @brief Assigns each entity in a range the given components. - * - * @sa emplace - * - * @tparam Component Type of component to create. - * @tparam EIt Type of input iterator. - * @tparam CIt Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param from An iterator to the first element of the range of components. - * @param to An iterator past the last element of the range of components. - */ - template - void insert(EIt first, EIt last, CIt from, CIt to) { - static_assert(std::is_constructible_v::value_type>, "Invalid value type"); - ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); - assure()->insert(*this, first, last, from, to); - } - - /** - * @brief Assigns or replaces the given component for an entity. - * - * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * auto &component = registry.all_of(entity) ? registry.replace(entity, args...) : registry.emplace(entity, args...); - * @endcode - * - * Prefer this function anyway because it has slightly better performance. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Type of component to assign or replace. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - decltype(auto) emplace_or_replace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity)); - auto *cpool = assure(); - - return cpool->contains(entity) - ? cpool->patch(*this, entity, [&args...](auto &... curr) { ((curr = Component{std::forward(args)...}), ...); }) - : cpool->emplace(*this, entity, std::forward(args)...); - } - - /** - * @brief Patches the given component for an entity. - * - * The signature of the functions should be equivalent to the following: - * - * @code{.cpp} - * void(Component &); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned. However, this function can be used to trigger an update signal - * for them. - * - * @warning - * Attempting to use an invalid entity or to patch a component of an entity - * that doesn't own it results in undefined behavior. - * - * @tparam Component Type of component to patch. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the patched component. - */ - template - decltype(auto) patch(const entity_type entity, Func &&... func) { - ENTT_ASSERT(valid(entity)); - return assure()->patch(*this, entity, std::forward(func)...); - } - - /** - * @brief Replaces the given component for an entity. - * - * A new instance of the given component is created and initialized with the - * arguments provided (the component must have a proper constructor or be of - * aggregate type). Then the component is assigned to the given entity. - * - * @warning - * Attempting to use an invalid entity or to replace a component of an - * entity that doesn't own it results in undefined behavior. - * - * @tparam Component Type of component to replace. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the component being replaced. - */ - template - decltype(auto) replace(const entity_type entity, Args &&... args) { - return assure()->patch(*this, entity, [&args...](auto &... curr) { ((curr = Component{std::forward(args)...}), ...); }); - } - - /** - * @brief Removes the given components from an entity. - * - * @warning - * Attempting to use an invalid entity or to remove a component from an - * entity that doesn't own it results in undefined behavior. - * - * @tparam Component Types of components to remove. - * @param entity A valid entity identifier. - */ - template - void remove(const entity_type entity) { - ENTT_ASSERT(valid(entity)); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - (assure()->remove(entity, this), ...); - } - - /** - * @brief Removes the given components from all the entities in a range. - * - * @sa remove - * - * @tparam Component Types of components to remove. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void remove(It first, It last) { - ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - (assure()->remove(first, last, this), ...); - } - - /** - * @brief Removes the given components from an entity. - * - * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * if(registry.all_of(entity)) { registry.remove(entity) } - * @endcode - * - * Prefer this function anyway because it has slightly better performance. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Types of components to remove. - * @param entity A valid entity identifier. - * @return The number of components actually removed. - */ - template - size_type remove_if_exists(const entity_type entity) { - ENTT_ASSERT(valid(entity)); - - return ([this, entity](auto *cpool) { - return cpool->contains(entity) ? (cpool->remove(entity, this), true) : false; - }(assure()) + ... + size_type{}); - } - - /** - * @brief Removes all the components from an entity and makes it orphaned. - * - * @warning - * In case there are listeners that observe the destruction of components - * and assign other components to the entity in their bodies, the result of - * invoking this function may not be as expected. In the worst case, it - * could lead to undefined behavior. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @param entity A valid entity identifier. - */ - void remove_all(const entity_type entity) { - ENTT_ASSERT(valid(entity)); - entity_type wrap[1u]{entity}; - - for(auto pos = pools.size(); pos; --pos) { - if(auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) { - pdata.pool->remove(std::begin(wrap), std::end(wrap), this); - } - } - } - - /** - * @brief Checks if an entity has all the given components. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Components for which to perform the check. - * @param entity A valid entity identifier. - * @return True if the entity has all the components, false otherwise. - */ - template - [[nodiscard]] bool all_of(const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - return [entity](const auto *... cpool) { return ((cpool && cpool->contains(entity)) && ...); }(pool_if_exists()...); - } - - /** - * @brief Checks if an entity has at least one of the given components. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Components for which to perform the check. - * @param entity A valid entity identifier. - * @return True if the entity has at least one of the given components, - * false otherwise. - */ - template - [[nodiscard]] bool any_of(const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - return [entity](const auto *... cpool) { return !((!cpool || !cpool->contains(entity)) && ...); }(pool_if_exists()...); - } - - /** - * @brief Returns references to the given components for an entity. - * - * @warning - * Attempting to use an invalid entity or to get a component from an entity - * that doesn't own it results in undefined behavior. - * - * @tparam Component Types of components to get. - * @param entity A valid entity identifier. - * @return References to the components owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - const auto *cpool = pool_if_exists...>(); - ENTT_ASSERT(cpool); - return cpool->get(entity); - } else { - return std::forward_as_tuple(get(entity)...); - } - } - - /*! @copydoc get */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - return (const_cast(assure>()->get(entity)), ...); - } else { - return std::forward_as_tuple(get(entity)...); - } - } - - /** - * @brief Returns a reference to the given component for an entity. - * - * In case the entity doesn't own the component, the parameters provided are - * used to construct it.
- * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * auto &component = registry.all_of(entity) ? registry.get(entity) : registry.emplace(entity, args...); - * @endcode - * - * Prefer this function anyway because it has slightly better performance. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @tparam Component Type of component to get. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return Reference to the component owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity)); - auto *cpool = assure(); - return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(*this, entity, std::forward(args)...); - } - - /** - * @brief Returns pointers to the given components for an entity. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @note - * The registry retains ownership of the pointed-to components. - * - * @tparam Component Types of components to get. - * @param entity A valid entity identifier. - * @return Pointers to the components owned by the entity. - */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - const auto *cpool = pool_if_exists...>(); - return (cpool && cpool->contains(entity)) ? &cpool->get(entity) : nullptr; - } else { - return std::make_tuple(try_get(entity)...); - } - } - - /*! @copydoc try_get */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity)); - - if constexpr(sizeof...(Component) == 1) { - return (const_cast(std::as_const(*this).template try_get(entity)), ...); - } else { - return std::make_tuple(try_get(entity)...); - } - } - - /** - * @brief Clears a whole registry or the pools for the given components. - * @tparam Component Types of components to remove from their entities. - */ - template - void clear() { - if constexpr(sizeof...(Component) == 0) { - for(auto pos = pools.size(); pos; --pos) { - if(auto &pdata = pools[pos-1]; pdata.pool) { - pdata.pool->clear(this); - } - } - - each([this](const auto entity) { release_entity(entity, version(entity) + 1u); }); - } else { - ([this](auto *cpool) { - cpool->remove(cpool->basic_sparse_set::begin(), cpool->basic_sparse_set::end(), this); - }(assure()), ...); - } - } - - /** - * @brief Iterates all the entities that are still in use. - * - * The function object is invoked for each entity that is still in use.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const Entity); - * @endcode - * - * This function is fairly slow and should not be used frequently. However, - * it's useful for iterating all the entities still in use, regardless of - * their components. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - if(available == null) { - for(auto pos = entities.size(); pos; --pos) { - func(entities[pos-1]); - } - } else { - for(auto pos = entities.size(); pos; --pos) { - if(const auto entity = entities[pos - 1]; (to_integral(entity) & traits_type::entity_mask) == (pos - 1)) { - func(entity); - } - } - } - } - - /** - * @brief Checks if an entity has components assigned. - * @param entity A valid entity identifier. - * @return True if the entity has no components assigned, false otherwise. - */ - [[nodiscard]] bool orphan(const entity_type entity) const { - ENTT_ASSERT(valid(entity)); - return std::none_of(pools.cbegin(), pools.cend(), [entity](auto &&pdata) { return pdata.pool && pdata.pool->contains(entity); }); - } - - /** - * @brief Iterates orphans and applies them the given function object. - * - * The function object is invoked for each entity that is still in use and - * has no components assigned.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const Entity); - * @endcode - * - * This function can be very slow and should not be used frequently. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void orphans(Func func) const { - each([this, &func](const auto entity) { - if(orphan(entity)) { - func(entity); - } - }); - } - - /** - * @brief Returns a sink object for the given component. - * - * The sink returned by this function can be used to receive notifications - * whenever a new instance of the given component is created and assigned to - * an entity.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** the component has been assigned to the - * entity. - * - * @sa sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_construct() { - return assure()->on_construct(); - } - - /** - * @brief Returns a sink object for the given component. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance of the given component is explicitly updated.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** the component has been updated. - * - * @sa sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_update() { - return assure()->on_update(); - } - - /** - * @brief Returns a sink object for the given component. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance of the given component is removed from an entity and - * thus destroyed.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **before** the component has been removed from the - * entity. - * - * @sa sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_destroy() { - return assure()->on_destroy(); - } - - /** - * @brief Returns a view for the given components. - * - * This kind of objects are created on the fly and share with the registry - * its internal data structures.
- * Feel free to discard a view after the use. Creating and destroying a view - * is an incredibly cheap operation because they do not require any type of - * initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Views do their best to iterate the smallest set of candidate entities. - * In particular: - * - * * Single component views are incredibly fast and iterate a packed array - * of entities, all of which has the given component. - * * Multi component views look at the number of entities available for each - * component and pick up a reference to the smallest set of candidates to - * test for the given components. - * - * Views in no way affect the functionalities of the registry nor those of - * the underlying pools. - * - * @note - * Multi component views are pretty fast. However their performance tend to - * degenerate when the number of components to iterate grows up and the most - * of the entities have all the given components.
- * To get a performance boost, consider using a group instead. - * - * @tparam Component Type of components used to construct the view. - * @tparam Exclude Types of components used to filter the view. - * @return A newly created view. - */ - template - [[nodiscard]] basic_view, Component...> view(exclude_t = {}) const { - static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - static_assert((std::is_const_v && ...), "Invalid non-const type"); - return { *assure>()..., *assure()... }; - } - - /*! @copydoc view */ - template - [[nodiscard]] basic_view, Component...> view(exclude_t = {}) { - static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - return { *assure>()..., *assure()... }; - } - - /** - * @brief Returns a runtime view for the given components. - * - * This kind of objects are created on the fly and share with the registry - * its internal data structures.
- * Users should throw away the view after use. Fortunately, creating and - * destroying a runtime view is an incredibly cheap operation because they - * do not require any type of initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Runtime views are to be used when users want to construct a view from - * some external inputs and don't know at compile-time what are the required - * components. - * - * @tparam ItComp Type of input iterator for the components to use to - * construct the view. - * @tparam ItExcl Type of input iterator for the components to use to filter - * the view. - * @param first An iterator to the first element of the range of components - * to use to construct the view. - * @param last An iterator past the last element of the range of components - * to use to construct the view. - * @param from An iterator to the first element of the range of components - * to use to filter the view. - * @param to An iterator past the last element of the range of components to - * use to filter the view. - * @return A newly created runtime view. - */ - template - [[nodiscard]] basic_runtime_view runtime_view(ItComp first, ItComp last, ItExcl from = {}, ItExcl to = {}) const { - std::vector *> component(std::distance(first, last)); - std::vector *> filter(std::distance(from, to)); - - std::transform(first, last, component.begin(), [this](const auto ctype) { - const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; }); - return it == pools.cend() ? nullptr : it->pool.get(); - }); - - std::transform(from, to, filter.begin(), [this](const auto ctype) { - const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto &&pdata) { return pdata.poly && pdata.poly->value_type().hash() == ctype; }); - return it == pools.cend() ? nullptr : it->pool.get(); - }); - - return { std::move(component), std::move(filter) }; - } - - /** - * @brief Returns a group for the given components. - * - * This kind of objects are created on the fly and share with the registry - * its internal data structures.
- * Feel free to discard a group after the use. Creating and destroying a - * group is an incredibly cheap operation because they do not require any - * type of initialization, but for the first time they are requested.
- * As a rule of thumb, storing a group should never be an option. - * - * Groups support exclusion lists and can own types of components. The more - * types are owned by a group, the faster it is to iterate entities and - * components.
- * However, groups also affect some features of the registry such as the - * creation and destruction of components, which will consequently be - * slightly slower (nothing that can be noticed in most cases). - * - * @note - * Pools of components that are owned by a group cannot be sorted anymore. - * The group takes the ownership of the pools and arrange components so as - * to iterate them as fast as possible. - * - * @tparam Owned Types of components owned by the group. - * @tparam Get Types of components observed by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t, Owned...> group(get_t, exclude_t = {}) { - static_assert(sizeof...(Owned) + sizeof...(Get) > 0, "Exclusion-only groups are not supported"); - static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1, "Single component groups are not allowed"); - - using handler_type = group_handler, get_t...>, std::remove_const_t...>; - - const auto cpools = std::make_tuple(assure>()..., assure>()...); - constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude); - handler_type *handler = nullptr; - - if(auto it = std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - return gdata.size == size - && (gdata.owned(type_hash>::value()) && ...) - && (gdata.get(type_hash>::value()) && ...) - && (gdata.exclude(type_hash::value()) && ...); - }); it != groups.cend()) - { - handler = static_cast(it->group.get()); - } - - if(!handler) { - group_data candidate = { - size, - { new handler_type{}, [](void *instance) { delete static_cast(instance); } }, - []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash>::value()) || ...); }, - []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash>::value()) || ...); }, - []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_hash::value()) || ...); }, - }; - - handler = static_cast(candidate.group.get()); - - const void *maybe_valid_if = nullptr; - const void *discard_if = nullptr; - - if constexpr(sizeof...(Owned) == 0) { - groups.push_back(std::move(candidate)); - } else { - ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - const auto overlapping = (0u + ... + gdata.owned(type_hash>::value())); - const auto sz = overlapping + (0u + ... + gdata.get(type_hash>::value())) + (0u + ... + gdata.exclude(type_hash::value())); - return !overlapping || ((sz == size) || (sz == gdata.size)); - })); - - const auto next = std::find_if_not(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - return !(0u + ... + gdata.owned(type_hash>::value())) || (size > gdata.size); - }); - - const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto &gdata) { - return (0u + ... + gdata.owned(type_hash>::value())); - }); - - maybe_valid_if = (next == groups.cend() ? maybe_valid_if : next->group.get()); - discard_if = (prev == groups.crend() ? discard_if : prev->group.get()); - groups.insert(next, std::move(candidate)); - } - - (on_construct>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if>>(*handler), ...); - (on_construct>().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if>>(*handler), ...); - (on_destroy().before(maybe_valid_if).template connect<&handler_type::template maybe_valid_if>(*handler), ...); - - (on_destroy>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...); - (on_destroy>().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...); - (on_construct().before(discard_if).template connect<&handler_type::discard_if>(*handler), ...); - - if constexpr(sizeof...(Owned) == 0) { - for(const auto entity: view(exclude)) { - handler->current.emplace(entity); - } - } else { - // we cannot iterate backwards because we want to leave behind valid entities in case of owned types - for(auto *first = std::get<0>(cpools)->data(), *last = first + std::get<0>(cpools)->size(); first != last; ++first) { - handler->template maybe_valid_if...>>>(*this, *first); - } - } - } - - return { handler->current, *std::get> *>(cpools)..., *std::get> *>(cpools)... }; - } - - /** - * @brief Returns a group for the given components. - * - * @sa group - * - * @tparam Owned Types of components owned by the group. - * @tparam Get Types of components observed by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t, Owned...> group_if_exists(get_t, exclude_t = {}) const { - static_assert(std::conjunction_v..., std::is_const...>, "Invalid non-const type"); - - if(auto it = std::find_if(groups.cbegin(), groups.cend(), [](const auto &gdata) { - return gdata.size == (sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude)) - && (gdata.owned(type_hash>::value()) && ...) - && (gdata.get(type_hash>::value()) && ...) - && (gdata.exclude(type_hash::value()) && ...); - }); it == groups.cend()) - { - return {}; - } else { - using handler_type = group_handler, get_t...>, std::remove_const_t...>; - return { static_cast(it->group.get())->current, *pool_if_exists>()... , *pool_if_exists>()... }; - } - } - - /** - * @brief Returns a group for the given components. - * - * @sa group - * - * @tparam Owned Types of components owned by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t<>, Owned...> group(exclude_t = {}) { - return group(get_t<>{}, exclude); - } - - /** - * @brief Returns a group for the given components. - * - * @sa group_if_exists - * - * @tparam Owned Types of components owned by the group. - * @tparam Exclude Types of components used to filter the group. - * @return A newly created group. - */ - template - [[nodiscard]] basic_group, get_t<>, Owned...> group_if_exists(exclude_t = {}) const { - return group_if_exists(get_t<>{}, exclude); - } - - /** - * @brief Checks whether the given components belong to any group. - * @tparam Component Types of components in which one is interested. - * @return True if the pools of the given components are sortable, false - * otherwise. - */ - template - [[nodiscard]] bool sortable() const { - return std::none_of(groups.cbegin(), groups.cend(), [](auto &&gdata) { return (gdata.owned(type_hash>::value()) || ...); }); - } - - /** - * @brief Checks whether a group can be sorted. - * @tparam Owned Types of components owned by the group. - * @tparam Get Types of components observed by the group. - * @tparam Exclude Types of components used to filter the group. - * @return True if the group can be sorted, false otherwise. - */ - template - [[nodiscard]] bool sortable(const basic_group, get_t, Owned...> &) ENTT_NOEXCEPT { - constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude); - return std::find_if(groups.cbegin(), groups.cend(), [size](const auto &gdata) { - return (0u + ... + gdata.owned(type_hash>::value())) && (size < gdata.size); - }) == groups.cend(); - } - - /** - * @brief Sorts the pool of entities for the given component. - * - * The order of the elements in a pool is highly affected by assignments - * of components to entities and deletions. Components are arranged to - * maximize the performance during iterations and users should not make any - * assumption on the order.
- * This function can be used to impose an order to the elements in the pool - * of the given component. The order is kept valid until a component of the - * given type is assigned or removed from an entity. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * bool(const Component &, const Component &); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * The comparison funtion object received by the sort function object hasn't - * necessarily the type of the one passed along with the other parameters to - * this member function. - * - * @warning - * Pools of components owned by a group cannot be sorted. - * - * @tparam Component Type of components to sort. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - ENTT_ASSERT(sortable()); - assure()->sort(std::move(compare), std::move(algo), std::forward(args)...); - } - - /** - * @brief Sorts two pools of components in the same way. - * - * The order of the elements in a pool is highly affected by assignments - * of components to entities and deletions. Components are arranged to - * maximize the performance during iterations and users should not make any - * assumption on the order. - * - * It happens that different pools of components must be sorted the same way - * because of runtime and/or performance constraints. This function can be - * used to order a pool of components according to the order between the - * entities in another pool of components. - * - * @b How @b it @b works - * - * Being `A` and `B` the two sets where `B` is the master (the one the order - * of which rules) and `A` is the slave (the one to sort), after a call to - * this function an iterator for `A` will return the entities according to - * the following rules: - * - * * All the entities in `A` that are also in `B` are returned first - * according to the order they have in `B`. - * * All the entities in `A` that are not in `B` are returned in no - * particular order after all the other entities. - * - * Any subsequent change to `B` won't affect the order in `A`. - * - * @warning - * Pools of components owned by a group cannot be sorted. - * - * @tparam To Type of components to sort. - * @tparam From Type of components to use to sort. - */ - template - void sort() { - ENTT_ASSERT(sortable()); - assure()->respect(*assure()); - } - - /** - * @brief Visits an entity and returns the type info for its components. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const type_info); - * @endcode - * - * Returned identifiers are those of the components owned by the entity. - * - * @sa type_info - * - * @warning - * It's not specified whether a component attached to or removed from the - * given entity during the visit is returned or not to the caller. - * - * @tparam Func Type of the function object to invoke. - * @param entity A valid entity identifier. - * @param func A valid function object. - */ - template - void visit(entity_type entity, Func func) const { - for(auto pos = pools.size(); pos; --pos) { - if(const auto &pdata = pools[pos-1]; pdata.pool && pdata.pool->contains(entity)) { - func(pdata.poly->value_type()); - } - } - } - - /** - * @brief Visits a registry and returns the type info for its components. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const type_info); - * @endcode - * - * Returned identifiers are those of the components managed by the registry. - * - * @sa type_info - * - * @warning - * It's not specified whether a component for which a pool is created during - * the visit is returned or not to the caller. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void visit(Func func) const { - for(auto pos = pools.size(); pos; --pos) { - if(const auto &pdata = pools[pos-1]; pdata.pool) { - func(pdata.poly->value_type()); - } - } - } - - /** - * @brief Binds an object to the context of the registry. - * - * If the value already exists it is overwritten, otherwise a new instance - * of the given type is created and initialized with the arguments provided. - * - * @tparam Type Type of object to set. - * @tparam Args Types of arguments to use to construct the object. - * @param args Parameters to use to initialize the value. - * @return A reference to the newly created object. - */ - template - Type & set(Args &&... args) { - unset(); - vars.emplace_back(std::in_place_type, std::forward(args)...); - return any_cast(vars.back()); - } - - /** - * @brief Unsets a context variable if it exists. - * @tparam Type Type of object to set. - */ - template - void unset() { - vars.erase(std::remove_if(vars.begin(), vars.end(), [type = type_id()](auto &&var) { return var.type() == type; }), vars.end()); - } - - /** - * @brief Binds an object to the context of the registry. - * - * In case the context doesn't contain the given object, the parameters - * provided are used to construct it. - * - * @tparam Type Type of object to set. - * @tparam Args Types of arguments to use to construct the object. - * @param args Parameters to use to initialize the object. - * @return A reference to the object in the context of the registry. - */ - template - [[nodiscard]] Type & ctx_or_set(Args &&... args) { - auto *value = try_ctx(); - return value ? *value : set(std::forward(args)...); - } - - /** - * @brief Returns a pointer to an object in the context of the registry. - * @tparam Type Type of object to get. - * @return A pointer to the object if it exists in the context of the - * registry, a null pointer otherwise. - */ - template - [[nodiscard]] Type * try_ctx() const { - auto it = std::find_if(vars.cbegin(), vars.cend(), [type = type_id()](auto &&var) { return var.type() == type; }); - return it == vars.cend() ? nullptr : any_cast(&*it); - } - - /*! @copydoc try_ctx */ - template - [[nodiscard]] Type * try_ctx() { - auto it = std::find_if(vars.begin(), vars.end(), [type = type_id()](auto &&var) { return var.type() == type; }); - return it == vars.end() ? nullptr : any_cast(&*it); - } - - /** - * @brief Returns a reference to an object in the context of the registry. - * - * @warning - * Attempting to get a context variable that doesn't exist results in - * undefined behavior. - * - * @tparam Type Type of object to get. - * @return A valid reference to the object in the context of the registry. - */ - template - [[nodiscard]] Type & ctx() const { - auto it = std::find_if(vars.cbegin(), vars.cend(), [type = type_id()](auto &&var) { return var.type() == type; }); - ENTT_ASSERT(it != vars.cend()); - return any_cast(*it); - } - - /*! @copydoc ctx */ - template - [[nodiscard]] Type & ctx() { - auto it = std::find_if(vars.begin(), vars.end(), [type = type_id()](auto &&var) { return var.type() == type; }); - ENTT_ASSERT(it != vars.end()); - return any_cast(*it); - } - - /** - * @brief Visits a registry and returns the type info for its context - * variables. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const type_info); - * @endcode - * - * Returned identifiers are those of the context variables currently set. - * - * @sa type_info - * - * @warning - * It's not specified whether a context variable created during the visit is - * returned or not to the caller. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void ctx(Func func) const { - for(auto pos = vars.size(); pos; --pos) { - func(vars[pos-1].type()); - } - } - -private: - std::vector> vars{}; - mutable std::vector pools{}; - std::vector groups{}; - std::vector entities{}; - entity_type available{null}; -}; - - -} - - -#endif - -// #include "entity/runtime_view.hpp" -#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP -#define ENTT_ENTITY_RUNTIME_VIEW_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "sparse_set.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Runtime view. - * - * Runtime views iterate over those entities that have at least all the given - * components in their bags. During initialization, a runtime view looks at the - * number of entities available for each component and picks up a reference to - * the smallest set of candidate entities in order to get a performance boost - * when iterate.
- * Order of elements during iterations are highly dependent on the order of the - * underlying data structures. See sparse_set and its specializations for more - * details. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all the other cases, modifying the pools of the given components in any - * way invalidates all the iterators and using them results in undefined - * behavior. - * - * @note - * Views share references to the underlying data structures of the registry that - * generated them. Therefore any change to the entities and to the components - * made by means of the registry are immediately reflected by the views, unless - * a pool was missing when the view was built (in this case, the view won't - * have a valid reference and won't be updated accordingly). - * - * @warning - * Lifetime of a view must not overcome that of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_runtime_view final { - using underlying_iterator = typename basic_sparse_set::iterator; - - class view_iterator final { - friend class basic_runtime_view; - - view_iterator(const std::vector *> &cpools, const std::vector *> &ignore, underlying_iterator curr) ENTT_NOEXCEPT - : pools{&cpools}, - filter{&ignore}, - it{curr} - { - if(it != (*pools)[0]->end() && !valid()) { - ++(*this); - } - } - - [[nodiscard]] bool valid() const { - return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); }) - && std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); }); - } - - public: - using difference_type = typename underlying_iterator::difference_type; - using value_type = typename underlying_iterator::value_type; - using pointer = typename underlying_iterator::pointer; - using reference = typename underlying_iterator::reference; - using iterator_category = std::bidirectional_iterator_tag; - - view_iterator() ENTT_NOEXCEPT = default; - - view_iterator & operator++() { - while(++it != (*pools)[0]->end() && !valid()); - return *this; - } - - view_iterator operator++(int) { - view_iterator orig = *this; - return ++(*this), orig; - } - - view_iterator & operator--() ENTT_NOEXCEPT { - while(--it != (*pools)[0]->begin() && !valid()); - return *this; - } - - view_iterator operator--(int) ENTT_NOEXCEPT { - view_iterator orig = *this; - return operator--(), orig; - } - - [[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] pointer operator->() const { - return it.operator->(); - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - const std::vector *> *pools; - const std::vector *> *filter; - underlying_iterator it; - }; - - [[nodiscard]] bool valid() const { - return !pools.empty() && pools.front(); - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Bidirectional iterator type. */ - using iterator = view_iterator; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_runtime_view() ENTT_NOEXCEPT - : pools{}, - filter{} - {} - - /** - * @brief Constructs a runtime view from a set of storage classes. - * @param cpools The storage for the types to iterate. - * @param epools The storage for the types used to filter the view. - */ - basic_runtime_view(std::vector *> cpools, std::vector *> epools) ENTT_NOEXCEPT - : pools{std::move(cpools)}, - filter{std::move(epools)} - { - const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) { - return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size()); - }); - - // brings the best candidate (if any) on front of the vector - std::rotate(pools.begin(), it, pools.end()); - } - - /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. - */ - [[nodiscard]] size_type size_hint() const { - return valid() ? pools.front()->size() : size_type{}; - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @return An iterator to the first entity that has the given components. - */ - [[nodiscard]] iterator begin() const { - return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - [[nodiscard]] iterator end() const { - return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{}; - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); }) - && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); }); - } - - /** - * @brief Iterates entities and applies the given function object to them. - * - * The function object is invoked for each entity. It is provided only with - * the entity itself. To get the components, users can use the registry with - * which the view was built.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entity: *this) { - func(entity); - } - } - -private: - std::vector *> pools; - std::vector *> filter; -}; - - -} - - -#endif - -// #include "entity/snapshot.hpp" -#ifndef ENTT_ENTITY_SNAPSHOT_HPP -#define ENTT_ENTITY_SNAPSHOT_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "registry.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to create snapshots from a registry. - * - * A _snapshot_ can be either a dump of the entire registry or a narrower - * selection of components of interest.
- * This type can be used in both cases if provided with a correctly configured - * output archive. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_snapshot { - using traits_type = entt_traits; - - template - void get(Archive &archive, std::size_t sz, It first, It last) const { - const auto view = reg->template view>(); - archive(typename traits_type::entity_type(sz)); - - while(first != last) { - const auto entt = *(first++); - - if(reg->template all_of(entt)) { - std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt))); - } - } - } - - template - void component(Archive &archive, It first, It last, std::index_sequence) const { - std::array size{}; - auto begin = first; - - while(begin != last) { - const auto entt = *(begin++); - ((reg->template all_of(entt) ? ++size[Index] : size[Index]), ...); - } - - (get(archive, size[Index], first, last), ...); - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - - /** - * @brief Constructs an instance that is bound to a given registry. - * @param source A valid reference to a registry. - */ - basic_snapshot(const basic_registry &source) ENTT_NOEXCEPT - : reg{&source} - {} - - /*! @brief Default move constructor. */ - basic_snapshot(basic_snapshot &&) = default; - - /*! @brief Default move assignment operator. @return This snapshot. */ - basic_snapshot & operator=(basic_snapshot &&) = default; - - /** - * @brief Puts aside all the entities from the underlying registry. - * - * Entities are serialized along with their versions. Destroyed entities are - * taken in consideration as well by this function. - * - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - const basic_snapshot & entities(Archive &archive) const { - const auto sz = reg->size(); - - archive(typename traits_type::entity_type(sz)); - - for(auto first = reg->data(), last = first + sz; first != last; ++first) { - archive(*first); - } - - archive(reg->destroyed()); - - return *this; - } - - /** - * @brief Puts aside the given components. - * - * Each instance is serialized together with the entity to which it belongs. - * Entities are serialized along with their versions. - * - * @tparam Component Types of components to serialize. - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - const basic_snapshot & component(Archive &archive) const { - if constexpr(sizeof...(Component) == 1u) { - const auto view = reg->template view(); - (component(archive, view.data(), view.data() + view.size()), ...); - return *this; - } else { - (component(archive), ...); - return *this; - } - } - - /** - * @brief Puts aside the given components for the entities in a range. - * - * Each instance is serialized together with the entity to which it belongs. - * Entities are serialized along with their versions. - * - * @tparam Component Types of components to serialize. - * @tparam Archive Type of output archive. - * @tparam It Type of input iterator. - * @param archive A valid reference to an output archive. - * @param first An iterator to the first element of the range to serialize. - * @param last An iterator past the last element of the range to serialize. - * @return An object of this type to continue creating the snapshot. - */ - template - const basic_snapshot & component(Archive &archive, It first, It last) const { - component(archive, first, last, std::index_sequence_for{}); - return *this; - } - -private: - const basic_registry *reg; -}; - - -/** - * @brief Utility class to restore a snapshot as a whole. - * - * A snapshot loader requires that the destination registry be empty and loads - * all the data at once while keeping intact the identifiers that the entities - * originally had.
- * An example of use is the implementation of a save/restore utility. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_snapshot_loader { - using traits_type = entt_traits; - - template - void assign(Archive &archive) const { - typename traits_type::entity_type length{}; - archive(length); - - entity_type entt{}; - - if constexpr(std::tuple_size_vtemplate view().get({}))> == 0) { - while(length--) { - archive(entt); - const auto entity = reg->valid(entt) ? entt : reg->create(entt); - ENTT_ASSERT(entity == entt); - reg->template emplace(entity); - } - } else { - Type instance{}; - - while(length--) { - archive(entt, instance); - const auto entity = reg->valid(entt) ? entt : reg->create(entt); - ENTT_ASSERT(entity == entt); - reg->template emplace(entity, std::move(instance)); - } - } - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - - /** - * @brief Constructs an instance that is bound to a given registry. - * @param source A valid reference to a registry. - */ - basic_snapshot_loader(basic_registry &source) ENTT_NOEXCEPT - : reg{&source} - { - // restoring a snapshot as a whole requires a clean registry - ENTT_ASSERT(reg->empty()); - } - - /*! @brief Default move constructor. */ - basic_snapshot_loader(basic_snapshot_loader &&) = default; - - /*! @brief Default move assignment operator. @return This loader. */ - basic_snapshot_loader & operator=(basic_snapshot_loader &&) = default; - - /** - * @brief Restores entities that were in use during serialization. - * - * This function restores the entities that were in use during serialization - * and gives them the versions they originally had. - * - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A valid loader to continue restoring data. - */ - template - const basic_snapshot_loader & entities(Archive &archive) const { - typename traits_type::entity_type length{}; - - archive(length); - std::vector all(length); - - for(decltype(length) pos{}; pos < length; ++pos) { - archive(all[pos]); - } - - entity_type destroyed; - archive(destroyed); - - reg->assign(all.cbegin(), all.cend(), destroyed); - - return *this; - } - - /** - * @brief Restores components and assigns them to the right entities. - * - * The template parameter list must be exactly the same used during - * serialization. In the event that the entity to which the component is - * assigned doesn't exist yet, the loader will take care to create it with - * the version it originally had. - * - * @tparam Component Types of components to restore. - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A valid loader to continue restoring data. - */ - template - const basic_snapshot_loader & component(Archive &archive) const { - (assign(archive), ...); - return *this; - } - - /** - * @brief Destroys those entities that have no components. - * - * In case all the entities were serialized but only part of the components - * was saved, it could happen that some of the entities have no components - * once restored.
- * This functions helps to identify and destroy those entities. - * - * @return A valid loader to continue restoring data. - */ - const basic_snapshot_loader & orphans() const { - reg->orphans([this](const auto entt) { - reg->destroy(entt); - }); - - return *this; - } - -private: - basic_registry *reg; -}; - - -/** - * @brief Utility class for _continuous loading_. - * - * A _continuous loader_ is designed to load data from a source registry to a - * (possibly) non-empty destination. The loader can accommodate in a registry - * more than one snapshot in a sort of _continuous loading_ that updates the - * destination one step at a time.
- * Identifiers that entities originally had are not transferred to the target. - * Instead, the loader maps remote identifiers to local ones while restoring a - * snapshot.
- * An example of use is the implementation of a client-server applications with - * the requirement of transferring somehow parts of the representation side to - * side. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_continuous_loader { - using traits_type = entt_traits; - - void destroy(Entity entt) { - if(const auto it = remloc.find(entt); it == remloc.cend()) { - const auto local = reg->create(); - remloc.emplace(entt, std::make_pair(local, true)); - reg->destroy(local); - } - } - - void restore(Entity entt) { - const auto it = remloc.find(entt); - - if(it == remloc.cend()) { - const auto local = reg->create(); - remloc.emplace(entt, std::make_pair(local, true)); - } else { - if(!reg->valid(remloc[entt].first)) { - remloc[entt].first = reg->create(); - } - - // set the dirty flag - remloc[entt].second = true; - } - } - - template - auto update(int, Container &container) - -> decltype(typename Container::mapped_type{}, void()) { - // map like container - Container other; - - for(auto &&pair: container) { - using first_type = std::remove_const_t::first_type>; - using second_type = typename std::decay_t::second_type; - - if constexpr(std::is_same_v && std::is_same_v) { - other.emplace(map(pair.first), map(pair.second)); - } else if constexpr(std::is_same_v) { - other.emplace(map(pair.first), std::move(pair.second)); - } else { - static_assert(std::is_same_v, "Neither the key nor the value are of entity type"); - other.emplace(std::move(pair.first), map(pair.second)); - } - } - - std::swap(container, other); - } - - template - auto update(char, Container &container) - -> decltype(typename Container::value_type{}, void()) { - // vector like container - static_assert(std::is_same_v, "Invalid value type"); - - for(auto &&entt: container) { - entt = map(entt); - } - } - - template - void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type:: *member) { - if constexpr(!std::is_same_v) { - return; - } else if constexpr(std::is_same_v) { - instance.*member = map(instance.*member); - } else { - // maybe a container? let's try... - update(0, instance.*member); - } - } - - template - void remove_if_exists() { - for(auto &&ref: remloc) { - const auto local = ref.second.first; - - if(reg->valid(local)) { - reg->template remove_if_exists(local); - } - } - } - - template - void assign(Archive &archive, [[maybe_unused]] Member Type:: *... member) { - typename traits_type::entity_type length{}; - archive(length); - - entity_type entt{}; - - if constexpr(std::tuple_size_vtemplate view().get({}))> == 0) { - while(length--) { - archive(entt); - restore(entt); - reg->template emplace_or_replace(map(entt)); - } - } else { - Other instance{}; - - while(length--) { - archive(entt, instance); - (update(instance, member), ...); - restore(entt); - reg->template emplace_or_replace(map(entt), std::move(instance)); - } - } - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - - /** - * @brief Constructs an instance that is bound to a given registry. - * @param source A valid reference to a registry. - */ - basic_continuous_loader(basic_registry &source) ENTT_NOEXCEPT - : reg{&source} - {} - - /*! @brief Default move constructor. */ - basic_continuous_loader(basic_continuous_loader &&) = default; - - /*! @brief Default move assignment operator. @return This loader. */ - basic_continuous_loader & operator=(basic_continuous_loader &&) = default; - - /** - * @brief Restores entities that were in use during serialization. - * - * This function restores the entities that were in use during serialization - * and creates local counterparts for them if required. - * - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A non-const reference to this loader. - */ - template - basic_continuous_loader & entities(Archive &archive) { - typename traits_type::entity_type length{}; - entity_type entt{}; - - archive(length); - - for(decltype(length) pos{}; pos < length; ++pos) { - archive(entt); - - if(const auto entity = (to_integral(entt) & traits_type::entity_mask); entity == pos) { - restore(entt); - } else { - destroy(entt); - } - } - - // discards the head of the list of destroyed entities - archive(entt); - - return *this; - } - - /** - * @brief Restores components and assigns them to the right entities. - * - * The template parameter list must be exactly the same used during - * serialization. In the event that the entity to which the component is - * assigned doesn't exist yet, the loader will take care to create a local - * counterpart for it.
- * Members can be either data members of type entity_type or containers of - * entities. In both cases, the loader will visit them and update the - * entities by replacing each one with its local counterpart. - * - * @tparam Component Type of component to restore. - * @tparam Archive Type of input archive. - * @tparam Type Types of components to update with local counterparts. - * @tparam Member Types of members to update with their local counterparts. - * @param archive A valid reference to an input archive. - * @param member Members to update with their local counterparts. - * @return A non-const reference to this loader. - */ - template - basic_continuous_loader & component(Archive &archive, Member Type:: *... member) { - (remove_if_exists(), ...); - (assign(archive, member...), ...); - return *this; - } - - /** - * @brief Helps to purge entities that no longer have a conterpart. - * - * Users should invoke this member function after restoring each snapshot, - * unless they know exactly what they are doing. - * - * @return A non-const reference to this loader. - */ - basic_continuous_loader & shrink() { - auto it = remloc.begin(); - - while(it != remloc.cend()) { - const auto local = it->second.first; - bool &dirty = it->second.second; - - if(dirty) { - dirty = false; - ++it; - } else { - if(reg->valid(local)) { - reg->destroy(local); - } - - it = remloc.erase(it); - } - } - - return *this; - } - - /** - * @brief Destroys those entities that have no components. - * - * In case all the entities were serialized but only part of the components - * was saved, it could happen that some of the entities have no components - * once restored.
- * This functions helps to identify and destroy those entities. - * - * @return A non-const reference to this loader. - */ - basic_continuous_loader & orphans() { - reg->orphans([this](const auto entt) { - reg->destroy(entt); - }); - - return *this; - } - - /** - * @brief Tests if a loader knows about a given entity. - * @param entt An entity identifier. - * @return True if `entity` is managed by the loader, false otherwise. - */ - [[nodiscard]] bool contains(entity_type entt) const ENTT_NOEXCEPT { - return (remloc.find(entt) != remloc.cend()); - } - - /** - * @brief Returns the identifier to which an entity refers. - * @param entt An entity identifier. - * @return The local identifier if any, the null entity otherwise. - */ - [[nodiscard]] entity_type map(entity_type entt) const ENTT_NOEXCEPT { - const auto it = remloc.find(entt); - entity_type other = null; - - if(it != remloc.cend()) { - other = it->second.first; - } - - return other; - } - -private: - std::unordered_map> remloc; - basic_registry *reg; -}; - - -} - - -#endif - -// #include "entity/sparse_set.hpp" -#ifndef ENTT_ENTITY_SPARSE_SET_HPP -#define ENTT_ENTITY_SPARSE_SET_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Basic sparse set implementation. - * - * Sparse set or packed array or whatever is the name users give it.
- * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a - * _packed_ one; one used for direct access through contiguous memory, the other - * one used to get the data through an extra level of indirection.
- * This is largely used by the registry to offer users the fastest access ever - * to the components. Views and groups in general are almost entirely designed - * around sparse sets. - * - * This type of data structure is widely documented in the literature and on the - * web. This is nothing more than a customized implementation suitable for the - * purpose of the framework. - * - * @note - * Internal data structures arrange elements to maximize performance. There are - * no guarantees that entities are returned in the insertion order when iterate - * a sparse set. Do not make assumption on the order in any case. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class basic_sparse_set { - static constexpr auto page_size = ENTT_PAGE_SIZE; - - using traits_type = entt_traits; - using page_type = std::unique_ptr; - - class sparse_set_iterator final { - friend class basic_sparse_set; - - using packed_type = std::vector; - using index_type = typename traits_type::difference_type; - - sparse_set_iterator(const packed_type &ref, const index_type idx) ENTT_NOEXCEPT - : packed{&ref}, index{idx} - {} - - public: - using difference_type = index_type; - using value_type = Entity; - using pointer = const value_type *; - using reference = const value_type &; - using iterator_category = std::random_access_iterator_tag; - - sparse_set_iterator() ENTT_NOEXCEPT = default; - - sparse_set_iterator & operator++() ENTT_NOEXCEPT { - return --index, *this; - } - - sparse_set_iterator operator++(int) ENTT_NOEXCEPT { - iterator orig = *this; - return ++(*this), orig; - } - - sparse_set_iterator & operator--() ENTT_NOEXCEPT { - return ++index, *this; - } - - sparse_set_iterator operator--(int) ENTT_NOEXCEPT { - sparse_set_iterator orig = *this; - return operator--(), orig; - } - - sparse_set_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { - index -= value; - return *this; - } - - sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT { - sparse_set_iterator copy = *this; - return (copy += value); - } - - sparse_set_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { - return (*this += -value); - } - - sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT { - return (*this + -value); - } - - difference_type operator-(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return other.index - index; - } - - [[nodiscard]] reference operator[](const difference_type value) const { - const auto pos = size_type(index-value-1u); - return (*packed)[pos]; - } - - [[nodiscard]] bool operator==(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return other.index == index; - } - - [[nodiscard]] bool operator!=(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] bool operator<(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return index > other.index; - } - - [[nodiscard]] bool operator>(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return index < other.index; - } - - [[nodiscard]] bool operator<=(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return !(*this > other); - } - - [[nodiscard]] bool operator>=(const sparse_set_iterator &other) const ENTT_NOEXCEPT { - return !(*this < other); - } - - [[nodiscard]] pointer operator->() const { - const auto pos = size_type(index-1u); - return &(*packed)[pos]; - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - const packed_type *packed; - index_type index; - }; - - [[nodiscard]] auto page(const Entity entt) const ENTT_NOEXCEPT { - return size_type{(to_integral(entt) & traits_type::entity_mask) / page_size}; - } - - [[nodiscard]] auto offset(const Entity entt) const ENTT_NOEXCEPT { - return size_type{to_integral(entt) & (page_size - 1)}; - } - - [[nodiscard]] page_type & assure(const std::size_t pos) { - if(!(pos < sparse.size())) { - sparse.resize(pos+1); - } - - if(!sparse[pos]) { - sparse[pos].reset(new entity_type[page_size]); - // null is safe in all cases for our purposes - for(auto *first = sparse[pos].get(), *last = first + page_size; first != last; ++first) { - *first = null; - } - } - - return sparse[pos]; - } - -protected: - /*! @brief Swaps two entities in the internal packed array. */ - virtual void swap_at(const std::size_t, const std::size_t) {} - - /*! @brief Attempts to remove an entity from the internal packed array. */ - virtual void swap_and_pop(const std::size_t, void *) {} - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = sparse_set_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = const entity_type *; - - /*! @brief Default constructor. */ - basic_sparse_set() = default; - - /*! @brief Default move constructor. */ - basic_sparse_set(basic_sparse_set &&) = default; - - /*! @brief Default destructor. */ - virtual ~basic_sparse_set() = default; - - /*! @brief Default move assignment operator. @return This sparse set. */ - basic_sparse_set & operator=(basic_sparse_set &&) = default; - - /** - * @brief Increases the capacity of a sparse set. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @param cap Desired capacity. - */ - void reserve(const size_type cap) { - packed.reserve(cap); - } - - /** - * @brief Returns the number of elements that a sparse set has currently - * allocated space for. - * @return Capacity of the sparse set. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return packed.capacity(); - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - // conservative approach - if(packed.empty()) { - sparse.clear(); - } - - sparse.shrink_to_fit(); - packed.shrink_to_fit(); - } - - /** - * @brief Returns the extent of a sparse set. - * - * The extent of a sparse set is also the size of the internal sparse array. - * There is no guarantee that the internal packed array has the same size. - * Usually the size of the internal sparse array is equal or greater than - * the one of the internal packed array. - * - * @return Extent of the sparse set. - */ - [[nodiscard]] size_type extent() const ENTT_NOEXCEPT { - return sparse.size() * page_size; - } - - /** - * @brief Returns the number of elements in a sparse set. - * - * The number of elements is also the size of the internal packed array. - * There is no guarantee that the internal sparse array has the same size. - * Usually the size of the internal sparse array is equal or greater than - * the one of the internal packed array. - * - * @return Number of elements. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return packed.size(); - } - - /** - * @brief Checks whether a sparse set is empty. - * @return True if the sparse set is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return packed.empty(); - } - - /** - * @brief Direct access to the internal packed array. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @note - * Entities are in the reverse order as returned by the `begin`/`end` - * iterators. - * - * @return A pointer to the internal packed array. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return packed.data(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first entity of the internal packed - * array. If the sparse set is empty, the returned iterator will be equal to - * `end()`. - * - * @return An iterator to the first entity of the internal packed array. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = packed.size(); - return iterator{packed, pos}; - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last entity in - * the internal packed array. Attempting to dereference the returned - * iterator results in undefined behavior. - * - * @return An iterator to the element following the last entity of the - * internal packed array. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{packed, {}}; - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * The returned iterator points to the first entity of the reversed internal - * packed array. If the sparse set is empty, the returned iterator will be - * equal to `rend()`. - * - * @return An iterator to the first entity of the reversed internal packed - * array. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return packed.data(); - } - - /** - * @brief Returns a reverse iterator to the end. - * - * The returned iterator points to the element following the last entity in - * the reversed internal packed array. Attempting to dereference the - * returned iterator results in undefined behavior. - * - * @return An iterator to the element following the last entity of the - * reversed internal packed array. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return rbegin() + packed.size(); - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - return contains(entt) ? --(end() - index(entt)) : end(); - } - - /** - * @brief Checks if a sparse set contains an entity. - * @param entt A valid entity identifier. - * @return True if the sparse set contains the entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - const auto curr = page(entt); - // testing against null permits to avoid accessing the packed array - return (curr < sparse.size() && sparse[curr] && sparse[curr][offset(entt)] != null); - } - - /** - * @brief Returns the position of an entity in a sparse set. - * - * @warning - * Attempting to get the position of an entity that doesn't belong to the - * sparse set results in undefined behavior. - * - * @param entt A valid entity identifier. - * @return The position of the entity in the sparse set. - */ - [[nodiscard]] size_type index(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - return size_type{to_integral(sparse[page(entt)][offset(entt)])}; - } - - /** - * @brief Returns the entity at specified location, with bounds checking. - * @param pos The position for which to return the entity. - * @return The entity at specified location if any, a null entity otherwise. - */ - [[nodiscard]] entity_type at(const size_type pos) const { - return pos < packed.size() ? packed[pos] : null; - } - - /** - * @brief Returns the entity at specified location, without bounds checking. - * @param pos The position for which to return the entity. - * @return The entity at specified location. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - ENTT_ASSERT(pos < packed.size()); - return packed[pos]; - } - - /** - * @brief Assigns an entity to a sparse set. - * - * @warning - * Attempting to assign an entity that already belongs to the sparse set - * results in undefined behavior. - * - * @param entt A valid entity identifier. - */ - void emplace(const entity_type entt) { - ENTT_ASSERT(!contains(entt)); - assure(page(entt))[offset(entt)] = entity_type{static_cast(packed.size())}; - packed.push_back(entt); - } - - /** - * @brief Assigns one or more entities to a sparse set. - * - * @warning - * Attempting to assign an entity that already belongs to the sparse set - * results in undefined behavior. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void insert(It first, It last) { - auto next = static_cast(packed.size()); - packed.insert(packed.end(), first, last); - - for(; first != last; ++first) { - ENTT_ASSERT(!contains(*first)); - assure(page(*first))[offset(*first)] = entity_type{next++}; - } - } - - /** - * @brief Removes an entity from a sparse set. - * - * @warning - * Attempting to remove an entity that doesn't belong to the sparse set - * results in undefined behavior. - * - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void remove(const entity_type entt, void *ud = nullptr) { - ENTT_ASSERT(contains(entt)); - auto &ref = sparse[page(entt)][offset(entt)]; - - // last chance to use the entity for derived classes and mixins, if any - swap_and_pop(size_type{to_integral(ref)}, ud); - - const auto other = packed.back(); - sparse[page(other)][offset(other)] = ref; - // if it looks weird, imagine what the subtle bugs it prevents are - ENTT_ASSERT((packed.back() = entt, true)); - packed[size_type{to_integral(ref)}] = other; - ref = null; - - packed.pop_back(); - } - - /** - * @brief Removes multiple entities from a pool. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - template - void remove(It first, It last, void *ud = nullptr) { - for(; first != last; ++first) { - remove(*first, ud); - } - } - - /** - * @copybrief swap_at - * - * For what it's worth, this function affects both the internal sparse array - * and the internal packed array. Users should not care of that anyway. - * - * @warning - * Attempting to swap entities that don't belong to the sparse set results - * in undefined behavior. - * - * @param lhs A valid entity identifier. - * @param rhs A valid entity identifier. - */ - void swap(const entity_type lhs, const entity_type rhs) { - const auto from = index(lhs); - const auto to = index(rhs); - std::swap(sparse[page(lhs)][offset(lhs)], sparse[page(rhs)][offset(rhs)]); - std::swap(packed[from], packed[to]); - swap_at(from, to); - } - - /** - * @brief Sort the first count elements according to the given comparison - * function. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param count Number of elements to sort. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) { - ENTT_ASSERT(!(count > size())); - - algo(packed.rend() - count, packed.rend(), std::move(compare), std::forward(args)...); - - for(size_type pos{}; pos < count; ++pos) { - auto curr = pos; - auto next = index(packed[curr]); - - while(curr != next) { - const auto idx = index(packed[next]); - const auto entt = packed[curr]; - - swap_at(next, idx); - sparse[page(entt)][offset(entt)] = entity_type{static_cast(curr)}; - - curr = next; - next = idx; - } - } - } - - /** - * @brief Sort all elements according to the given comparison function. - * - * @sa sort_n - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - sort_n(size(), std::move(compare), std::move(algo), std::forward(args)...); - } - - /** - * @brief Sort entities according to their order in another sparse set. - * - * Entities that are part of both the sparse sets are ordered internally - * according to the order they have in `other`. All the other entities goes - * to the end of the list and there are no guarantees on their order.
- * In other terms, this function can be used to impose the same order on two - * sets by using one of them as a master and the other one as a slave. - * - * Iterating the sparse set with a couple of iterators returns elements in - * the expected order after a call to `respect`. See `begin` and `end` for - * more details. - * - * @param other The sparse sets that imposes the order of the entities. - */ - void respect(const basic_sparse_set &other) { - const auto to = other.end(); - auto from = other.begin(); - - size_type pos = packed.size() - 1; - - while(pos && from != to) { - if(contains(*from)) { - if(*from != packed[pos]) { - swap(packed[pos], *from); - } - - --pos; - } - - ++from; - } - } - - /** - * @brief Clears a sparse set. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void clear(void *ud = nullptr) ENTT_NOEXCEPT { - remove(begin(), end(), ud); - } - -private: - std::vector sparse; - std::vector packed; -}; - - -} - - -#endif - -// #include "entity/storage.hpp" -#ifndef ENTT_ENTITY_STORAGE_HPP -#define ENTT_ENTITY_STORAGE_HPP - - -#include -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "../core/type_traits.hpp" - -// #include "../signal/sigh.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "sparse_set.hpp" - - - -namespace entt { - - -/** - * @brief Basic storage implementation. - * - * This class is a refinement of a sparse set that associates an object to an - * entity. The main purpose of this class is to extend sparse sets to store - * components in a registry. It guarantees fast access both to the elements and - * to the entities. - * - * @note - * Entities and objects have the same order. It's guaranteed both in case of raw - * access (either to entities or objects) and when using random or input access - * iterators. - * - * @note - * Internal data structures arrange elements to maximize performance. There are - * no guarantees that objects are returned in the insertion order when iterate - * a storage. Do not make assumption on the order in any case. - * - * @warning - * Empty types aren't explicitly instantiated. Therefore, many of the functions - * normally available for non-empty types will not be available for empty ones. - * - * @sa sparse_set - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects assigned to the entities. - */ -template -class basic_storage: public basic_sparse_set { - static_assert(std::is_move_constructible_v && std::is_move_assignable_v, "The managed type must be at least move constructible and assignable"); - - using underlying_type = basic_sparse_set; - using traits_type = entt_traits; - - template - class storage_iterator final { - friend class basic_storage; - - using instance_type = constness_as_t, Value>; - using index_type = typename traits_type::difference_type; - - storage_iterator(instance_type &ref, const index_type idx) ENTT_NOEXCEPT - : instances{&ref}, index{idx} - {} - - public: - using difference_type = index_type; - using value_type = Value; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::random_access_iterator_tag; - - storage_iterator() ENTT_NOEXCEPT = default; - - storage_iterator & operator++() ENTT_NOEXCEPT { - return --index, *this; - } - - storage_iterator operator++(int) ENTT_NOEXCEPT { - storage_iterator orig = *this; - return ++(*this), orig; - } - - storage_iterator & operator--() ENTT_NOEXCEPT { - return ++index, *this; - } - - storage_iterator operator--(int) ENTT_NOEXCEPT { - storage_iterator orig = *this; - return operator--(), orig; - } - - storage_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { - index -= value; - return *this; - } - - storage_iterator operator+(const difference_type value) const ENTT_NOEXCEPT { - storage_iterator copy = *this; - return (copy += value); - } - - storage_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { - return (*this += -value); - } - - storage_iterator operator-(const difference_type value) const ENTT_NOEXCEPT { - return (*this + -value); - } - - difference_type operator-(const storage_iterator &other) const ENTT_NOEXCEPT { - return other.index - index; - } - - [[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT { - const auto pos = size_type(index-value-1); - return (*instances)[pos]; - } - - [[nodiscard]] bool operator==(const storage_iterator &other) const ENTT_NOEXCEPT { - return other.index == index; - } - - [[nodiscard]] bool operator!=(const storage_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] bool operator<(const storage_iterator &other) const ENTT_NOEXCEPT { - return index > other.index; - } - - [[nodiscard]] bool operator>(const storage_iterator &other) const ENTT_NOEXCEPT { - return index < other.index; - } - - [[nodiscard]] bool operator<=(const storage_iterator &other) const ENTT_NOEXCEPT { - return !(*this > other); - } - - [[nodiscard]] bool operator>=(const storage_iterator &other) const ENTT_NOEXCEPT { - return !(*this < other); - } - - [[nodiscard]] pointer operator->() const ENTT_NOEXCEPT { - const auto pos = size_type(index-1u); - return &(*instances)[pos]; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return *operator->(); - } - - private: - instance_type *instances; - index_type index; - }; - -protected: - /** - * @copybrief basic_sparse_set::swap_at - * @param lhs A valid position of an entity within storage. - * @param rhs A valid position of an entity within storage. - */ - void swap_at(const std::size_t lhs, const std::size_t rhs) { - std::swap(instances[lhs], instances[rhs]); - } - - /** - * @copybrief basic_sparse_set::swap_and_pop - * @param pos A valid position of an entity within storage. - */ - void swap_and_pop(const std::size_t pos, void *) { - auto other = std::move(instances.back()); - instances[pos] = std::move(other); - instances.pop_back(); - } - -public: - /*! @brief Type of the objects assigned to entities. */ - using value_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = storage_iterator; - /*! @brief Constant random access iterator type. */ - using const_iterator = storage_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = Type *; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = const Type *; - - /** - * @brief Increases the capacity of a storage. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @param cap Desired capacity. - */ - void reserve(const size_type cap) { - underlying_type::reserve(cap); - instances.reserve(cap); - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - underlying_type::shrink_to_fit(); - instances.shrink_to_fit(); - } - - /** - * @brief Direct access to the array of objects. - * - * The returned pointer is such that range `[raw(), raw() + size())` is - * always a valid range, even if the container is empty. - * - * @note - * Objects are in the reverse order as returned by the `begin`/`end` - * iterators. - * - * @return A pointer to the array of objects. - */ - [[nodiscard]] const value_type * raw() const ENTT_NOEXCEPT { - return instances.data(); - } - - /*! @copydoc raw */ - [[nodiscard]] value_type * raw() ENTT_NOEXCEPT { - return const_cast(std::as_const(*this).raw()); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first instance of the internal array. - * If the storage is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first instance of the internal array. - */ - [[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = underlying_type::size(); - return const_iterator{instances, pos}; - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = underlying_type::size(); - return iterator{instances, pos}; - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last instance - * of the internal array. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the element following the last instance of the - * internal array. - */ - [[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT { - return const_iterator{instances, {}}; - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const ENTT_NOEXCEPT { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() ENTT_NOEXCEPT { - return iterator{instances, {}}; - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * The returned iterator points to the first instance of the reversed - * internal array. If the storage is empty, the returned iterator will be - * equal to `rend()`. - * - * @return An iterator to the first instance of the reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crbegin() const ENTT_NOEXCEPT { - return instances.data(); - } - - /*! @copydoc crbegin */ - [[nodiscard]] const_reverse_iterator rbegin() const ENTT_NOEXCEPT { - return crbegin(); - } - - /*! @copydoc rbegin */ - [[nodiscard]] reverse_iterator rbegin() ENTT_NOEXCEPT { - return instances.data(); - } - - /** - * @brief Returns a reverse iterator to the end. - * - * The returned iterator points to the element following the last instance - * of the reversed internal array. Attempting to dereference the returned - * iterator results in undefined behavior. - * - * @return An iterator to the element following the last instance of the - * reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crend() const ENTT_NOEXCEPT { - return crbegin() + instances.size(); - } - - /*! @copydoc crend */ - [[nodiscard]] const_reverse_iterator rend() const ENTT_NOEXCEPT { - return crend(); - } - - /*! @copydoc rend */ - [[nodiscard]] reverse_iterator rend() ENTT_NOEXCEPT { - return rbegin() + instances.size(); - } - - /** - * @brief Returns the object assigned to an entity. - * - * @warning - * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. - * - * @param entt A valid entity identifier. - * @return The object assigned to the entity. - */ - [[nodiscard]] const value_type & get(const entity_type entt) const { - return instances[underlying_type::index(entt)]; - } - - /*! @copydoc get */ - [[nodiscard]] value_type & get(const entity_type entt) { - return const_cast(std::as_const(*this).get(entt)); - } - - /** - * @brief Assigns an entity to a storage and constructs its object. - * - * This version accept both types that can be constructed in place directly - * and types like aggregates that do not work well with a placement new as - * performed usually under the hood during an _emplace back_. - * - * @warning - * Attempting to use an entity that already belongs to the storage results - * in undefined behavior. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entt A valid entity identifier. - * @param args Parameters to use to construct an object for the entity. - * @return A reference to the newly created object. - */ - template - value_type & emplace(const entity_type entt, Args &&... args) { - if constexpr(std::is_aggregate_v) { - instances.push_back(Type{std::forward(args)...}); - } else { - instances.emplace_back(std::forward(args)...); - } - - // entity goes after component in case constructor throws - underlying_type::emplace(entt); - return instances.back(); - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the updated instance. - */ - template - decltype(auto) patch(const entity_type entity, Func &&... func) { - auto &&instance = instances[this->index(entity)]; - (std::forward(func)(instance), ...); - return instance; - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given instance. - * - * @warning - * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param value An instance of the object to construct. - */ - template - void insert(It first, It last, const value_type &value = {}) { - instances.insert(instances.end(), std::distance(first, last), value); - // entities go after components in case constructors throw - underlying_type::insert(first, last); - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given range. - * - * @sa construct - * - * @tparam EIt Type of input iterator. - * @tparam CIt Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param from An iterator to the first element of the range of objects. - * @param to An iterator past the last element of the range of objects. - */ - template - void insert(EIt first, EIt last, CIt from, CIt to) { - instances.insert(instances.end(), from, to); - // entities go after components in case constructors throw - underlying_type::insert(first, last); - } - - /** - * @brief Sort elements according to the given comparison function. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * bool(const Type &, const Type &); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @warning - * Empty types are never instantiated. Therefore, only comparison function - * objects that require to return entities rather than components are - * accepted. - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param count Number of elements to sort. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) { - if constexpr(std::is_invocable_v) { - underlying_type::sort_n(count, [this, compare = std::move(compare)](const auto lhs, const auto rhs) { - return compare(std::as_const(instances[underlying_type::index(lhs)]), std::as_const(instances[underlying_type::index(rhs)])); - }, std::move(algo), std::forward(args)...); - } else { - underlying_type::sort_n(count, std::move(compare), std::move(algo), std::forward(args)...); - } - } - - /** - * @brief Sort all elements according to the given comparison function. - * - * @sa sort_n - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - sort_n(this->size(), std::move(compare), std::move(algo), std::forward(args)...); - } - -private: - std::vector instances; -}; - - -/*! @copydoc basic_storage */ -template -class basic_storage>>: public basic_sparse_set { - using underlying_type = basic_sparse_set; - -public: - /*! @brief Type of the objects assigned to entities. */ - using value_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - - /** - * @brief Fake get function. - * - * @warning - * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. - * - * @param entt A valid entity identifier. - */ - void get([[maybe_unused]] const entity_type entt) const { - ENTT_ASSERT(this->contains(entt)); - } - - /** - * @brief Assigns an entity to a storage and constructs its object. - * - * @warning - * Attempting to use an entity that already belongs to the storage results - * in undefined behavior. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entt A valid entity identifier. - * @param args Parameters to use to construct an object for the entity. - */ - template - void emplace(const entity_type entt, Args &&... args) { - [[maybe_unused]] value_type instance{std::forward(args)...}; - underlying_type::emplace(entt); - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - */ - template - void patch([[maybe_unused]] const entity_type entity, Func &&... func) { - ENTT_ASSERT(this->contains(entity)); - (std::forward(func)(), ...); - } - - /** - * @brief Assigns one or more entities to a storage. - * - * @warning - * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void insert(It first, It last, const value_type & = {}) { - underlying_type::insert(first, last); - } -}; - - -/** - * @brief Mixin type to use to wrap basic storage classes. - * @tparam Type The type of the underlying storage. - */ -template -struct storage_adapter_mixin: Type { - static_assert(std::is_same_v>, "Invalid object type"); - - /*! @brief Type of the objects assigned to entities. */ - using value_type = typename Type::value_type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename Type::entity_type; - - /** - * @brief Assigns entities to a storage. - * @tparam Args Types of arguments to use to construct the object. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the object. - * @return A reference to the newly created object. - */ - template - decltype(auto) emplace(basic_registry &, const entity_type entity, Args &&... args) { - return Type::emplace(entity, std::forward(args)...); - } - - /** - * @brief Assigns entities to a storage. - * @tparam It Type of input iterator. - * @tparam Args Types of arguments to use to construct the objects assigned - * to the entities. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param args Parameters to use to initialize the objects assigned to the - * entities. - */ - template - void insert(basic_registry &, It first, It last, Args &&... args) { - Type::insert(first, last, std::forward(args)...); - } - - /** - * @brief Patches the given instance for an entity. - * @tparam Func Types of the function objects to invoke. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the patched instance. - */ - template - decltype(auto) patch(basic_registry &, const entity_type entity, Func &&... func) { - return Type::patch(entity, std::forward(func)...); - } -}; - - -/** - * @brief Mixin type to use to add signal support to storage types. - * @tparam Type The type of the underlying storage. - */ -template -class sigh_storage_mixin final: public Type { - /** - * @copybrief basic_sparse_set::swap_and_pop - * @param pos A valid position of an entity within storage. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void swap_and_pop(const std::size_t pos, void *ud) final { - ENTT_ASSERT(ud != nullptr); - const auto entity = basic_sparse_set::operator[](pos); - destruction.publish(*static_cast *>(ud), entity); - // the position may have changed due to the actions of a listener - Type::swap_and_pop(this->index(entity), ud); - } - -public: - /*! @brief Underlying value type. */ - using value_type = typename Type::value_type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename Type::entity_type; - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever a new instance is created and assigned to an entity.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, entity_type); - * @endcode - * - * Listeners are invoked **after** the object has been assigned to the - * entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_construct() ENTT_NOEXCEPT { - return sink{construction}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is explicitly updated.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, entity_type); - * @endcode - * - * Listeners are invoked **after** the object has been updated. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_update() ENTT_NOEXCEPT { - return sink{update}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is removed from an entity and thus destroyed.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, entity_type); - * @endcode - * - * Listeners are invoked **before** the object has been removed from the - * entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_destroy() ENTT_NOEXCEPT { - return sink{destruction}; - } - - /** - * @brief Assigns entities to a storage. - * @tparam Args Types of arguments to use to construct the object. - * @param owner The registry that issued the request. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the object. - * @return A reference to the newly created object. - */ - template - decltype(auto) emplace(basic_registry &owner, const entity_type entity, Args &&... args) { - Type::emplace(entity, std::forward(args)...); - construction.publish(owner, entity); - return this->get(entity); - } - - /** - * @brief Assigns entities to a storage. - * @tparam It Type of input iterator. - * @tparam Args Types of arguments to use to construct the objects assigned - * to the entities. - * @param owner The registry that issued the request. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param args Parameters to use to initialize the objects assigned to the - * entities. - */ - template - void insert(basic_registry &owner, It first, It last, Args &&... args) { - Type::insert(first, last, std::forward(args)...); - - if(!construction.empty()) { - for(; first != last; ++first) { - construction.publish(owner, *first); - } - } - } - - /** - * @brief Patches the given instance for an entity. - * @tparam Func Types of the function objects to invoke. - * @param owner The registry that issued the request. - * @param entity A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the patched instance. - */ - template - decltype(auto) patch(basic_registry &owner, const entity_type entity, Func &&... func) { - Type::patch(entity, std::forward(func)...); - update.publish(owner, entity); - return this->get(entity); - } - -private: - sigh &, const entity_type)> construction{}; - sigh &, const entity_type)> destruction{}; - sigh &, const entity_type)> update{}; -}; - - -/** - * @brief Defines the component-to-storage conversion. - * - * Formally: - * - * * If the component type is a non-const one, the member typedef type is the - * declared storage type. - * * If the component type is a const one, the member typedef type is the - * declared storage type, except it has a const-qualifier added. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects assigned to the entities. - */ -template -struct storage_traits { - /*! @brief Resulting type after component-to-storage conversion. */ - using storage_type = sigh_storage_mixin>; -}; - - -/** - * @brief Gets the element assigned to an entity from a storage, if any. - * @tparam Type Storage type. - * @param container A valid instance of a storage class. - * @param entity A valid entity identifier. - * @return A possibly empty tuple containing the requested element. - */ -template -[[nodiscard]] auto get_as_tuple([[maybe_unused]] Type &container, [[maybe_unused]] const typename Type::entity_type entity) { - static_assert(std::is_same_v, typename storage_traits::storage_type>, "Invalid storage"); - - if constexpr(std::is_void_v) { - return std::make_tuple(); - } else { - return std::forward_as_tuple(container.get(entity)); - } -} - - -} - - -#endif - -// #include "entity/utility.hpp" -#ifndef ENTT_ENTITY_UTILITY_HPP -#define ENTT_ENTITY_UTILITY_HPP - - -// #include "../core/type_traits.hpp" - - - -namespace entt { - - -/** - * @brief Alias for exclusion lists. - * @tparam Type List of types. - */ -template -struct exclude_t: type_list {}; - - -/** - * @brief Variable template for exclusion lists. - * @tparam Type List of types. - */ -template -inline constexpr exclude_t exclude{}; - - -/** - * @brief Alias for lists of observed components. - * @tparam Type List of types. - */ -template -struct get_t: type_list{}; - - -/** - * @brief Variable template for lists of observed components. - * @tparam Type List of types. - */ -template -inline constexpr get_t get{}; - - -} - - -#endif - -// #include "entity/view.hpp" -#ifndef ENTT_ENTITY_VIEW_HPP -#define ENTT_ENTITY_VIEW_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "sparse_set.hpp" - -// #include "storage.hpp" - -// #include "utility.hpp" - - - -namespace entt { - - -/** - * @brief View. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class basic_view; - - -/** - * @brief Multi component view. - * - * Multi component views iterate over those entities that have at least all the - * given components in their bags. During initialization, a multi component view - * looks at the number of entities available for each component and uses the - * smallest set in order to get a performance boost when iterate. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the view in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Views share references to the underlying data structures of the registry that - * generated them. Therefore any change to the entities and to the components - * made by means of the registry are immediately reflected by views. - * - * @warning - * Lifetime of a view must not overcome that of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Exclude Types of components used to filter the view. - * @tparam Component Types of components iterated by the view. - */ -template -class basic_view, Component...> final { - template - using storage_type = constness_as_t>::storage_type, Comp>; - - using unchecked_type = std::array *, (sizeof...(Component) - 1)>; - - template - class view_iterator final { - friend class basic_view, Component...>; - - view_iterator(It from, It to, It curr, unchecked_type other, const std::tuple *...> &ignore) ENTT_NOEXCEPT - : first{from}, - last{to}, - it{curr}, - unchecked{other}, - filter{ignore} - { - if(it != last && !valid()) { - ++(*this); - } - } - - [[nodiscard]] bool valid() const { - const auto entt = *it; - - return std::all_of(unchecked.cbegin(), unchecked.cend(), [entt](const basic_sparse_set *curr) { return curr->contains(entt); }) - && !(std::get *>(filter)->contains(entt) || ...); - } - - public: - using difference_type = typename std::iterator_traits::difference_type; - using value_type = typename std::iterator_traits::value_type; - using pointer = typename std::iterator_traits::pointer; - using reference = typename std::iterator_traits::reference; - using iterator_category = std::bidirectional_iterator_tag; - - view_iterator() ENTT_NOEXCEPT - : view_iterator{{}, {}, {}, {}, {}} - {} - - view_iterator & operator++() ENTT_NOEXCEPT { - while(++it != last && !valid()); - return *this; - } - - view_iterator operator++(int) ENTT_NOEXCEPT { - view_iterator orig = *this; - return ++(*this), orig; - } - - view_iterator & operator--() ENTT_NOEXCEPT { - while(--it != first && !valid()); - return *this; - } - - view_iterator operator--(int) ENTT_NOEXCEPT { - view_iterator orig = *this; - return operator--(), orig; - } - - [[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - [[nodiscard]] pointer operator->() const { - return &*it; - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - It first; - It last; - It it; - unchecked_type unchecked; - std::tuple *...> filter; - }; - - class iterable_view final { - friend class basic_view, Component...>; - - template - class iterable_view_iterator final { - friend class iterable_view; - - iterable_view_iterator(It from, const basic_view *parent) ENTT_NOEXCEPT - : it{from}, - view{parent} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_view_iterator & operator++() ENTT_NOEXCEPT { - return ++it, *this; - } - - iterable_view_iterator operator++(int) ENTT_NOEXCEPT { - iterable_view_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat(std::make_tuple(*it), view->get(*it)); - } - - [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - const basic_view *view; - }; - - iterable_view(const basic_view &parent) - : view{parent} - {} - - public: - using iterator = iterable_view_iterator::iterator>>; - using reverse_iterator = iterable_view_iterator::reverse_iterator>>; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return { view.begin(), &view }; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return { view.end(), &view }; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return { view.rbegin(), &view }; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return { view.rend(), &view }; - } - - private: - const basic_view view; - }; - - [[nodiscard]] const basic_sparse_set * candidate() const ENTT_NOEXCEPT { - return (std::min)({ static_cast *>(std::get *>(pools))... }, [](const auto *lhs, const auto *rhs) { - return lhs->size() < rhs->size(); - }); - } - - [[nodiscard]] unchecked_type unchecked(const basic_sparse_set *cpool) const { - std::size_t pos{}; - unchecked_type other{}; - (static_cast(std::get *>(pools) == cpool ? void() : void(other[pos++] = std::get *>(pools))), ...); - return other; - } - - template - [[nodiscard]] auto dispatch_get([[maybe_unused]] It &it, [[maybe_unused]] const Entity entt) const { - if constexpr(std::is_same_v::value_type, typename storage_type::value_type>) { - return std::forward_as_tuple(*it); - } else { - return get_as_tuple(*std::get *>(pools), entt); - } - } - - template - void traverse(Func func) const { - if constexpr(std::is_void_v *>(pools)->get({}))>) { - for(const auto entt: static_cast &>(*std::get *>(pools))) { - if(((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && !(std::get *>(filter)->contains(entt) || ...)) - { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); - } else { - std::apply(func, get(entt)); - } - } - } - } else { - auto it = std::get *>(pools)->begin(); - - for(const auto entt: static_cast &>(*std::get *>(pools))) { - if(((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && !(std::get *>(filter)->contains(entt) || ...)) - { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get(it, entt)...)); - } else { - std::apply(func, std::tuple_cat(dispatch_get(it, entt)...)); - } - } - - ++it; - } - } - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Bidirectional iterator type. */ - using iterator = view_iterator::iterator>; - /*! @brief Reverse iterator type. */ - using reverse_iterator = view_iterator::reverse_iterator>; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view() ENTT_NOEXCEPT - : view{} - {} - - /** - * @brief Constructs a multi-type view from a set of storage classes. - * @param component The storage for the types to iterate. - * @param epool The storage for the types used to filter the view. - */ - basic_view(storage_type &... component, const storage_type &... epool) ENTT_NOEXCEPT - : pools{&component...}, - filter{&epool...}, - view{candidate()} - {} - - /** - * @brief Forces the type to use to drive iterations. - * @tparam Comp Type of component to use to drive the iteration. - */ - template - void use() const ENTT_NOEXCEPT { - view = std::get *>(pools); - } - - /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. - */ - [[nodiscard]] size_type size_hint() const ENTT_NOEXCEPT { - return view->size(); - } - - /** - * @brief Returns an iterator to the first entity of the view. - * - * The returned iterator points to the first entity of the view. If the view - * is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the view. - */ - [[nodiscard]] iterator begin() const { - return iterator{view->begin(), view->end(), view->begin(), unchecked(view), filter}; - } - - /** - * @brief Returns an iterator that is past the last entity of the view. - * - * The returned iterator points to the entity following the last entity of - * the view. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the view. - */ - [[nodiscard]] iterator end() const { - return iterator{view->begin(), view->end(), view->end(), unchecked(view), filter}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed view. - * - * The returned iterator points to the first entity of the reversed view. If - * the view is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed view. - */ - [[nodiscard]] reverse_iterator rbegin() const { - return reverse_iterator{view->rbegin(), view->rend(), view->rbegin(), unchecked(view), filter}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * view. - * - * The returned iterator points to the entity following the last entity of - * the reversed view. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed view. - */ - [[nodiscard]] reverse_iterator rend() const { - return reverse_iterator{view->rbegin(), view->rend(), view->rend(), unchecked(view), filter}; - } - - /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the view, if any. - * @return The last entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = iterator{view->begin(), view->end(), view->find(entt), unchecked(view), filter}; - return (it != end() && *it == entt) ? it : end(); - } - - /** - * @brief Checks if a view is properly initialized. - * @return True if the view is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return view != nullptr; - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return (std::get *>(pools)->contains(entt) && ...) && !(std::get *>(filter)->contains(entt) || ...); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior. - * - * @tparam Comp Types of components to get. - * @param entt A valid entity identifier. - * @return The components assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Comp) == 0) { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } else if constexpr(sizeof...(Comp) == 1) { - return (std::get *>(pools)->get(entt), ...); - } else { - return std::tuple_cat(get_as_tuple(*std::get *>(pools), entt)...); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty components. The - * _constness_ of the components is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - ((std::get *>(pools) == view ? traverse(std::move(func)) : void()), ...); - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The pool of the suggested component is used to lead the iterations. The - * returned entities will therefore respect the order of the pool associated - * with that type.
- * It is no longer guaranteed that the performance is the best possible, but - * there will be greater control over the order of iteration. - * - * @sa each - * - * @tparam Comp Type of component to use to drive the iteration. - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - use(); - traverse(std::move(func)); - } - - /** - * @brief Returns an iterable object to use to _visit_ the view. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty components. The _constness_ of the - * components is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the view. - */ - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - return iterable_view{*this}; - } - - /** - * @brief Returns an iterable object to use to _visit_ the view. - * - * The pool of the suggested component is used to lead the iterations. The - * returned elements will therefore respect the order of the pool associated - * with that type.
- * It is no longer guaranteed that the performance is the best possible, but - * there will be greater control over the order of iteration. - * - * @sa each - * - * @tparam Comp Type of component to use to drive the iteration. - * @return An iterable object to use to _visit_ the view. - */ - template - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - use(); - return iterable_view{*this}; - } - - /** - * @brief Combines two views in a _more specific_ one (friend function). - * @tparam Id A valid entity type (see entt_traits for more details). - * @tparam ELhs Filter list of the first view. - * @tparam CLhs Component list of the first view. - * @tparam ERhs Filter list of the second view. - * @tparam CRhs Component list of the second view. - * @return A more specific view. - */ - template - friend auto operator|(const basic_view, CLhs...> &, const basic_view, CRhs...> &); - -private: - const std::tuple *...> pools; - const std::tuple *...> filter; - mutable const basic_sparse_set *view; -}; - - -/** - * @brief Single component view specialization. - * - * Single component views are specialized in order to get a boost in terms of - * performance. This kind of views can access the underlying data structure - * directly and avoid superfluous checks. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given component are created and assigned to entities. - * * The entity currently pointed is modified (as an example, the given - * component is removed from the entity to which the iterator points). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pool iterated by the view in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Views share a reference to the underlying data structure of the registry that - * generated them. Therefore any change to the entities and to the components - * made by means of the registry are immediately reflected by views. - * - * @warning - * Lifetime of a view must not overcome that of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Type of component iterated by the view. - */ -template -class basic_view, Component> final { - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable_view { - friend class basic_view, Component>; - - template - class iterable_view_iterator { - friend class iterable_view; - - template - iterable_view_iterator(It... from, Discard...) ENTT_NOEXCEPT - : it{from...} - {} - - public: - using difference_type = std::ptrdiff_t; - using value_type = decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))); - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - - iterable_view_iterator & operator++() ENTT_NOEXCEPT { - return (++std::get(it), ...), *this; - } - - iterable_view_iterator operator++(int) ENTT_NOEXCEPT { - iterable_view_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return { *std::get(it)... }; - } - - [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return std::get<0>(other.it) == std::get<0>(it); - } - - [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - std::tuple it; - }; - - iterable_view(storage_type &ref) - : pool{&ref} - {} - - public: - using iterator = std::conditional_t< - std::is_void_v().get({}))>, - iterable_view_iterator::iterator>, - iterable_view_iterator::iterator, decltype(std::declval().begin())> - >; - using reverse_iterator = std::conditional_t< - std::is_void_v().get({}))>, - iterable_view_iterator::reverse_iterator>, - iterable_view_iterator::reverse_iterator, decltype(std::declval().rbegin())> - >; - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return iterator{pool->basic_sparse_set::begin(), pool->begin()}; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{pool->basic_sparse_set::end(), pool->end()}; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return reverse_iterator{pool->basic_sparse_set::rbegin(), pool->rbegin()}; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return reverse_iterator{pool->basic_sparse_set::rend(), pool->rend()}; - } - - private: - storage_type * const pool; - }; - -public: - /*! @brief Type of component iterated by the view. */ - using raw_type = Component; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Random access iterator type. */ - using iterator = typename basic_sparse_set::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_sparse_set::reverse_iterator; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view() ENTT_NOEXCEPT - : pools{}, - filter{} - {} - - /** - * @brief Constructs a single-type view from a storage class. - * @param ref The storage for the type to iterate. - */ - basic_view(storage_type &ref) ENTT_NOEXCEPT - : pools{&ref}, - filter{} - {} - - /** - * @brief Returns the number of entities that have the given component. - * @return Number of entities that have the given component. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return std::get<0>(pools)->size(); - } - - /** - * @brief Checks whether a view is empty. - * @return True if the view is empty, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return std::get<0>(pools)->empty(); - } - - /** - * @brief Direct access to the list of components. - * - * The returned pointer is such that range `[raw(), raw() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of components. - */ - [[nodiscard]] raw_type * raw() const ENTT_NOEXCEPT { - return std::get<0>(pools)->raw(); - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size())` is - * always a valid range, even if the container is empty. - * - * @return A pointer to the array of entities. - */ - [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT { - return std::get<0>(pools)->data(); - } - - /** - * @brief Returns an iterator to the first entity of the view. - * - * The returned iterator points to the first entity of the view. If the view - * is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the view. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::begin(); - } - - /** - * @brief Returns an iterator that is past the last entity of the view. - * - * The returned iterator points to the entity following the last entity of - * the view. Attempting to dereference the returned iterator results in - * undefined behavior. - * - * @return An iterator to the entity following the last entity of the view. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::end(); - } - - /** - * @brief Returns an iterator to the first entity of the reversed view. - * - * The returned iterator points to the first entity of the reversed view. If - * the view is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed view. - */ - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::rbegin(); - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * view. - * - * The returned iterator points to the entity following the last entity of - * the reversed view. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @return An iterator to the entity following the last entity of the - * reversed view. - */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_sparse_set::rend(); - } - - /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the view, if any. - * @return The last entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid entity identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const { - const auto it = std::get<0>(pools)->find(entt); - return it != end() && *it == entt ? it : end(); - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[pos]; - } - - /** - * @brief Checks if a view is properly initialized. - * @return True if the view is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return std::get<0>(pools) != nullptr; - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return std::get<0>(pools)->contains(entt); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `registry::get` during iterations. It has - * far better performance than its counterpart. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior. - * - * @tparam Comp Types of components to get. - * @param entt A valid entity identifier. - * @return The component assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - ENTT_ASSERT(contains(entt)); - - if constexpr(sizeof...(Comp) == 0) { - return get_as_tuple(*std::get<0>(pools), entt); - } else { - static_assert(std::is_same_v, "Invalid component type"); - return std::get<0>(pools)->get(entt); - } - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a reference to the component if it's a non-empty one. - * The _constness_ of the component is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Component &); - * void(Component &); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - if constexpr(std::is_void_v(pools)->get({}))>) { - if constexpr(std::is_invocable_v) { - for(auto pos = size(); pos; --pos) { - func(); - } - } else { - for(auto entity: *this) { - func(entity); - } - } - } else { - if constexpr(is_applicable_v) { - for(const auto pack: each()) { - std::apply(func, pack); - } - } else { - for(auto &&component: *std::get<0>(pools)) { - func(component); - } - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ the view. - * - * The iterable object returns tuples that contain the current entity and a - * reference to its component if it's a non-empty one. The _constness_ of - * the component is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the view. - */ - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - return iterable_view{*std::get<0>(pools)}; - } - - /** - * @brief Combines two views in a _more specific_ one (friend function). - * @tparam Id A valid entity type (see entt_traits for more details). - * @tparam ELhs Filter list of the first view. - * @tparam CLhs Component list of the first view. - * @tparam ERhs Filter list of the second view. - * @tparam CRhs Component list of the second view. - * @return A more specific view. - */ - template - friend auto operator|(const basic_view, CLhs...> &, const basic_view, CRhs...> &); - -private: - const std::tuple pools; - const std::tuple<> filter; -}; - - -/** - * @brief Deduction guide. - * @tparam Storage Type of storage classes used to create the view. - * @param storage The storage for the types to iterate. - */ -template -basic_view(Storage &... storage) --> basic_view, entt::exclude_t<>, constness_as_t...>; - - -/** - * @brief Combines two views in a _more specific_ one. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam ELhs Filter list of the first view. - * @tparam CLhs Component list of the first view. - * @tparam ERhs Filter list of the second view. - * @tparam CRhs Component list of the second view. - * @param lhs A valid reference to the first view. - * @param rhs A valid reference to the second view. - * @return A more specific view. - */ -template -[[nodiscard]] auto operator|(const basic_view, CLhs...> &lhs, const basic_view, CRhs...> &rhs) { - using view_type = basic_view, CLhs..., CRhs...>; - return std::apply([](auto *... storage) { return view_type{*storage...}; }, std::tuple_cat(lhs.pools, rhs.pools, lhs.filter, rhs.filter)); -} - - -} - - -#endif - -// #include "locator/locator.hpp" -#ifndef ENTT_LOCATOR_LOCATOR_HPP -#define ENTT_LOCATOR_LOCATOR_HPP - - -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - - - -namespace entt { - - -/** - * @brief Service locator, nothing more. - * - * A service locator can be used to do what it promises: locate services.
- * Usually service locators are tightly bound to the services they expose and - * thus it's hard to define a general purpose class to do that. This template - * based implementation tries to fill the gap and to get rid of the burden of - * defining a different specific locator for each application. - * - * @tparam Service Type of service managed by the locator. - */ -template -struct service_locator { - /*! @brief Type of service offered. */ - using service_type = Service; - - /*! @brief Default constructor, deleted on purpose. */ - service_locator() = delete; - /*! @brief Default destructor, deleted on purpose. */ - ~service_locator() = delete; - - /** - * @brief Tests if a valid service implementation is set. - * @return True if the service is set, false otherwise. - */ - [[nodiscard]] static bool empty() ENTT_NOEXCEPT { - return !static_cast(service); - } - - /** - * @brief Returns a weak pointer to a service implementation, if any. - * - * Clients of a service shouldn't retain references to it. The recommended - * way is to retrieve the service implementation currently set each and - * every time the need of using it arises. Otherwise users can incur in - * unexpected behaviors. - * - * @return A reference to the service implementation currently set, if any. - */ - [[nodiscard]] static std::weak_ptr get() ENTT_NOEXCEPT { - return service; - } - - /** - * @brief Returns a weak reference to a service implementation, if any. - * - * Clients of a service shouldn't retain references to it. The recommended - * way is to retrieve the service implementation currently set each and - * every time the need of using it arises. Otherwise users can incur in - * unexpected behaviors. - * - * @warning - * In case no service implementation has been set, a call to this function - * results in undefined behavior. - * - * @return A reference to the service implementation currently set, if any. - */ - [[nodiscard]] static Service & ref() ENTT_NOEXCEPT { - return *service; - } - - /** - * @brief Sets or replaces a service. - * @tparam Impl Type of the new service to use. - * @tparam Args Types of arguments to use to construct the service. - * @param args Parameters to use to construct the service. - */ - template - static void set(Args &&... args) { - service = std::make_shared(std::forward(args)...); - } - - /** - * @brief Sets or replaces a service. - * @param ptr Service to use to replace the current one. - */ - static void set(std::shared_ptr ptr) { - ENTT_ASSERT(static_cast(ptr)); - service = std::move(ptr); - } - - /** - * @brief Resets a service. - * - * The service is no longer valid after a reset. - */ - static void reset() { - service.reset(); - } - -private: - inline static std::shared_ptr service = nullptr; -}; - - -} - - -#endif - -// #include "meta/adl_pointer.hpp" -#ifndef ENTT_META_ADL_POINTER_HPP -#define ENTT_META_ADL_POINTER_HPP - - -namespace entt { - - -/** - * @brief ADL based lookup function for dereferencing meta pointer-like types. - * @tparam Type Element type. - * @param value A pointer-like object. - * @return The value returned from the dereferenced pointer. - */ -template -decltype(auto) dereference_meta_pointer_like(const Type &value) { - return *value; -} - - -/** - * @brief Fake ADL based lookup function for meta pointer-like types. - * @tparam Type Element type. - */ -template -struct adl_meta_pointer_like { - /** - * @brief Uses the default ADL based lookup method to resolve the call. - * @param value A pointer-like object. - * @return The value returned from the dereferenced pointer. - */ - static decltype(auto) dereference(const Type &value) { - return dereference_meta_pointer_like(value); - } -}; - - -} - - -#endif - -// #include "meta/container.hpp" -#ifndef ENTT_META_CONTAINER_HPP -#define ENTT_META_CONTAINER_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "../core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - -// #include "type_traits.hpp" -#ifndef ENTT_META_TYPE_TRAITS_HPP -#define ENTT_META_TYPE_TRAITS_HPP - - -#include - - -namespace entt { - - -/** - * @brief Traits class template to be specialized to enable support for meta - * template information. - */ -template -struct meta_template_traits; - - -/** - * @brief Traits class template to be specialized to enable support for meta - * sequence containers. - */ -template -struct meta_sequence_container_traits; - - -/** - * @brief Traits class template to be specialized to enable support for meta - * associative containers. - */ -template -struct meta_associative_container_traits; - - -/** - * @brief Provides the member constant `value` to true if a meta associative - * container claims to wrap a key-only type, false otherwise. - * @tparam Type Potentially key-only meta associative container type. - */ -template -struct is_key_only_meta_associative_container: std::true_type {}; - - -/*! @copydoc is_key_only_meta_associative_container */ -template -struct is_key_only_meta_associative_container::type::mapped_type>> - : std::false_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially key-only meta associative container type. - */ -template -inline constexpr auto is_key_only_meta_associative_container_v = is_key_only_meta_associative_container::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 -struct is_meta_pointer_like: std::false_type {}; - - -/** - * @brief Partial specialization to ensure that const pointer-like types are - * also accepted. - * @tparam Type Potentially pointer-like type. - */ -template -struct is_meta_pointer_like: is_meta_pointer_like {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially pointer-like type. - */ -template -inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like::value; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Container traits. - * @tparam Container Type of the underlying container. - * @tparam Trait Traits associated with the underlying container. - */ -template class... Trait> -struct meta_container_traits: public Trait... { - /*! @brief Type of container. */ - using type = Container; -}; - - -/** - * @brief Basic STL-compatible container traits - * @tparam Container The type of the container. - */ -template -struct basic_container { - /** - * @brief Returns the size of the given container. - * @param cont The container for which to return the size. - * @return The size of the given container. - */ - [[nodiscard]] static typename Container::size_type size(const Container &cont) ENTT_NOEXCEPT { - return cont.size(); - } - - /** - * @brief Returns an iterator to the first element of the given container. - * @param cont The container for which to return the iterator. - * @return An iterator to the first element of the given container. - */ - [[nodiscard]] static typename Container::iterator begin(Container &cont) { - return cont.begin(); - } - - /** - * @brief Returns an iterator to the first element of the given container. - * @param cont The container for which to return the iterator. - * @return An iterator to the first element of the given container. - */ - [[nodiscard]] static typename Container::const_iterator cbegin(const Container &cont) { - return cont.begin(); - } - - /** - * @brief Returns an iterator past the last element of the given container. - * @param cont The container for which to return the iterator. - * @return An iterator past the last element of the given container. - */ - [[nodiscard]] static typename Container::iterator end(Container &cont) { - return cont.end(); - } - - /** - * @brief Returns an iterator past the last element of the given container. - * @param cont The container for which to return the iterator. - * @return An iterator past the last element of the given container. - */ - [[nodiscard]] static typename Container::const_iterator cend(const Container &cont) { - return cont.end(); - } -}; - - -/** - * @brief Basic STL-compatible associative container traits - * @tparam Container The type of the container. - */ -template -struct basic_associative_container { - /** - * @brief Returns an iterator to the element with key equivalent to the - * given one, if any. - * @param cont The container in which to search for the element. - * @param key The key of the element to search. - * @return An iterator to the element with the given key, if any. - */ - [[nodiscard]] static typename Container::iterator find(Container &cont, const typename Container::key_type &key) { - return cont.find(key); - } - - /*! @copydoc find */ - [[nodiscard]] static typename Container::const_iterator cfind(const Container &cont, const typename Container::key_type &key) { - return cont.find(key); - } -}; - - -/** - * @brief Basic STL-compatible dynamic container traits - * @tparam Container The type of the container. - */ -template -struct basic_dynamic_container { - /** - * @brief Clears the content of the given container. - * @param cont The container for which to clear the content. - * @return True in case of success, false otherwise. - */ - [[nodiscard]] static bool clear([[maybe_unused]] Container &cont) { - return cont.clear(), true; - } -}; - - -/** - * @brief Basic STL-compatible dynamic associative container traits - * @tparam Container The type of the container. - */ -template -struct basic_dynamic_associative_container { - /** - * @brief Removes the specified element from the given container. - * @param cont The container from which to remove the element. - * @param key The element to remove. - * @return A bool denoting whether the removal took place. - */ - [[nodiscard]] static bool erase([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) { - const auto sz = cont.size(); - return cont.erase(key) != sz; - } -}; - - -/** - * @brief Basic STL-compatible sequence container traits - * @tparam Container The type of the container. - */ -template -struct basic_sequence_container { - /** - * @brief Returns a reference to the element at the specified location of - * the given container (no bounds checking is performed). - * @param cont The container from which to get the element. - * @param pos The position of the element to return. - * @return A reference to the requested element. - */ - [[nodiscard]] static typename Container::reference get(Container &cont, typename Container::size_type pos) { - return cont[pos]; - } - - /*! @copydoc get */ - [[nodiscard]] static typename Container::const_reference cget(const Container &cont, typename Container::size_type pos) { - return cont[pos]; - } -}; - - -/** - * @brief STL-compatible dynamic associative key-only container traits - * @tparam Container The type of the container. - */ -template -struct dynamic_associative_key_only_container { - /** - * @brief Inserts an element into the given container. - * @param cont The container in which to insert the element. - * @param key The element to insert. - * @return A bool denoting whether the insertion took place. - */ - [[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) { - return cont.insert(key).second; - } -}; - - -/** - * @brief STL-compatible dynamic key-value associative container traits - * @tparam Container The type of the container. - */ -template -struct dynamic_associative_key_value_container { - /** - * @brief Inserts an element (a key/value pair) into the given container. - * @param cont The container in which to insert the element. - * @param key The key of the element to insert. - * @param value The value of the element to insert. - * @return A bool denoting whether the insertion took place. - */ - [[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key, [[maybe_unused]] const typename Container::mapped_type &value) { - return cont.insert(std::make_pair(key, value)).second; - } -}; - - -/** - * @brief STL-compatible dynamic sequence container traits - * @tparam Container The type of the container. - */ -template -struct dynamic_sequence_container { - /** - * @brief Resizes the given container to contain the given number of - * elements. - * @param cont The container to resize. - * @param sz The new size of the container. - * @return True in case of success, false otherwise. - */ - [[nodiscard]] static bool resize([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::size_type sz) { - return cont.resize(sz), true; - } - - /** - * @brief Inserts an element at the specified location of the given - * container. - * @param cont The container into which to insert the element. - * @param it Iterator before which the element will be inserted. - * @param value Element value to insert. - * @return A pair consisting of an iterator to the inserted element (in case - * of success) and a bool denoting whether the insertion took place. - */ - [[nodiscard]] static std::pair insert([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it, [[maybe_unused]] const typename Container::value_type &value) { - return { cont.insert(it, value), true }; - } - - /** - * @brief Removes the element at the specified location from the given - * container. - * @param cont The container from which to remove the element. - * @param it Iterator to the element to remove. - * @return A pair consisting of an iterator following the last removed - * element (in case of success) and a bool denoting whether the insertion - * took place. - */ - [[nodiscard]] static std::pair erase([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it) { - return { cont.erase(it), true }; - } -}; - - -/** - * @brief STL-compatible fixed sequence container traits - * @tparam Container The type of the container. - */ -template -struct fixed_sequence_container { - /** - * @brief Does nothing. - * @return False to indicate failure in all cases. - */ - [[nodiscard]] static bool resize(const Container &, typename Container::size_type) { - return false; - } - - /** - * @brief Does nothing. - * @return False to indicate failure in all cases. - */ - [[nodiscard]] static bool clear(const Container &) { - return false; - } - - /** - * @brief Does nothing. - * @return A pair consisting of an invalid iterator and a false value to - * indicate failure in all cases. - */ - [[nodiscard]] static std::pair insert(const Container &, typename Container::const_iterator, const typename Container::value_type &) { - return { {}, false }; - } - - /** - * @brief Does nothing. - * @return A pair consisting of an invalid iterator and a false value to - * indicate failure in all cases. - */ - [[nodiscard]] static std::pair erase(const Container &, typename Container::const_iterator) { - return { {}, false }; - } -}; - - -/** - * @brief Meta sequence container traits for `std::vector`s of any type. - * @tparam Type The type of elements. - * @tparam Args Other arguments. - */ -template -struct meta_sequence_container_traits> - : meta_container_traits< - std::vector, - basic_container, - basic_dynamic_container, - basic_sequence_container, - dynamic_sequence_container - > -{}; - - -/** - * @brief Meta sequence container traits for `std::array`s of any type. - * @tparam Type The type of elements. - * @tparam N The number of elements. - */ -template -struct meta_sequence_container_traits> - : meta_container_traits< - std::array, - basic_container, - basic_sequence_container, - fixed_sequence_container - > -{}; - - -/** - * @brief Meta associative container traits for `std::map`s of any type. - * @tparam Key The key type of elements. - * @tparam Value The value type of elements. - * @tparam Args Other arguments. - */ -template -struct meta_associative_container_traits> - : meta_container_traits< - std::map, - basic_container, - basic_associative_container, - basic_dynamic_container, - basic_dynamic_associative_container, - dynamic_associative_key_value_container - > -{}; - - -/** - * @brief Meta associative container traits for `std::unordered_map`s of any - * type. - * @tparam Key The key type of elements. - * @tparam Value The value type of elements. - * @tparam Args Other arguments. - */ -template -struct meta_associative_container_traits> - : meta_container_traits< - std::unordered_map, - basic_container, - basic_associative_container, - basic_dynamic_container, - basic_dynamic_associative_container, - dynamic_associative_key_value_container - > -{}; - - -/** - * @brief Meta associative container traits for `std::set`s of any type. - * @tparam Key The type of elements. - * @tparam Args Other arguments. - */ -template -struct meta_associative_container_traits> - : meta_container_traits< - std::set, - basic_container, - basic_associative_container, - basic_dynamic_container, - basic_dynamic_associative_container, - dynamic_associative_key_only_container - > -{}; - - -/** - * @brief Meta associative container traits for `std::unordered_set`s of any - * type. - * @tparam Key The type of elements. - * @tparam Args Other arguments. - */ -template -struct meta_associative_container_traits> - : meta_container_traits< - std::unordered_set, - basic_container, - basic_associative_container, - basic_dynamic_container, - basic_dynamic_associative_container, - dynamic_associative_key_only_container - > -{}; - - -} - - -#endif - -// #include "meta/ctx.hpp" -#ifndef ENTT_META_CTX_HPP -#define ENTT_META_CTX_HPP - - -// #include "../core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "../config/config.h" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct meta_type_node; - - -struct ENTT_API meta_context { - // we could use the lines below but VS2017 returns with an ICE if combined with ENTT_API despite the code being valid C++ - // inline static meta_type_node *local = nullptr; - // inline static meta_type_node **global = &local; - - [[nodiscard]] static meta_type_node * & local() ENTT_NOEXCEPT { - static meta_type_node *chain = nullptr; - return chain; - } - - [[nodiscard]] static meta_type_node ** & global() ENTT_NOEXCEPT { - static meta_type_node **chain = &local(); - return chain; - } -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/*! @brief Opaque container for a meta context. */ -struct meta_ctx { - /** - * @brief Binds the meta system to a given context. - * @param other A valid context to which to bind. - */ - static void bind(meta_ctx other) ENTT_NOEXCEPT { - internal::meta_context::global() = other.ctx; - } - -private: - internal::meta_type_node **ctx{&internal::meta_context::local()}; -}; - - -} - - -#endif - -// #include "meta/factory.hpp" -#ifndef ENTT_META_FACTORY_HPP -#define ENTT_META_FACTORY_HPP - - -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - -// #include "../core/type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "hashed_string.hpp" -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct fnv1a_traits; - - -template<> -struct fnv1a_traits { - using type = std::uint32_t; - static constexpr std::uint32_t offset = 2166136261; - static constexpr std::uint32_t prime = 16777619; -}; - - -template<> -struct fnv1a_traits { - using type = std::uint64_t; - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string { - using traits_type = internal::fnv1a_traits; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {} - const Char *str; - }; - - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT { - auto value = traits_type::offset; - - while(*curr != 0) { - value = (value ^ static_cast(*(curr++))) * traits_type::prime; - } - - return value; - } - -public: - /*! @brief Character type. */ - using value_type = Char; - /*! @brief Unsigned integer type. */ - using hash_type = id_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifer. - * @param size Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT { - id_type partial{traits_type::offset}; - while(size--) { partial = (partial^(str++)[0])*traits_type::prime; } - return partial; - } - - /** - * @brief Returns directly the numeric representation of a string. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * const auto value = basic_hashed_string::to_value("my.png"); - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - * @return The numeric representation of the string. - */ - template - [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT { - return helper(str); - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { - return helper(wrapper.str); - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() ENTT_NOEXCEPT - : str{nullptr}, hash{} - {} - - /** - * @brief Constructs a hashed string from an array of const characters. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * basic_hashed_string hs{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param curr Human-readable identifer. - */ - template - constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT - : str{curr}, hash{helper(curr)} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT - : str{wrapper.str}, hash{helper(wrapper.str)} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - [[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT { - return str; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { - return hash; - } - - /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const value_type *str; - hash_type hash; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the character type of the hashed string directly from a - * human-readable identifer provided to the constructor. - * - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ -template -basic_hashed_string(const Char (&str)[N]) --> basic_hashed_string; - - -/** - * @brief Compares two hashed strings. - * @tparam Char Character type. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const basic_hashed_string &lhs, const basic_hashed_string &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - - -inline namespace literals { - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_string{str}; -} - - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_wstring{str}; -} - - -} - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "../core/type_traits.hpp" - -// #include "meta.hpp" -#ifndef ENTT_META_META_HPP -#define ENTT_META_META_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/any.hpp" -#ifndef ENTT_CORE_ANY_HPP -#define ENTT_CORE_ANY_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - -// #include "type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" - -// #include "hashed_string.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief A SBO friendly, type-safe container for single values of any type. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_any { - enum class operation { COPY, MOVE, DTOR, COMP, ADDR, CADDR, REF, CREF, TYPE }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void *(const operation, const basic_any &, const void *); - - template - static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v; - - template - [[nodiscard]] static bool compare(const void *lhs, const void *rhs) { - if constexpr(!std::is_function_v && is_equality_comparable_v) { - return *static_cast(lhs) == *static_cast(rhs); - } else { - return lhs == rhs; - } - } - - template - static Type & as(const void *to) { - return *const_cast(static_cast(to)); - } - - template - static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(std::is_void_v) { - switch(op) { - case operation::COPY: - case operation::MOVE: - case operation::REF: - case operation::CREF: - as(to).vtable = from.vtable; - break; - default: - break; - } - } else if constexpr(std::is_lvalue_reference_v) { - using base_type = std::decay_t; - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to) = *static_cast(from.instance); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - as(to).vtable = from.vtable; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - as(to).vtable = from.vtable; - break; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = std::exchange(as(&from).instance, nullptr); - as(to).vtable = from.vtable; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } - - return nullptr; - } - - template - void initialize([[maybe_unused]] Args &&... args) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - if constexpr(std::is_aggregate_v) { - new (&storage) Type{std::forward(args)...}; - } else { - new (&storage) Type(std::forward(args)...); - } - } else { - if constexpr(std::is_aggregate_v) { - instance = new Type{std::forward(args)...}; - } else { - instance = new Type(std::forward(args)...); - } - } - } - } - -public: - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : basic_any{std::in_place_type} - {} - - /** - * @brief Constructs an any by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_any(std::in_place_type_t, Args &&... args) - : instance{}, - vtable{&basic_vtable} - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs an any that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - basic_any(std::reference_wrapper value) ENTT_NOEXCEPT - : basic_any{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs an any from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template, basic_any>>> - basic_any(Type &&value) - : basic_any{std::in_place_type>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any &other) - : basic_any{std::in_place_type} - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{std::in_place_type} - { - other.vtable(operation::MOVE, other, this); - } - - /*! @brief Frees the internal storage, whatever it means. */ - ~basic_any() { - vtable(operation::DTOR, *this, nullptr); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This any object. - */ - basic_any & operator=(const basic_any &other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::COPY, other, this); - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This any object. - */ - basic_any & operator=(basic_any &&other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { - emplace(value.get()); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - std::enable_if_t, basic_any>, basic_any &> - operator=(Type &&value) { - emplace>(std::forward(value)); - return *this; - } - - /** - * @brief Returns the type of the contained object. - * @return The type of the contained object, if any. - */ - [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info{}; - vtable(operation::TYPE, *this, &info); - return info; - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return vtable(operation::CADDR, *this, nullptr); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return const_cast(vtable(operation::ADDR, *this, nullptr)); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - } - - /** - * @brief Returns false if a wrapper is empty, true otherwise. - * @return False if the wrapper is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(vtable(operation::CADDR, *this, nullptr) == nullptr); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - bool operator==(const basic_any &other) const ENTT_NOEXCEPT { - return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); - } - - /** - * @brief Aliasing constructor. - * @return An any that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::REF, *this, &ref); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::CREF, *this, &ref); - return ref; - } - -private: - union { const void *instance; storage_type storage; }; - vtable_type *vtable; -}; - - -/** - * @brief Checks if two wrappers differ in their content. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param lhs A wrapper, either empty or not. - * @param rhs A wrapper, either empty or not. - * @return True if the two wrappers differ in their content, false otherwise. - */ -template -[[nodiscard]] inline bool operator!=(const basic_any &lhs, const basic_any &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Performs type-safe access to the contained object. - * @tparam Type Type to which conversion is required. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param data Target any object. - * @return The element converted to the requested type. - */ -template -Type any_cast(const basic_any &data) ENTT_NOEXCEPT { - const auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &&data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(std::move(*instance)); -} - - -/*! @copydoc any_cast */ -template -const Type * any_cast(const basic_any *data) ENTT_NOEXCEPT { - return (data->type() == type_id() ? static_cast(data->data()) : nullptr); -} - - -/*! @copydoc any_cast */ -template -Type * any_cast(basic_any *data) ENTT_NOEXCEPT { - // last attempt to make wrappers for const references return their values - return (data->type() == type_id() ? static_cast(static_cast, Type> *>(data)->data()) : nullptr); -} - - -} - - -#endif - -// #include "../core/fwd.hpp" - -// #include "../core/utility.hpp" -#ifndef ENTT_CORE_UTILITY_HPP -#define ENTT_CORE_UTILITY_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -/*! @brief Identity function object (waiting for C++20). */ -struct identity { - /** - * @brief Returns its argument unchanged. - * @tparam Type Type of the argument. - * @param value The actual argument. - * @return The submitted value as-is. - */ - template - [[nodiscard]] constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT { - return std::forward(value); - } -}; - - -/** - * @brief Constant utility to disambiguate overloaded members of a class. - * @tparam Type Type of the desired overload. - * @tparam Class Type of class to which the member belongs. - * @param member A valid pointer to a member. - * @return Pointer to the member. - */ -template -[[nodiscard]] constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; } - - -/** - * @brief Constant utility to disambiguate overloaded functions. - * @tparam Func Function type of the desired overload. - * @param func A valid pointer to a function. - * @return Pointer to the function. - */ -template -[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; } - - -/** - * @brief Helper type for visitors. - * @tparam Func Types of function objects. - */ -template -struct overloaded: Func... { - using Func::operator()...; -}; - - -/** - * @brief Deduction guide. - * @tparam Func Types of function objects. - */ -template -overloaded(Func...) --> overloaded; - - -/** - * @brief Basic implementation of a y-combinator. - * @tparam Func Type of a potentially recursive function. - */ -template -struct y_combinator { - /** - * @brief Constructs a y-combinator from a given function. - * @param recursive A potentially recursive function. - */ - y_combinator(Func recursive): - func{std::move(recursive)} - {} - - /** - * @brief Invokes a y-combinator and therefore its underlying function. - * @tparam Args Types of arguments to use to invoke the underlying function. - * @param args Parameters to use to invoke the underlying function. - * @return Return value of the underlying function, if any. - */ - template - decltype(auto) operator()(Args &&... args) const { - return func(*this, std::forward(args)...); - } - - /*! @copydoc operator()() */ - template - decltype(auto) operator()(Args &&... args) { - return func(*this, std::forward(args)...); - } - -private: - Func func; -}; - - -} - - -#endif - -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "adl_pointer.hpp" -#ifndef ENTT_META_ADL_POINTER_HPP -#define ENTT_META_ADL_POINTER_HPP - - -namespace entt { - - -/** - * @brief ADL based lookup function for dereferencing meta pointer-like types. - * @tparam Type Element type. - * @param value A pointer-like object. - * @return The value returned from the dereferenced pointer. - */ -template -decltype(auto) dereference_meta_pointer_like(const Type &value) { - return *value; -} - - -/** - * @brief Fake ADL based lookup function for meta pointer-like types. - * @tparam Type Element type. - */ -template -struct adl_meta_pointer_like { - /** - * @brief Uses the default ADL based lookup method to resolve the call. - * @param value A pointer-like object. - * @return The value returned from the dereferenced pointer. - */ - static decltype(auto) dereference(const Type &value) { - return dereference_meta_pointer_like(value); - } -}; - - -} - - -#endif - -// #include "ctx.hpp" -#ifndef ENTT_META_CTX_HPP -#define ENTT_META_CTX_HPP - - -// #include "../core/attribute.h" - -// #include "../config/config.h" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct meta_type_node; - - -struct ENTT_API meta_context { - // we could use the lines below but VS2017 returns with an ICE if combined with ENTT_API despite the code being valid C++ - // inline static meta_type_node *local = nullptr; - // inline static meta_type_node **global = &local; - - [[nodiscard]] static meta_type_node * & local() ENTT_NOEXCEPT { - static meta_type_node *chain = nullptr; - return chain; - } - - [[nodiscard]] static meta_type_node ** & global() ENTT_NOEXCEPT { - static meta_type_node **chain = &local(); - return chain; - } -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/*! @brief Opaque container for a meta context. */ -struct meta_ctx { - /** - * @brief Binds the meta system to a given context. - * @param other A valid context to which to bind. - */ - static void bind(meta_ctx other) ENTT_NOEXCEPT { - internal::meta_context::global() = other.ctx; - } - -private: - internal::meta_type_node **ctx{&internal::meta_context::local()}; -}; - - -} - - -#endif - -// #include "node.hpp" -#ifndef ENTT_META_NODE_HPP -#define ENTT_META_NODE_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" - -// #include "../core/fwd.hpp" - -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "type_traits.hpp" - - - -namespace entt { - - -class meta_any; -class meta_type; -struct meta_handle; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct meta_type_node; - - -struct meta_prop_node { - meta_prop_node * next; - const meta_any &id; - meta_any &value; -}; - - -struct meta_base_node { - meta_type_node * const parent; - meta_base_node * next; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - const void *(* const cast)(const void *) ENTT_NOEXCEPT; -}; - - -struct meta_conv_node { - meta_type_node * const parent; - meta_conv_node * next; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - meta_any(* const conv)(const void *); -}; - - -struct meta_ctor_node { - using size_type = std::size_t; - meta_type_node * const parent; - meta_ctor_node * next; - meta_prop_node * prop; - const size_type arity; - meta_type(* const arg)(const size_type) ENTT_NOEXCEPT; - meta_any(* const invoke)(meta_any * const); -}; - - -struct meta_data_node { - id_type id; - meta_type_node * const parent; - meta_data_node * next; - meta_prop_node * prop; - const bool is_const; - const bool is_static; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - bool(* const set)(meta_handle, meta_any); - meta_any(* const get)(meta_handle); -}; - - -struct meta_func_node { - using size_type = std::size_t; - id_type id; - meta_type_node * const parent; - meta_func_node * next; - meta_prop_node * prop; - const size_type arity; - const bool is_const; - const bool is_static; - meta_type_node *(* const ret)() ENTT_NOEXCEPT; - meta_type(* const arg)(const size_type) ENTT_NOEXCEPT; - meta_any(* const invoke)(meta_handle, meta_any *); -}; - - -struct meta_template_info { - using size_type = std::size_t; - const bool is_template_specialization; - const size_type arity; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - meta_type_node *(* const arg)(const size_type) ENTT_NOEXCEPT; -}; - - -struct meta_type_node { - using size_type = std::size_t; - const type_info info; - id_type id; - meta_type_node * next; - meta_prop_node * prop; - const size_type size_of; - const bool is_void; - const bool is_integral; - const bool is_floating_point; - const bool is_array; - const bool is_enum; - const bool is_union; - const bool is_class; - const bool is_pointer; - const bool is_function_pointer; - const bool is_member_object_pointer; - const bool is_member_function_pointer; - const bool is_pointer_like; - const bool is_sequence_container; - const bool is_associative_container; - const meta_template_info template_info; - const size_type rank; - size_type(* const extent)(const size_type) ENTT_NOEXCEPT ; - meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT; - meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT; - meta_ctor_node * const def_ctor; - meta_ctor_node *ctor{nullptr}; - meta_base_node *base{nullptr}; - meta_conv_node *conv{nullptr}; - meta_data_node *data{nullptr}; - meta_func_node *func{nullptr}; - void(* dtor)(void *){nullptr}; -}; - - -template -auto meta_visit(const Op &op, const Node *node) --> std::decay_t*Member)> { - for(auto *curr = node->*Member; curr; curr = curr->next) { - if(op(curr)) { - return curr; - } - } - - if constexpr(std::is_same_v) { - for(auto *curr = node->base; curr; curr = curr->next) { - if(auto *ret = meta_visit(op, curr->type()); ret) { - return ret; - } - } - } - - return nullptr; -} - - -template -meta_type_node * meta_arg_node(type_list, const std::size_t index) ENTT_NOEXCEPT; - - -template -class ENTT_API meta_node { - static_assert(std::is_same_v>>, "Invalid type"); - - template - [[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence) ENTT_NOEXCEPT { - meta_type_node::size_type ext{}; - ((ext = (dim == Index ? std::extent_v : ext)), ...); - return ext; - } - - [[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) ENTT_NOEXCEPT { - if constexpr(std::is_default_constructible_v) { - static meta_ctor_node node{ - type, - nullptr, - nullptr, - 0u, - nullptr, - [](meta_any * const) { return meta_any{std::in_place_type}; } - }; - - return &node; - } else { - return nullptr; - } - } - - [[nodiscard]] static meta_template_info meta_template_descriptor() ENTT_NOEXCEPT { - if constexpr(is_complete_v>) { - return { - true, - meta_template_traits::args_type::size, - &meta_node::class_type>::resolve, - [](const std::size_t index) ENTT_NOEXCEPT { - return meta_arg_node(typename meta_template_traits::args_type{}, index); - } - }; - } else { - return { false, 0u, nullptr, nullptr }; - } - } - -public: - [[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT { - static meta_type_node node{ - type_id(), - {}, - nullptr, - nullptr, - size_of_v, - std::is_void_v, - std::is_integral_v, - std::is_floating_point_v, - std::is_array_v, - std::is_enum_v, - std::is_union_v, - std::is_class_v, - std::is_pointer_v, - std::is_pointer_v && std::is_function_v>, - std::is_member_object_pointer_v, - std::is_member_function_pointer_v, - is_meta_pointer_like_v, - is_complete_v>, - is_complete_v>, - meta_template_descriptor(), - std::rank_v, - [](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence>{}); }, - &meta_node>>>::resolve, - &meta_node>>>::resolve, - meta_default_constructor(&node), - meta_default_constructor(&node) - }; - - return &node; - } -}; - - -template -struct meta_info: meta_node>> {}; - - -template -meta_type_node * meta_arg_node(type_list, const std::size_t index) ENTT_NOEXCEPT { - meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info::resolve()...}; - return args[index + 1u]; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -} - - -#endif - -// #include "range.hpp" -#ifndef ENTT_META_RANGE_HPP -#define ENTT_META_RANGE_HPP - - -#include -#include - - -namespace entt { - - -/** - * @brief Iterable range to use to iterate all types of meta objects. - * @tparam Type Type of meta objects returned. - * @tparam Node Type of meta nodes iterated. - */ -template -class meta_range { - struct range_iterator { - using difference_type = std::ptrdiff_t; - using value_type = Type; - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - using node_type = Node; - - range_iterator() ENTT_NOEXCEPT = default; - - range_iterator(node_type *head) ENTT_NOEXCEPT - : it{head} - {} - - range_iterator & operator++() ENTT_NOEXCEPT { - return (it = it->next), *this; - } - - range_iterator operator++(int) ENTT_NOEXCEPT { - range_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return it; - } - - [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - node_type *it{}; - }; - -public: - /*! @brief Node type. */ - using node_type = Node; - /*! @brief Input iterator type. */ - using iterator = range_iterator; - - /*! @brief Default constructor. */ - meta_range() ENTT_NOEXCEPT = default; - - /** - * @brief Constructs a meta range from a given node. - * @param head The underlying node with which to construct the range. - */ - meta_range(node_type *head) - : node{head} - {} - - /** - * @brief Returns an iterator to the beginning. - * @return An iterator to the first meta object of the range. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return iterator{node}; - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last meta object of the - * range. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{}; - } - -private: - node_type *node{nullptr}; -}; - - -} - - -#endif - -// #include "type_traits.hpp" - - - -namespace entt { - - -class meta_any; -class meta_type; - - -/*! @brief Proxy object for sequence containers. */ -class meta_sequence_container { - template - struct meta_sequence_container_proxy; - - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; - - /*! @brief Default constructor. */ - meta_sequence_container() ENTT_NOEXCEPT = default; - - /** - * @brief Construct a proxy object for sequence containers. - * @tparam Type Type of container to wrap. - * @param instance The container to wrap. - */ - template - meta_sequence_container(std::in_place_type_t, any instance) ENTT_NOEXCEPT - : value_type_fn{&meta_sequence_container_proxy::value_type}, - size_fn{&meta_sequence_container_proxy::size}, - resize_fn{&meta_sequence_container_proxy::resize}, - clear_fn{&meta_sequence_container_proxy::clear}, - begin_fn{&meta_sequence_container_proxy::begin}, - end_fn{&meta_sequence_container_proxy::end}, - insert_fn{&meta_sequence_container_proxy::insert}, - erase_fn{&meta_sequence_container_proxy::erase}, - get_fn{&meta_sequence_container_proxy::get}, - storage{std::move(instance)} - {} - - [[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT; - inline bool resize(size_type); - inline bool clear(); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline std::pair insert(iterator, meta_any); - inline std::pair erase(iterator); - [[nodiscard]] inline meta_any operator[](size_type); - [[nodiscard]] inline explicit operator bool() const ENTT_NOEXCEPT; - -private: - meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr; - size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr; - bool(* resize_fn)(any &, size_type) = nullptr; - bool(* clear_fn)(any &) = nullptr; - iterator(* begin_fn)(any &) = nullptr; - iterator(* end_fn)(any &) = nullptr; - std::pair(* insert_fn)(any &, iterator, meta_any &) = nullptr; - std::pair(* erase_fn)(any &, iterator) = nullptr; - meta_any(* get_fn)(any &, size_type) = nullptr; - any storage{}; -}; - - -/*! @brief Proxy object for associative containers. */ -class meta_associative_container { - template - struct meta_associative_container_proxy; - - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; - - /*! @brief Default constructor. */ - meta_associative_container() ENTT_NOEXCEPT = default; - - /** - * @brief Construct a proxy object for associative containers. - * @tparam Type Type of container to wrap. - * @param instance The container to wrap. - */ - template - meta_associative_container(std::in_place_type_t, any instance) ENTT_NOEXCEPT - : key_only_container{is_key_only_meta_associative_container_v}, - key_type_fn{&meta_associative_container_proxy::key_type}, - mapped_type_fn{&meta_associative_container_proxy::mapped_type}, - value_type_fn{&meta_associative_container_proxy::value_type}, - size_fn{&meta_associative_container_proxy::size}, - clear_fn{&meta_associative_container_proxy::clear}, - begin_fn{&meta_associative_container_proxy::begin}, - end_fn{&meta_associative_container_proxy::end}, - insert_fn{&meta_associative_container_proxy::insert}, - erase_fn{&meta_associative_container_proxy::erase}, - find_fn{&meta_associative_container_proxy::find}, - storage{std::move(instance)} - {} - - [[nodiscard]] inline bool key_only() const ENTT_NOEXCEPT; - [[nodiscard]] inline meta_type key_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline meta_type mapped_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT; - inline bool clear(); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline bool insert(meta_any, meta_any); - inline bool erase(meta_any); - [[nodiscard]] inline iterator find(meta_any); - [[nodiscard]] inline explicit operator bool() const ENTT_NOEXCEPT; - -private: - bool key_only_container{}; - meta_type(* key_type_fn)() ENTT_NOEXCEPT = nullptr; - meta_type(* mapped_type_fn)() ENTT_NOEXCEPT = nullptr; - meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr; - size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr; - bool(* clear_fn)(any &) = nullptr; - iterator(* begin_fn)(any &) = nullptr; - iterator(* end_fn)(any &) = nullptr; - bool(* insert_fn)(any &, meta_any &, meta_any &) = nullptr; - bool(* erase_fn)(any &, meta_any &) = nullptr; - iterator(* find_fn)(any &, meta_any &) = nullptr; - any storage{}; -}; - - -/*! @brief Opaque wrapper for values of any type. */ -class meta_any { - enum class operation { DTOR, REF, CREF, DEREF, CDEREF, SEQ, CSEQ, ASSOC, CASSOC }; - - using vtable_type = void(const operation, const any &, void *); - - template - static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) { - if constexpr(!std::is_void_v) { - switch(op) { - case operation::DTOR: - if constexpr(!std::is_lvalue_reference_v) { - if(auto *curr = static_cast(to); curr->dtor) { - curr->dtor(const_cast(from).data()); - } - } - break; - case operation::REF: - case operation::CREF: - *static_cast(to) = (op == operation::REF ? meta_any{std::ref(any_cast(const_cast(from)))} : meta_any{std::cref(any_cast &>(from))}); - break; - case operation::DEREF: - case operation::CDEREF: - if constexpr(is_meta_pointer_like_v>) { - using element_type = std::remove_const_t>::element_type>; - - if constexpr(std::is_function_v) { - *static_cast(to) = any_cast>(from); - } else if constexpr(!std::is_same_v) { - using adl_meta_pointer_like_type = adl_meta_pointer_like>; - - if constexpr(std::is_lvalue_reference_v &>()))>) { - auto &&obj = adl_meta_pointer_like_type::dereference(any_cast &>(from)); - *static_cast(to) = (op == operation::DEREF ? meta_any{std::ref(obj)} : meta_any{std::cref(obj)}); - } else { - *static_cast(to) = adl_meta_pointer_like_type::dereference(any_cast &>(from)); - } - } - } - break; - case operation::SEQ: - case operation::CSEQ: - if constexpr(is_complete_v>>) { - *static_cast(to) = { std::in_place_type>, (op == operation::SEQ ? const_cast(from).as_ref() : from.as_ref()) }; - } - break; - case operation::ASSOC: - case operation::CASSOC: - if constexpr(is_complete_v>>) { - *static_cast(to) = { std::in_place_type>, (op == operation::ASSOC ? const_cast(from).as_ref() : from.as_ref()) }; - } - break; - } - } - } - -public: - /*! @brief Default constructor. */ - meta_any() ENTT_NOEXCEPT - : storage{}, - node{}, - vtable{&basic_vtable} - {} - - /** - * @brief Constructs a meta any by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit meta_any(std::in_place_type_t, Args &&... args) - : storage{std::in_place_type, std::forward(args)...}, - node{internal::meta_info::resolve()}, - vtable{&basic_vtable} - {} - - /** - * @brief Constructs a meta any that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - meta_any(std::reference_wrapper value) - : meta_any{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs a meta any from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template, meta_any>>> - meta_any(Type &&value) - : meta_any{std::in_place_type>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - meta_any(const meta_any &other) = default; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - meta_any(meta_any &&other) ENTT_NOEXCEPT - : storage{std::move(other.storage)}, - node{std::exchange(other.node, nullptr)}, - vtable{std::exchange(other.vtable, &basic_vtable)} - {} - - /*! @brief Frees the internal storage, whatever it means. */ - ~meta_any() { - vtable(operation::DTOR, storage, node); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This meta any object. - */ - meta_any & operator=(const meta_any &other) { - std::exchange(vtable, other.vtable)(operation::DTOR, storage, node); - storage = other.storage; - node = other.node; - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This meta any object. - */ - meta_any & operator=(meta_any &&other) { - std::exchange(vtable, std::exchange(other.vtable, &basic_vtable))(operation::DTOR, storage, node); - storage = std::move(other.storage); - node = std::exchange(other.node, nullptr); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This meta any object. - */ - template - meta_any & operator=(std::reference_wrapper value) { - emplace(value.get()); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This meta any object. - */ - template - std::enable_if_t, meta_any>, meta_any &> - operator=(Type &&value) { - emplace>(std::forward(value)); - return *this; - } - - /** - * @brief Returns the type of the underlying object. - * @return The type of the underlying object, if any. - */ - [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT; - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return storage.data(); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return storage.data(); - } - - /** - * @brief Invokes the underlying function, if possible. - * - * @sa meta_func::invoke - * - * @tparam Args Types of arguments to use to invoke the function. - * @param id Unique identifier. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ - template - meta_any invoke(const id_type id, Args &&... args) const; - - /*! @copydoc invoke */ - template - meta_any invoke(const id_type id, Args &&... args); - - /** - * @brief Sets the value of a given variable. - * - * The type of the value must be such that a cast or conversion to the type - * of the variable is possible. Otherwise, invoking the setter does nothing. - * - * @tparam Type Type of value to assign. - * @param id Unique identifier. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - bool set(const id_type id, Type &&value); - - /** - * @brief Gets the value of a given variable. - * @param id Unique identifier. - * @return A meta any containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(const id_type id) const; - - /*! @copydoc get */ - [[nodiscard]] meta_any get(const id_type id); - - /** - * @brief Tries to cast an instance to a given type. - * @tparam Type Type to which to cast the instance. - * @return A (possibly null) pointer to the contained instance. - */ - template - [[nodiscard]] const Type * try_cast() const { - if(node) { - if(const auto info = type_id(); node->info == info) { - return any_cast(&storage); - } else if(const auto *base = internal::meta_visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) { - return static_cast(base->cast(storage.data())); - } - } - - return nullptr; - } - - /*! @copydoc try_cast */ - template - [[nodiscard]] Type * try_cast() { - if(node) { - if(const auto info = type_id(); node->info == info) { - return any_cast(&storage); - } else if(const auto *base = internal::meta_visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) { - return static_cast(const_cast *>(base->cast(static_cast &>(storage).data()))); - } - } - - return nullptr; - } - - /** - * @brief Tries to cast an instance to a given type. - * - * The type of the instance must be such that the cast is possible. - * - * @warning - * Attempting to perform an invalid cast results in undefined behavior. - * - * @tparam Type Type to which to cast the instance. - * @return A reference to the contained instance. - */ - template - [[nodiscard]] Type cast() const { - auto * const actual = try_cast>(); - ENTT_ASSERT(actual); - return static_cast(*actual); - } - - /*! @copydoc cast */ - template - [[nodiscard]] Type cast() { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = try_cast>(); - ENTT_ASSERT(instance); - return static_cast(*instance); - } - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return A valid meta any object if there exists a viable conversion, an - * invalid one otherwise. - */ - template - [[nodiscard]] meta_any allow_cast() const { - if(try_cast>() != nullptr) { - return as_ref(); - } else if(node) { - if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id()](const auto *curr) { return curr->type()->info == info; }, node); conv) { - return conv->conv(storage.data()); - } - } - - return {}; - } - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return True if there exists a viable conversion, false otherwise. - */ - template - bool allow_cast() { - // forces const on non-reference types to make them work also with wrappers for const references - if(try_cast>() != nullptr) { - return true; - } else if(node) { - if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id()](const auto *curr) { return curr->type()->info == info; }, node); conv) { - *this = conv->conv(std::as_const(storage).data()); - return true; - } - } - - return false; - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); - storage.emplace(std::forward(args)...); - node = internal::meta_info::resolve(); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); - storage.reset(); - node = nullptr; - } - - /** - * @brief Returns a sequence container proxy. - * @return A sequence container proxy for the underlying object. - */ - [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT { - meta_sequence_container proxy; - vtable(operation::SEQ, storage, &proxy); - return proxy; - } - - /*! @copydoc as_sequence_container */ - [[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT { - meta_sequence_container proxy; - vtable(operation::CSEQ, storage, &proxy); - return proxy; - } - - /** - * @brief Returns an associative container proxy. - * @return An associative container proxy for the underlying object. - */ - [[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT { - meta_associative_container proxy; - vtable(operation::ASSOC, storage, &proxy); - return proxy; - } - - /*! @copydoc as_associative_container */ - [[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT { - meta_associative_container proxy; - vtable(operation::CASSOC, storage, &proxy); - return proxy; - } - - /** - * @brief Indirection operator for dereferencing opaque objects. - * @return A meta any that shares a reference to an unmanaged object if the - * wrapped element is dereferenceable, an invalid meta any otherwise. - */ - [[nodiscard]] meta_any operator*() ENTT_NOEXCEPT { - meta_any ret{}; - vtable(operation::DEREF, storage, &ret); - return ret; - } - - /*! @copydoc operator* */ - [[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT { - meta_any ret{}; - vtable(operation::CDEREF, storage, &ret); - return ret; - } - - /** - * @brief Returns false if a wrapper is invalid, true otherwise. - * @return False if the wrapper is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - [[nodiscard]] bool operator==(const meta_any &other) const { - return (!node && !other.node) || (node && other.node && node->info == other.node->info && storage == other.storage); - } - - /** - * @brief Aliasing constructor. - * @return A meta any that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any as_ref() ENTT_NOEXCEPT { - meta_any ref{}; - vtable(operation::REF, storage, &ref); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] meta_any as_ref() const ENTT_NOEXCEPT { - meta_any ref{}; - vtable(operation::CREF, storage, &ref); - return ref; - } - -private: - any storage; - internal::meta_type_node *node; - vtable_type *vtable; -}; - - -/** - * @brief Checks if two wrappers differ in their content. - * @param lhs A meta any object, either empty or not. - * @param rhs A meta any object, either empty or not. - * @return True if the two wrappers differ in their content, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const meta_any &lhs, const meta_any &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Opaque pointers to instances of any type. - * - * A handle doesn't perform copies and isn't responsible for the contained - * object. It doesn't prolong the lifetime of the pointed instance.
- * Handles are used to generate references to actual objects when needed. - */ -struct meta_handle { - /*! @brief Default constructor. */ - meta_handle() = default; - - - /*! @brief Default copy constructor, deleted on purpose. */ - meta_handle(const meta_handle &) = delete; - - /*! @brief Default move constructor. */ - meta_handle(meta_handle &&) = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This meta handle. - */ - meta_handle & operator=(const meta_handle &) = delete; - - /** - * @brief Default move assignment operator. - * @return This meta handle. - */ - meta_handle & operator=(meta_handle &&) = default; - - /** - * @brief Creates a handle that points to an unmanaged object. - * @tparam Type Type of object to use to initialize the handle. - * @param value An instance of an object to use to initialize the handle. - */ - template, meta_handle>>> - meta_handle(Type &value) ENTT_NOEXCEPT - : meta_handle{} - { - if constexpr(std::is_same_v, meta_any>) { - any = value.as_ref(); - } else { - any.emplace(value); - } - } - - /** - * @brief Returns false if a handle is invalid, true otherwise. - * @return False if the handle is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(any); - } - - /** - * @brief Access operator for accessing the contained opaque object. - * @return A meta any that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any * operator->() { - return &any; - } - - /*! @copydoc operator-> */ - [[nodiscard]] const meta_any * operator->() const { - return &any; - } - -private: - meta_any any; -}; - - -/*! @brief Opaque wrapper for properties of any type. */ -struct meta_prop { - /*! @brief Node type. */ - using node_type = internal::meta_prop_node; - - /** - * @brief Constructs an instance from a given node. - * @param curr The underlying node with which to construct the instance. - */ - meta_prop(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /** - * @brief Returns the stored key as a const reference. - * @return A meta any containing the key stored with the property. - */ - [[nodiscard]] meta_any key() const { - return node->id.as_ref(); - } - - /** - * @brief Returns the stored value by copy. - * @return A meta any containing the value stored with the property. - */ - [[nodiscard]] meta_any value() const { - return node->value; - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for constructors. */ -struct meta_ctor { - /*! @brief Node type. */ - using node_type = internal::meta_ctor_node; - /*! @brief Unsigned integer type. */ - using size_type = typename node_type::size_type; - - /*! @copydoc meta_prop::meta_prop */ - meta_ctor(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /** - * @brief Returns the type to which an object belongs. - * @return The type to which the object belongs. - */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; - - /** - * @brief Returns the number of arguments accepted by a constructor. - * @return The number of arguments accepted by the constructor. - */ - [[nodiscard]] size_type arity() const ENTT_NOEXCEPT { - return node->arity; - } - - /** - * @brief Returns the type of the i-th argument of a constructor. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a constructor. - */ - [[nodiscard]] meta_type arg(size_type index) const ENTT_NOEXCEPT; - - /** - * @brief Creates an instance of the underlying type, if possible. - * - * Parameters must be such that a cast or conversion to the required types - * is possible. Otherwise, an empty and thus invalid wrapper is returned. - * - * @param args Parameters to use to construct the instance. - * @param sz Number of parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - [[nodiscard]] meta_any invoke(meta_any * const args, const size_type sz) const { - return sz == arity() ? node->invoke(args) : meta_any{}; - } - - /** - * @copybrief invoke - * - * @sa invoke - * - * @tparam Args Types of arguments to use to construct the instance. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - template - [[nodiscard]] meta_any invoke([[maybe_unused]] Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return invoke(arguments, sizeof...(Args)); - } - - /** - * @brief Returns a range to use to visit all properties. - * @return An iterable range to use to visit all properties. - */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for data members. */ -struct meta_data { - /*! @brief Node type. */ - using node_type = internal::meta_data_node; - - /*! @copydoc meta_prop::meta_prop */ - meta_data(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /*! @copydoc meta_type::id */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { - return node->id; - } - - /*! @copydoc meta_ctor::parent */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; - - /** - * @brief Indicates whether a data member is constant or not. - * @return True if the data member is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const ENTT_NOEXCEPT { - return node->is_const; - } - - /** - * @brief Indicates whether a data member is static or not. - * @return True if the data member is static, false otherwise. - */ - [[nodiscard]] bool is_static() const ENTT_NOEXCEPT { - return node->is_static; - } - - /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT; - - /** - * @brief Sets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the setter results in an undefined - * behavior.
- * The type of the value must be such that a cast or conversion to the type - * of the variable is possible. Otherwise, invoking the setter does nothing. - * - * @tparam Type Type of value to assign. - * @param instance An opaque instance of the underlying type. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - bool set(meta_handle instance, Type &&value) const { - return node->set && node->set(std::move(instance), std::forward(value)); - } - - /** - * @brief Gets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the getter results in an undefined behavior. - * - * @param instance An opaque instance of the underlying type. - * @return A meta any containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(meta_handle instance) const { - return node->get(std::move(instance)); - } - - /*! @copydoc meta_ctor::prop */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for member functions. */ -struct meta_func { - /*! @brief Node type. */ - using node_type = internal::meta_func_node; - /*! @brief Unsigned integer type. */ - using size_type = typename node_type::size_type; - - /*! @copydoc meta_prop::meta_prop */ - meta_func(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /*! @copydoc meta_type::id */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { - return node->id; - } - - /*! @copydoc meta_ctor::parent */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; - - /** - * @brief Returns the number of arguments accepted by a member function. - * @return The number of arguments accepted by the member function. - */ - [[nodiscard]] size_type arity() const ENTT_NOEXCEPT { - return node->arity; - } - - /** - * @brief Indicates whether a member function is constant or not. - * @return True if the member function is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const ENTT_NOEXCEPT { - return node->is_const; - } - - /** - * @brief Indicates whether a member function is static or not. - * @return True if the member function is static, false otherwise. - */ - [[nodiscard]] bool is_static() const ENTT_NOEXCEPT { - return node->is_static; - } - - /** - * @brief Returns the return type of a member function. - * @return The return type of the member function. - */ - [[nodiscard]] inline meta_type ret() const ENTT_NOEXCEPT; - - /** - * @brief Returns the type of the i-th argument of a member function. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a member function. - */ - [[nodiscard]] inline meta_type arg(size_type index) const ENTT_NOEXCEPT; - - /** - * @brief Invokes the underlying function, if possible. - * - * To invoke a member function, the parameters must be such that a cast or - * conversion to the required types is possible. Otherwise, an empty and - * thus invalid wrapper is returned.
- * It must be possible to cast the instance to the parent type of the member - * function. Otherwise, invoking the underlying function results in an - * undefined behavior. - * - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @param sz Number of parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ - meta_any invoke(meta_handle instance, meta_any * const args, const size_type sz) const { - return sz == arity() ? node->invoke(std::move(instance), args) : meta_any{}; - } - - /** - * @copybrief invoke - * - * @sa invoke - * - * @tparam Args Types of arguments to use to invoke the function. - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the new instance, if any. - */ - template - meta_any invoke(meta_handle instance, Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return invoke(std::move(instance), arguments, sizeof...(Args)); - } - - /*! @copydoc meta_ctor::prop */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for types. */ -class meta_type { - static bool can_cast_or_convert(const internal::meta_type_node *type, const type_info info) ENTT_NOEXCEPT { - if(type->info == info) { - return true; - } - - for(const auto *curr = type->conv; curr; curr = curr->next) { - if(curr->type()->info == info) { - return true; - } - } - - for(const auto *curr = type->base; curr; curr = curr->next) { - if(auto *target = curr->type(); can_cast_or_convert(target, info)) { - return true; - } - } - - return false; - } - - template - [[nodiscard]] static const internal::meta_ctor_node * ctor(const internal::meta_ctor_node *curr, std::index_sequence) { - for(; curr; curr = curr->next) { - if(curr->arity == sizeof...(Args) && (can_cast_or_convert(internal::meta_info::resolve(), curr->arg(Index).info()) && ...)) { - return curr; - } - } - - return nullptr; - } - -public: - /*! @brief Node type. */ - using node_type = internal::meta_type_node; - /*! @brief Node type. */ - using base_node_type = internal::meta_base_node; - /*! @brief Unsigned integer type. */ - using size_type = typename node_type::size_type; - - /*! @copydoc meta_prop::meta_prop */ - meta_type(node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /** - * @brief Constructs an instance from a given base node. - * @param curr The base node with which to construct the instance. - */ - meta_type(base_node_type *curr) ENTT_NOEXCEPT - : node{curr ? curr->type() : nullptr} - {} - - /** - * @brief Returns the type info object of the underlying type. - * @return The type info object of the underlying type. - */ - [[nodiscard]] type_info info() const ENTT_NOEXCEPT { - return node->info; - } - - /** - * @brief Returns the identifier assigned to a type. - * @return The identifier assigned to the type. - */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { - return node->id; - } - - /** - * @brief Returns the size of the underlying type if known. - * @return The size of the underlying type if known, 0 otherwise. - */ - [[nodiscard]] size_type size_of() const ENTT_NOEXCEPT { - return node->size_of; - } - - /** - * @brief Checks whether a type refers to void or not. - * @return True if the underlying type is void, false otherwise. - */ - [[nodiscard]] bool is_void() const ENTT_NOEXCEPT { - return node->is_void; - } - - /** - * @brief Checks whether a type refers to an integral type or not. - * @return True if the underlying type is an integral type, false otherwise. - */ - [[nodiscard]] bool is_integral() const ENTT_NOEXCEPT { - return node->is_integral; - } - - /** - * @brief Checks whether a type refers to a floating-point type or not. - * @return True if the underlying type is a floating-point type, false - * otherwise. - */ - [[nodiscard]] bool is_floating_point() const ENTT_NOEXCEPT { - return node->is_floating_point; - } - - /** - * @brief Checks whether a type refers to an array type or not. - * @return True if the underlying type is an array type, false otherwise. - */ - [[nodiscard]] bool is_array() const ENTT_NOEXCEPT { - return node->is_array; - } - - /** - * @brief Checks whether a type refers to an enum or not. - * @return True if the underlying type is an enum, false otherwise. - */ - [[nodiscard]] bool is_enum() const ENTT_NOEXCEPT { - return node->is_enum; - } - - /** - * @brief Checks whether a type refers to an union or not. - * @return True if the underlying type is an union, false otherwise. - */ - [[nodiscard]] bool is_union() const ENTT_NOEXCEPT { - return node->is_union; - } - - /** - * @brief Checks whether a type refers to a class or not. - * @return True if the underlying type is a class, false otherwise. - */ - [[nodiscard]] bool is_class() const ENTT_NOEXCEPT { - return node->is_class; - } - - /** - * @brief Checks whether a type refers to a pointer or not. - * @return True if the underlying type is a pointer, false otherwise. - */ - [[nodiscard]] bool is_pointer() const ENTT_NOEXCEPT { - return node->is_pointer; - } - - /** - * @brief Checks whether a type refers to a function pointer or not. - * @return True if the underlying type is a function pointer, false - * otherwise. - */ - [[nodiscard]] bool is_function_pointer() const ENTT_NOEXCEPT { - return node->is_function_pointer; - } - - /** - * @brief Checks whether a type refers to a pointer to data member or not. - * @return True if the underlying type is a pointer to data member, false - * otherwise. - */ - [[nodiscard]] bool is_member_object_pointer() const ENTT_NOEXCEPT { - return node->is_member_object_pointer; - } - - /** - * @brief Checks whether a type refers to a pointer to member function or - * not. - * @return True if the underlying type is a pointer to member function, - * false otherwise. - */ - [[nodiscard]] bool is_member_function_pointer() const ENTT_NOEXCEPT { - return node->is_member_function_pointer; - } - - /** - * @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_pointer_like() const ENTT_NOEXCEPT { - return node->is_pointer_like; - } - - /** - * @brief Checks whether a type refers to a sequence container or not. - * @return True if the type is a sequence container, false otherwise. - */ - [[nodiscard]] bool is_sequence_container() const ENTT_NOEXCEPT { - return node->is_sequence_container; - } - - /** - * @brief Checks whether a type refers to an associative container or not. - * @return True if the type is an associative container, false otherwise. - */ - [[nodiscard]] bool is_associative_container() const ENTT_NOEXCEPT { - return node->is_associative_container; - } - - /** - * @brief Checks whether a type refers to a recognized class template - * specialization or not. - * @return True if the type is a recognized class template specialization, - * false otherwise. - */ - [[nodiscard]] bool is_template_specialization() const ENTT_NOEXCEPT { - return node->template_info.is_template_specialization; - } - - /** - * @brief Returns the number of template arguments, if any. - * @return The number of template arguments, if any. - */ - [[nodiscard]] size_type template_arity() const ENTT_NOEXCEPT { - return node->template_info.arity; - } - - /** - * @brief Returns a tag for the class template of the underlying type. - * - * @sa meta_class_template_tag - * - * @return The tag for the class template of the underlying type. - */ - [[nodiscard]] inline meta_type template_type() const ENTT_NOEXCEPT { - return is_template_specialization() ? node->template_info.type() : meta_type{}; - } - - /** - * @brief Returns the type of the i-th template argument of a type. - * @param index Index of the template argument of which to return the type. - * @return The type of the i-th template argument of a type. - */ - [[nodiscard]] inline meta_type template_arg(size_type index) const ENTT_NOEXCEPT { - return index < template_arity() ? node->template_info.arg(index) : meta_type{}; - } - - /** - * @brief Provides the number of dimensions of an array type. - * @return The number of dimensions in case of array types, 0 otherwise. - */ - [[nodiscard]] size_type rank() const ENTT_NOEXCEPT { - return node->rank; - } - - /** - * @brief The number of elements along the given dimension of an array type. - * @param dim The dimension of which to return the number of elements. - * @return The number of elements along the given dimension in case of array - * types, 0 otherwise. - */ - [[nodiscard]] size_type extent(size_type dim = {}) const ENTT_NOEXCEPT { - return node->extent(dim); - } - - /** - * @brief Provides the type for which the pointer is defined. - * @return The type for which the pointer is defined or this type if it - * doesn't refer to a pointer type. - */ - [[nodiscard]] meta_type remove_pointer() const ENTT_NOEXCEPT { - return node->remove_pointer(); - } - - /** - * @brief Provides the type for which the array is defined. - * @return The type for which the array is defined or this type if it - * doesn't refer to an array type. - */ - [[nodiscard]] meta_type remove_extent() const ENTT_NOEXCEPT { - return node->remove_extent(); - } - - /** - * @brief Returns a range to use to visit top-level base meta types. - * @return An iterable range to use to visit top-level base meta types. - */ - [[nodiscard]] meta_range base() const ENTT_NOEXCEPT { - return node->base; - } - - /** - * @brief Returns the base meta type associated with a given identifier. - * @param id Unique identifier. - * @return The base meta type associated with the given identifier, if any. - */ - [[nodiscard]] meta_type base(const id_type id) const { - return internal::meta_visit<&node_type::base>([id](const auto *curr) { return curr->type()->id == id; }, node); - } - - /** - * @brief Returns a range to use to visit top-level constructors. - * @return An iterable range to use to visit top-level constructors. - */ - [[nodiscard]] meta_range ctor() const ENTT_NOEXCEPT { - return node->ctor; - } - - /** - * @brief Returns a constructor for a given list of types of arguments. - * @tparam Args Constructor arguments. - * @return The requested constructor, if any. - */ - template - [[nodiscard]] meta_ctor ctor() const { - return ctor(node->ctor, std::make_index_sequence{}); - } - - /** - * @brief Returns a range to use to visit top-level data. - * @return An iterable range to use to visit top-level data. - */ - [[nodiscard]] meta_range data() const ENTT_NOEXCEPT { - return node->data; - } - - /** - * @brief Returns the data associated with a given identifier. - * - * The data of the base classes will also be visited, if any. - * - * @param id Unique identifier. - * @return The data associated with the given identifier, if any. - */ - [[nodiscard]] meta_data data(const id_type id) const { - return internal::meta_visit<&node_type::data>([id](const auto *curr) { return curr->id == id; }, node); - } - - /** - * @brief Returns a range to use to visit top-level functions. - * @return An iterable range to use to visit top-level functions. - */ - [[nodiscard]] meta_range func() const ENTT_NOEXCEPT { - return node->func; - } - - /** - * @brief Returns the function associated with a given identifier. - * - * The functions of the base classes will also be visited, if any.
- * In the case of overloaded functions, the first one with the required - * identifier will be returned. - * - * @param id Unique identifier. - * @return The function associated with the given identifier, if any. - */ - [[nodiscard]] meta_func func(const id_type id) const { - return internal::meta_visit<&node_type::func>([id](const auto *curr) { return curr->id == id; }, node); - } - - /** - * @brief Creates an instance of the underlying type, if possible. - * - * Parameters must be such that a cast or conversion to the required types - * is possible. Otherwise, an empty and thus invalid wrapper is returned. - * - * @param args Parameters to use to construct the instance. - * @param sz Number of parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - [[nodiscard]] meta_any construct(meta_any * const args, const size_type sz) const { - meta_any ret{}; - internal::meta_visit<&node_type::ctor>([args, sz, &ret](const auto *curr) { return (curr->arity == sz) && (ret = curr->invoke(args)); }, node); - return ret; - } - - /** - * @copybrief construct - * - * @sa construct - * - * @tparam Args Types of arguments to use to construct the instance. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - template - [[nodiscard]] meta_any construct(Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return construct(arguments, sizeof...(Args)); - } - - /** - * @brief Invokes a function given an identifier, if possible. - * - * It must be possible to cast the instance to the parent type of the member - * function. Otherwise, invoking the underlying function results in an - * undefined behavior. - * - * @sa meta_func::invoke - * - * @param id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @param sz Number of parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ - meta_any invoke(const id_type id, meta_handle instance, meta_any * const args, const size_type sz) const { - const internal::meta_func_node* candidate{}; - size_type extent{sz + 1u}; - bool ambiguous{}; - - for(auto *it = internal::meta_visit<&node_type::func>([id, sz](const auto *curr) { return curr->id == id && curr->arity == sz; }, node); it && it->id == id && it->arity == sz; it = it->next) { - size_type direct{}; - size_type ext{}; - - for(size_type next{}; next < sz && next == (direct + ext); ++next) { - const auto type = args[next].type(); - const auto req = it->arg(next).info(); - type.info() == req ? ++direct : (ext += can_cast_or_convert(type.node, req)); - } - - if((direct + ext) == sz) { - if(ext < extent) { - candidate = it; - extent = ext; - ambiguous = false; - } else if(ext == extent) { - ambiguous = true; - } - } - } - - return (candidate && !ambiguous) ? candidate->invoke(std::move(instance), args) : meta_any{}; - } - - /** - * @copybrief invoke - * - * @sa invoke - * - * @param id Unique identifier. - * @tparam Args Types of arguments to use to invoke the function. - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the new instance, if any. - */ - template - meta_any invoke(const id_type id, meta_handle instance, Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return invoke(id, std::move(instance), arguments, sizeof...(Args)); - } - - /** - * @brief Sets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the setter results in an undefined - * behavior.
- * The type of the value must be such that a cast or conversion to the type - * of the variable is possible. Otherwise, invoking the setter does nothing. - * - * @tparam Type Type of value to assign. - * @param id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - bool set(const id_type id, meta_handle instance, Type &&value) const { - auto const candidate = data(id); - return candidate ? candidate.set(std::move(instance), std::forward(value)) : false; - } - - /** - * @brief Gets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the getter results in an undefined behavior. - * - * @param id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @return A meta any containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(const id_type id, meta_handle instance) const { - auto const candidate = data(id); - return candidate ? candidate.get(std::move(instance)) : meta_any{}; - } - - /** - * @brief Returns a range to use to visit top-level properties. - * @return An iterable range to use to visit top-level properties. - */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * - * Properties of the base classes will also be visited, if any. - * - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - - /** - * @brief Checks if two objects refer to the same type. - * @param other The object with which to compare. - * @return True if the objects refer to the same type, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_type &other) const ENTT_NOEXCEPT { - return (!node && !other.node) || (node && other.node && node->info == other.node->info); - } - - /** - * @brief Resets a type and all its parts. - * - * This function 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 list of searchable types. - */ - void reset() ENTT_NOEXCEPT { - auto** it = internal::meta_context::global(); - - while(*it && *it != node) { - it = &(*it)->next; - } - - if(*it) { - *it = (*it)->next; - } - - const auto unregister_all = y_combinator{ - [](auto &&self, auto **curr, auto... member) { - while(*curr) { - auto *prev = *curr; - (self(&(prev->*member)), ...); - *curr = prev->next; - prev->next = nullptr; - } - } - }; - - unregister_all(&node->prop); - unregister_all(&node->base); - unregister_all(&node->conv); - unregister_all(&node->ctor, &internal::meta_ctor_node::prop); - unregister_all(&node->data, &internal::meta_data_node::prop); - unregister_all(&node->func, &internal::meta_func_node::prop); - - node->id = {}; - node->ctor = node->def_ctor; - node->dtor = nullptr; - } - -private: - node_type *node; -}; - - -/** - * @brief Checks if two objects refer to the same type. - * @param lhs An object, either valid or not. - * @param rhs An object, either valid or not. - * @return False if the objects refer to the same node, true otherwise. - */ -[[nodiscard]] inline bool operator!=(const meta_type &lhs, const meta_type &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -[[nodiscard]] inline meta_type meta_any::type() const ENTT_NOEXCEPT { - return node; -} - - -template -meta_any meta_any::invoke(const id_type id, Args &&... args) const { - return type().invoke(id, *this, std::forward(args)...); -} - - -template -meta_any meta_any::invoke(const id_type id, Args &&... args) { - return type().invoke(id, *this, std::forward(args)...); -} - - -template -bool meta_any::set(const id_type id, Type &&value) { - return type().set(id, *this, std::forward(value)); -} - - -[[nodiscard]] inline meta_any meta_any::get(const id_type id) const { - return type().get(id, *this); -} - - -[[nodiscard]] inline meta_any meta_any::get(const id_type id) { - return type().get(id, *this); -} - - -[[nodiscard]] inline meta_type meta_ctor::parent() const ENTT_NOEXCEPT { - return node->parent; -} - - -[[nodiscard]] inline meta_type meta_ctor::arg(size_type index) const ENTT_NOEXCEPT { - return index < arity() ? node->arg(index) : meta_type{}; -} - - -[[nodiscard]] inline meta_type meta_data::parent() const ENTT_NOEXCEPT { - return node->parent; -} - - -[[nodiscard]] inline meta_type meta_data::type() const ENTT_NOEXCEPT { - return node->type(); -} - - -[[nodiscard]] inline meta_type meta_func::parent() const ENTT_NOEXCEPT { - return node->parent; -} - - -[[nodiscard]] inline meta_type meta_func::ret() const ENTT_NOEXCEPT { - return node->ret(); -} - - -[[nodiscard]] inline meta_type meta_func::arg(size_type index) const ENTT_NOEXCEPT { - return index < arity() ? node->arg(index) : meta_type{}; -} - - -/*! @brief Opaque iterator for sequence containers. */ -class meta_sequence_container::meta_iterator { - /*! @brief A sequence container can access the underlying iterator. */ - friend class meta_sequence_container; - - enum class operation { INCR, DEREF }; - - using vtable_type = void(const operation, const any &, void *); - - template - static void basic_vtable(const operation op, const any &from, void *to) { - switch(op) { - case operation::INCR: - ++any_cast(const_cast(from)); - break; - case operation::DEREF: - static_cast(to)->emplace::reference>(*any_cast(from)); - break; - } - } - -public: - /*! @brief Signed integer type. */ - using difference_type = std::ptrdiff_t; - /*! @brief Type of elements returned by the iterator. */ - using value_type = meta_any; - /*! @brief Pointer type, `void` on purpose. */ - using pointer = void; - /*! @brief Reference type, it is **not** an actual reference. */ - using reference = value_type; - /*! @brief Iterator category. */ - using iterator_category = std::input_iterator_tag; - - /*! @brief Default constructor. */ - meta_iterator() ENTT_NOEXCEPT = default; - - /** - * @brief Constructs a meta iterator from a given iterator. - * @tparam It Type of actual iterator with which to build the meta iterator. - * @param iter The actual iterator with which to build the meta iterator. - */ - template - meta_iterator(It iter) - : vtable{&basic_vtable}, - handle{std::move(iter)} - {} - - /*! @brief Pre-increment operator. @return This iterator. */ - meta_iterator & operator++() ENTT_NOEXCEPT { - return vtable(operation::INCR, handle, nullptr), *this; - } - - /*! @brief Post-increment operator. @return This iterator. */ - meta_iterator operator++(int) ENTT_NOEXCEPT { - meta_iterator orig = *this; - return ++(*this), orig; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return True if the iterators refer to the same element, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT { - return handle == other.handle; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return False if the iterators refer to the same element, true otherwise. - */ - [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - /** - * @brief Indirection operator. - * @return The element to which the iterator points. - */ - [[nodiscard]] reference operator*() const { - meta_any other; - vtable(operation::DEREF, handle, &other); - return other; - } - - /** - * @brief Returns false if an iterator is invalid, true otherwise. - * @return False if the iterator is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(handle); - } - -private: - vtable_type *vtable{}; - any handle{}; -}; - - -template -struct meta_sequence_container::meta_sequence_container_proxy { - using traits_type = meta_sequence_container_traits; - - [[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); - } - - [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT { - return traits_type::size(any_cast(container)); - } - - [[nodiscard]] static bool resize(any &container, size_type sz) { - auto * const cont = any_cast(&container); - return cont ? traits_type::resize(*cont, sz) : false; - } - - [[nodiscard]] static bool clear(any &container) { - auto * const cont = any_cast(&container); - return cont ? traits_type::clear(*cont) : false; - } - - [[nodiscard]] static iterator begin(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{traits_type::begin(*cont)}; - } - - return iterator{traits_type::cbegin(any_cast(container))}; - } - - [[nodiscard]] static iterator end(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{traits_type::end(*cont)}; - } - - return iterator{traits_type::cend(any_cast(container))}; - } - - [[nodiscard]] static std::pair insert(any &container, iterator it, meta_any &value) { - if(auto * const cont = any_cast(&container); cont) { - // this abomination is necessary because only on macos value_type and const_reference are different types for std::vector - if(value.allow_cast() || value.allow_cast()) { - const auto *element = value.try_cast>(); - auto ret = traits_type::insert(*cont, any_cast(it.handle), element ? *element : value.cast()); - return { iterator{std::move(ret.first)}, ret.second }; - } - } - - return {}; - } - - [[nodiscard]] static std::pair erase(any &container, iterator it) { - if(auto * const cont = any_cast(&container); cont) { - auto ret = traits_type::erase(*cont, any_cast(it.handle)); - return { iterator{std::move(ret.first)}, ret.second }; - } - - return {}; - } - - [[nodiscard]] static meta_any get(any &container, size_type pos) { - if(auto * const cont = any_cast(&container); cont) { - return meta_any{std::in_place_type, traits_type::get(*cont, pos)}; - } - - return meta_any{std::in_place_type, traits_type::cget(any_cast(container), pos)}; - } -}; - - -/** - * @brief Returns the meta value type of a container. - * @return The meta value type of the container. - */ -[[nodiscard]] inline meta_type meta_sequence_container::value_type() const ENTT_NOEXCEPT { - return value_type_fn(); -} - - -/** - * @brief Returns the size of a container. - * @return The size of the container. - */ -[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const ENTT_NOEXCEPT { - return size_fn(storage); -} - - -/** - * @brief Resizes a container to contain a given number of elements. - * @param sz The new size of the container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::resize(size_type sz) { - return resize_fn(storage, sz); -} - - -/** - * @brief Clears the content of a container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::clear() { - return clear_fn(storage); -} - - -/** - * @brief Returns an iterator to the first element of a container. - * @return An iterator to the first element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() { - return begin_fn(storage); -} - - -/** - * @brief Returns an iterator that is past the last element of a container. - * @return An iterator that is past the last element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() { - return end_fn(storage); -} - - -/** - * @brief Inserts an element at a specified location of a container. - * @param it Iterator before which the element will be inserted. - * @param value Element value to insert. - * @return A pair consisting of an iterator to the inserted element (in case of - * success) and a bool denoting whether the insertion took place. - */ -inline std::pair meta_sequence_container::insert(iterator it, meta_any value) { - return insert_fn(storage, it, value); -} - - -/** - * @brief Removes a given element from a container. - * @param it Iterator to the element to remove. - * @return A pair consisting of an iterator following the last removed element - * (in case of success) and a bool denoting whether the insertion took place. - */ -inline std::pair meta_sequence_container::erase(iterator it) { - return erase_fn(storage, it); -} - - -/** - * @brief Returns a reference to the element at a given location of a container - * (no bounds checking is performed). - * @param pos The position of the element to return. - * @return A reference to the requested element properly wrapped. - */ -[[nodiscard]] inline meta_any meta_sequence_container::operator[](size_type pos) { - return get_fn(storage, pos); -} - - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_sequence_container::operator bool() const ENTT_NOEXCEPT { - return static_cast(storage); -} - - -/*! @brief Opaque iterator for associative containers. */ -class meta_associative_container::meta_iterator { - enum operation { INCR, DEREF }; - - using vtable_type = void(const operation, const any &, void *); - - template - static void basic_vtable(const operation op, const any &from, void *to) { - switch(op) { - case operation::INCR: - ++any_cast(const_cast(from)); - break; - case operation::DEREF: - if constexpr(KeyOnly) { - static_cast *>(to)->first = std::cref(*any_cast(from)); - } else { - *static_cast *>(to) = std::make_pair(std::cref(any_cast(from)->first), std::ref(any_cast(from)->second)); - } - break; - } - } - -public: - /*! @brief Signed integer type. */ - using difference_type = std::ptrdiff_t; - /*! @brief Type of elements returned by the iterator. */ - using value_type = std::pair; - /*! @brief Pointer type, `void` on purpose. */ - using pointer = void; - /*! @brief Reference type, it is **not** an actual reference. */ - using reference = value_type; - /*! @brief Iterator category. */ - using iterator_category = std::input_iterator_tag; - - /*! @brief Default constructor. */ - meta_iterator() ENTT_NOEXCEPT = default; - - /** - * @brief Constructs an meta iterator from a given iterator. - * @tparam KeyOnly True if the container is also key-only, false otherwise. - * @tparam It Type of actual iterator with which to build the meta iterator. - * @param iter The actual iterator with which to build the meta iterator. - */ - template - meta_iterator(std::integral_constant, It iter) - : vtable{&basic_vtable}, - handle{std::move(iter)} - {} - - /*! @brief Pre-increment operator. @return This iterator. */ - meta_iterator & operator++() ENTT_NOEXCEPT { - return vtable(operation::INCR, handle, nullptr), *this; - } - - /*! @brief Post-increment operator. @return This iterator. */ - meta_iterator operator++(int) ENTT_NOEXCEPT { - meta_iterator orig = *this; - return ++(*this), orig; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return True if the iterators refer to the same element, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT { - return handle == other.handle; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return False if the iterators refer to the same element, true otherwise. - */ - [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - /** - * @brief Indirection operator. - * @return The element to which the iterator points. - */ - [[nodiscard]] reference operator*() const { - reference other; - vtable(operation::DEREF, handle, &other); - return other; - } - - /** - * @brief Returns false if an iterator is invalid, true otherwise. - * @return False if the iterator is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(handle); - } - -private: - vtable_type *vtable{}; - any handle{}; -}; - - -template -struct meta_associative_container::meta_associative_container_proxy { - using traits_type = meta_associative_container_traits; - - [[nodiscard]] static meta_type key_type() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); - } - - [[nodiscard]] static meta_type mapped_type() ENTT_NOEXCEPT { - if constexpr(is_key_only_meta_associative_container_v) { - return meta_type{}; - } else { - return internal::meta_info::resolve(); - } - } - - [[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); - } - - [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT { - return traits_type::size(any_cast(container)); - } - - [[nodiscard]] static bool clear(any &container) { - auto * const cont = any_cast(&container); - return cont ? traits_type::clear(*cont) : false; - } - - [[nodiscard]] static iterator begin(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{is_key_only_meta_associative_container{}, traits_type::begin(*cont)}; - } - - return iterator{is_key_only_meta_associative_container{}, traits_type::cbegin(any_cast(container))}; - } - - [[nodiscard]] static iterator end(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{is_key_only_meta_associative_container{}, traits_type::end(*cont)}; - } - - return iterator{is_key_only_meta_associative_container{}, traits_type::cend(any_cast(container))}; - } - - [[nodiscard]] static bool insert(any &container, meta_any &key, meta_any &value) { - if(auto * const cont = any_cast(&container); cont && key.allow_cast()) { - if constexpr(is_key_only_meta_associative_container_v) { - return traits_type::insert(*cont, key.cast()); - } else { - if(value.allow_cast()) { - return traits_type::insert(*cont, key.cast(), value.cast()); - } - } - } - - return false; - } - - [[nodiscard]] static bool erase(any &container, meta_any &key) { - if(auto * const cont = any_cast(&container); cont && key.allow_cast()) { - return traits_type::erase(*cont, key.cast()); - } - - return false; - } - - [[nodiscard]] static iterator find(any &container, meta_any &key) { - if(key.allow_cast()) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{is_key_only_meta_associative_container{}, traits_type::find(*cont, key.cast())}; - } - - return iterator{is_key_only_meta_associative_container{}, traits_type::cfind(any_cast(container), key.cast())}; - } - - return {}; - } -}; - - -/** - * @brief Returns true if a container is also key-only, false otherwise. - * @return True if the associative container is also key-only, false otherwise. - */ -[[nodiscard]] inline bool meta_associative_container::key_only() const ENTT_NOEXCEPT { - return key_only_container; -} - - -/** - * @brief Returns the meta key type of a container. - * @return The meta key type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::key_type() const ENTT_NOEXCEPT { - return key_type_fn(); -} - - -/** - * @brief Returns the meta mapped type of a container. - * @return The meta mapped type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::mapped_type() const ENTT_NOEXCEPT { - return mapped_type_fn(); -} - - -/*! @copydoc meta_sequence_container::value_type */ -[[nodiscard]] inline meta_type meta_associative_container::value_type() const ENTT_NOEXCEPT { - return value_type_fn(); -} - - -/*! @copydoc meta_sequence_container::size */ -[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const ENTT_NOEXCEPT { - return size_fn(storage); -} - - -/*! @copydoc meta_sequence_container::clear */ -inline bool meta_associative_container::clear() { - return clear_fn(storage); -} - - -/*! @copydoc meta_sequence_container::begin */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() { - return begin_fn(storage); -} - - -/*! @copydoc meta_sequence_container::end */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() { - return end_fn(storage); -} - - -/** - * @brief Inserts an element (a key/value pair) into a container. - * @param key The key of the element to insert. - * @param value The value of the element to insert. - * @return A bool denoting whether the insertion took place. - */ -inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { - return insert_fn(storage, key, value); -} - - -/** - * @brief Removes the specified element from a container. - * @param key The key of the element to remove. - * @return A bool denoting whether the removal took place. - */ -inline bool meta_associative_container::erase(meta_any key) { - return erase_fn(storage, key); -} - - -/** - * @brief Returns an iterator to the element with a given key, if any. - * @param key The key of the element to search. - * @return An iterator to the element with the given key, if any. - */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) { - return find_fn(storage, key); -} - - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_associative_container::operator bool() const ENTT_NOEXCEPT { - return static_cast(storage); -} - - -} - - -#endif - -// #include "node.hpp" - -// #include "policy.hpp" -#ifndef ENTT_META_POLICY_HPP -#define ENTT_META_POLICY_HPP - - -namespace entt { - - -/*! @brief Empty class type used to request the _as ref_ policy. */ -struct as_ref_t {}; - - -/*! @brief Empty class type used to request the _as cref_ policy. */ -struct as_cref_t {}; - - -/*! @brief Empty class type used to request the _as-is_ policy. */ -struct as_is_t {}; - - -/*! @brief Empty class type used to request the _as void_ policy. */ -struct as_void_t {}; - - -} - - -#endif - -// #include "utility.hpp" -#ifndef ENTT_META_UTILITY_HPP -#define ENTT_META_UTILITY_HPP - - -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "meta.hpp" - -// #include "node.hpp" - -// #include "policy.hpp" - - - -namespace entt { - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct meta_function_descriptor; - - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Class Actual owner of the member function. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor { - /*! @brief Meta function return type. */ - using return_type = Ret; - /*! @brief Meta function arguments. */ - using args_type = std::conditional_t, type_list, type_list>; - - /*! @brief True if the meta function is const, false otherwise. */ - static constexpr auto is_const = true; - /*! @brief True if the meta function is static, false otherwise. */ - static constexpr auto is_static = !std::is_same_v; -}; - - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Class Actual owner of the member function. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor { - /*! @brief Meta function return type. */ - using return_type = Ret; - /*! @brief Meta function arguments. */ - using args_type = std::conditional_t, type_list, type_list>; - - /*! @brief True if the meta function is const, false otherwise. */ - static constexpr auto is_const = false; - /*! @brief True if the meta function is static, false otherwise. */ - static constexpr auto is_static = !std::is_same_v; -}; - - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor { - /*! @brief Meta function return type. */ - using return_type = Ret; - /*! @brief Meta function arguments. */ - using args_type = type_list; - - /*! @brief True if the meta function is const, false otherwise. */ - static constexpr auto is_const = false; - /*! @brief True if the meta function is static, false otherwise. */ - static constexpr auto is_static = true; -}; - - -/** - * @brief Meta function helper. - * - * Converts a function type to be associated with a reflected type into its meta - * function descriptor. - * - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Candidate The actual function to associate with the reflected type. - */ -template -class meta_function_helper { - template - static constexpr meta_function_descriptor get_rid_of_noexcept(Ret(Class:: *)(Args...) const); - - template - static constexpr meta_function_descriptor get_rid_of_noexcept(Ret(Class:: *)(Args...)); - - template - static constexpr meta_function_descriptor get_rid_of_noexcept(Ret(*)(Args...)); - -public: - /*! @brief The meta function descriptor of the given function. */ - using type = decltype(get_rid_of_noexcept(std::declval())); -}; - - -/** - * @brief Helper type. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Candidate The actual function to associate with the reflected type. - */ -template -using meta_function_helper_t = typename meta_function_helper::type; - - -/** - * @brief Returns the meta type of the i-th element of a list of arguments. - * @tparam Args Actual types of arguments. - * @return The meta type of the i-th element of the list of arguments. - */ -template -[[nodiscard]] static meta_type meta_arg(type_list, const std::size_t index) ENTT_NOEXCEPT { - return internal::meta_arg_node(type_list{}, index); -} - - -/** - * @brief Constructs an instance given a list of erased parameters, if possible. - * @tparam Type Actual type of the instance to construct. - * @tparam Args Types of arguments expected. - * @tparam Index Indexes to use to extract erased arguments from their list. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ -template -[[nodiscard]] meta_any meta_construct(meta_any * const args, std::index_sequence) { - if(((args+Index)->allow_cast() && ...)) { - return Type{(args+Index)->cast()...}; - } - - return {}; -} - - -/** - * @brief Sets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to set. - * @param instance An opaque instance of the underlying type, if required. - * @param value Parameter to use to set the variable. - * @return True in case of success, false otherwise. - */ -template -[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) { - if constexpr(!std::is_same_v && !std::is_same_v) { - if constexpr(std::is_function_v>> || std::is_member_function_pointer_v) { - using descriptor = meta_function_helper_t; - using data_type = type_list_element_t, typename descriptor::args_type>; - - if(auto * const clazz = instance->try_cast(); clazz) { - if(value.allow_cast()) { - std::invoke(Data, *clazz, value.cast()); - return true; - } - } - } else if constexpr(std::is_member_object_pointer_v) { - using data_type = std::remove_reference_t().*Data)>; - - if constexpr(!std::is_array_v && !std::is_const_v) { - if(auto * const clazz = instance->try_cast(); clazz) { - if(value.allow_cast()) { - std::invoke(Data, clazz) = value.cast(); - return true; - } - } - } - } else { - using data_type = std::remove_reference_t; - - if constexpr(!std::is_array_v && !std::is_const_v) { - if(value.allow_cast()) { - *Data = value.cast(); - return true; - } - } - } - } - - return false; -} - - -/** - * @brief Gets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to get. - * @tparam Policy Optional policy (no policy set by default). - * @param instance An opaque instance of the underlying type, if required. - * @return A meta any containing the value of the underlying variable. - */ -template -[[nodiscard]] meta_any meta_getter([[maybe_unused]] meta_handle instance) { - [[maybe_unused]] auto dispatch = [](auto &&value) { - if constexpr(std::is_same_v) { - return meta_any{std::in_place_type, std::forward(value)}; - } else if constexpr(std::is_same_v) { - return meta_any{std::reference_wrapper{std::forward(value)}}; - } else if constexpr(std::is_same_v) { - return meta_any{std::cref(std::forward(value))}; - } else { - static_assert(std::is_same_v, "Policy not supported"); - return meta_any{std::forward(value)}; - } - }; - - if constexpr(std::is_function_v>> || std::is_member_function_pointer_v) { - auto * const clazz = instance->try_cast, const Type, Type>>(); - return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{}; - } else if constexpr(std::is_member_object_pointer_v) { - if constexpr(std::is_array_v().*Data)>>>) { - return meta_any{}; - } else { - if(auto * clazz = instance->try_cast(); clazz) { - return dispatch(std::invoke(Data, *clazz)); - } else { - auto * fallback = instance->try_cast(); - return fallback ? dispatch(std::invoke(Data, *fallback)) : meta_any{}; - } - } - } else if constexpr(std::is_pointer_v) { - if constexpr(std::is_array_v>) { - return meta_any{}; - } else { - return dispatch(*Data); - } - } else { - return dispatch(Data); - } -} - - -/** - * @brief Invokes a function given a list of erased parameters, if possible. - * @tparam Type Reflected type to which the function is associated. - * @tparam Candidate The actual function to invoke. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Index Indexes to use to extract erased arguments from their list. - * @param instance An opaque instance of the underlying type, if required. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence) { - using descriptor = meta_function_helper_t; - - auto dispatch = [](auto &&... params) { - if constexpr(std::is_void_v> || std::is_same_v) { - std::invoke(Candidate, std::forward(params)...); - return meta_any{std::in_place_type}; - } else if constexpr(std::is_same_v) { - return meta_any{std::reference_wrapper{std::invoke(Candidate, std::forward(params)...)}}; - } else if constexpr(std::is_same_v) { - return meta_any{std::cref(std::invoke(Candidate, std::forward(params)...))}; - } else { - static_assert(std::is_same_v, "Policy not supported"); - return meta_any{std::invoke(Candidate, std::forward(params)...)}; - } - }; - - if constexpr(std::is_invocable_v...>) { - if(const auto * const clazz = instance->try_cast(); clazz && ((args+Index)->allow_cast>() && ...)) { - return dispatch(*clazz, (args+Index)->cast>()...); - } - } else if constexpr(std::is_invocable_v...>) { - if(auto * const clazz = instance->try_cast(); clazz && ((args+Index)->allow_cast>() && ...)) { - return dispatch(*clazz, (args+Index)->cast>()...); - } - } else { - if(((args+Index)->allow_cast>() && ...)) { - return dispatch((args+Index)->cast>()...); - } - } - - return meta_any{}; -} - - -} - - -#endif - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] bool find_if(const Node *candidate, const Node *node) ENTT_NOEXCEPT { - return node && (node == candidate || find_if(candidate, node->next)); -} - - -template -[[nodiscard]] bool find_if_not(const Id id, Node *node, const Node *owner) ENTT_NOEXCEPT { - if constexpr(std::is_pointer_v) { - return node && ((*node->id == *id && node != owner) || find_if_not(id, node->next, owner)); - } else { - return node && ((node->id == id && node != owner) || find_if_not(id, node->next, owner)); - } -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @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 -struct meta_factory; - - -/** - * @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 -struct meta_factory: public meta_factory { -private: - 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, meta_any value = {}) { - static meta_any property[2u]{}; - - static internal::meta_prop_node node{ - nullptr, - property[0u], - property[1u] - }; - - entt::meta_any instance{std::forward(key)}; - ENTT_ASSERT(!internal::find_if_not(&instance, *curr, &node)); - property[0u] = std::move(instance); - property[1u] = std::move(value); - - if(!internal::find_if(&node, *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(internal::meta_prop_node **target) ENTT_NOEXCEPT - : 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: - internal::meta_prop_node **curr; -}; - - -/** - * @brief Basic meta factory to be used for reflection purposes. - * @tparam Type Reflected type for which the factory was created. - */ -template -struct meta_factory { - /** - * @brief Makes a meta type _searchable_. - * @param id Optional unique identifier. - * @return An extended meta factory for the given type. - */ - auto type(const id_type id = type_hash::value()) { - auto * const node = internal::meta_info::resolve(); - - ENTT_ASSERT(!internal::find_if_not(id, *internal::meta_context::global(), node)); - node->id = id; - - if(!internal::find_if(node, *internal::meta_context::global())) { - node->next = *internal::meta_context::global(); - *internal::meta_context::global() = node; - } - - return meta_factory{&node->prop}; - } - - /** - * @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 - auto base() ENTT_NOEXCEPT { - static_assert(std::is_base_of_v, "Invalid base type"); - auto * const type = internal::meta_info::resolve(); - - static internal::meta_base_node node{ - type, - nullptr, - &internal::meta_info::resolve, - [](const void *instance) ENTT_NOEXCEPT -> const void * { - return static_cast(static_cast(instance)); - } - }; - - if(!internal::find_if(&node, type->base)) { - node.next = type->base; - type->base = &node; - } - - return meta_factory{}; - } - - /** - * @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 - auto conv() ENTT_NOEXCEPT { - static_assert(std::is_convertible_v, "Could not convert to the required type"); - auto * const type = internal::meta_info::resolve(); - - static internal::meta_conv_node node{ - type, - nullptr, - &internal::meta_info::resolve, - [](const void *instance) -> meta_any { - return static_cast(*static_cast(instance)); - } - }; - - if(!internal::find_if(&node, type->conv)) { - node.next = type->conv; - type->conv = &node; - } - - return meta_factory{}; - } - - /** - * @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() ENTT_NOEXCEPT { - using conv_type = std::invoke_result_t; - auto * const type = internal::meta_info::resolve(); - - static internal::meta_conv_node node{ - type, - nullptr, - &internal::meta_info::resolve, - [](const void *instance) -> meta_any { - return std::invoke(Candidate, *static_cast(instance)); - } - }; - - if(!internal::find_if(&node, type->conv)) { - node.next = type->conv; - type->conv = &node; - } - - return meta_factory{}; - } - - /** - * @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 An extended meta factory for the parent type. - */ - template - auto ctor() ENTT_NOEXCEPT { - using descriptor = meta_function_helper_t; - static_assert(std::is_same_v, Type>, "The function doesn't return an object of the required type"); - auto * const type = internal::meta_info::resolve(); - - static internal::meta_ctor_node node{ - type, - nullptr, - nullptr, - descriptor::args_type::size, - [](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT { - return meta_arg(typename descriptor::args_type{}, index); - }, - [](meta_any * const args) { - return meta_invoke({}, args, std::make_index_sequence{}); - } - }; - - if(!internal::find_if(&node, type->ctor)) { - node.next = type->ctor; - type->ctor = &node; - } - - return meta_factory>{&node.prop}; - } - - /** - * @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 An extended meta factory for the parent type. - */ - template - auto ctor() ENTT_NOEXCEPT { - using descriptor = meta_function_helper_t; - auto * const type = internal::meta_info::resolve(); - - static internal::meta_ctor_node node{ - type, - nullptr, - nullptr, - descriptor::args_type::size, - [](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT { - return meta_arg(typename descriptor::args_type{}, index); - }, - [](meta_any * const args) { - return meta_construct(args, std::make_index_sequence{}); - } - }; - - if(!internal::find_if(&node, type->ctor)) { - node.next = type->ctor; - type->ctor = &node; - } - - return meta_factory{&node.prop}; - } - - /** - * @brief Assigns a meta destructor to a meta type. - * - * Free functions can be assigned to meta types in the role of destructors. - * The signature of the function should identical to the following: - * - * @code{.cpp} - * void(Type &); - * @endcode - * - * 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 - auto dtor() ENTT_NOEXCEPT { - static_assert(std::is_invocable_v, "The function doesn't accept an object of the type provided"); - auto * const type = internal::meta_info::resolve(); - - type->dtor = [](void *instance) { - std::invoke(Func, *static_cast(instance)); - }; - - return meta_factory{}; - } - - /** - * @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 An extended meta factory for the parent type. - */ - template - auto data(const id_type id) ENTT_NOEXCEPT { - if constexpr(std::is_member_object_pointer_v) { - return data(id); - } else { - using data_type = std::remove_pointer_t; - auto * const type = internal::meta_info::resolve(); - - static internal::meta_data_node node{ - {}, - type, - nullptr, - nullptr, - std::is_same_v || std::is_const_v, - true, - &internal::meta_info::resolve, - &meta_setter, - &meta_getter - }; - - ENTT_ASSERT(!internal::find_if_not(id, type->data, &node)); - node.id = id; - - if(!internal::find_if(&node, type->data)) { - node.next = type->data; - type->data = &node; - } - - return meta_factory>{&node.prop}; - } - } - - /** - * @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 An extended meta factory for the parent type. - */ - template - auto data(const id_type id) ENTT_NOEXCEPT { - using underlying_type = std::remove_reference_t>; - auto * const type = internal::meta_info::resolve(); - - static internal::meta_data_node node{ - {}, - type, - nullptr, - nullptr, - std::is_same_v || (std::is_member_object_pointer_v && std::is_const_v), - false, - &internal::meta_info::resolve, - &meta_setter, - &meta_getter - }; - - ENTT_ASSERT(!internal::find_if_not(id, type->data, &node)); - node.id = id; - - if(!internal::find_if(&node, type->data)) { - node.next = type->data; - type->data = &node; - } - - return meta_factory, std::integral_constant>{&node.prop}; - } - - /** - * @brief Assigns a meta funcion 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 An extended meta factory for the parent type. - */ - template - auto func(const id_type id) ENTT_NOEXCEPT { - using descriptor = meta_function_helper_t; - auto * const type = internal::meta_info::resolve(); - - static internal::meta_func_node node{ - {}, - type, - nullptr, - nullptr, - descriptor::args_type::size, - descriptor::is_const, - descriptor::is_static, - &internal::meta_info, void, typename descriptor::return_type>>::resolve, - [](const typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT { - return meta_arg(typename descriptor::args_type{}, index); - }, - [](meta_handle instance, meta_any *args) { - return meta_invoke(std::move(instance), args, std::make_index_sequence{}); - } - }; - - for(auto *it = &type->func; *it; it = &(*it)->next) { - if(*it == &node) { - *it = node.next; - break; - } - } - - internal::meta_func_node **it = &type->func; - for(; *it && (*it)->id != id; it = &(*it)->next); - for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next); - - node.id = id; - node.next = *it; - *it = &node; - - return meta_factory>{&node.prop}; - } -}; - - -/** - * @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() ENTT_NOEXCEPT { - auto * const node = internal::meta_info::resolve(); - // extended meta factory to allow assigning properties to opaque meta types - return meta_factory{&node->prop}; -} - - -} - - -#endif - -// #include "meta/meta.hpp" -#ifndef ENTT_META_META_HPP -#define ENTT_META_META_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/any.hpp" - -// #include "../core/fwd.hpp" - -// #include "../core/utility.hpp" - -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "adl_pointer.hpp" - -// #include "ctx.hpp" - -// #include "node.hpp" - -// #include "range.hpp" - -// #include "type_traits.hpp" - - - -namespace entt { - - -class meta_any; -class meta_type; - - -/*! @brief Proxy object for sequence containers. */ -class meta_sequence_container { - template - struct meta_sequence_container_proxy; - - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; - - /*! @brief Default constructor. */ - meta_sequence_container() ENTT_NOEXCEPT = default; - - /** - * @brief Construct a proxy object for sequence containers. - * @tparam Type Type of container to wrap. - * @param instance The container to wrap. - */ - template - meta_sequence_container(std::in_place_type_t, any instance) ENTT_NOEXCEPT - : value_type_fn{&meta_sequence_container_proxy::value_type}, - size_fn{&meta_sequence_container_proxy::size}, - resize_fn{&meta_sequence_container_proxy::resize}, - clear_fn{&meta_sequence_container_proxy::clear}, - begin_fn{&meta_sequence_container_proxy::begin}, - end_fn{&meta_sequence_container_proxy::end}, - insert_fn{&meta_sequence_container_proxy::insert}, - erase_fn{&meta_sequence_container_proxy::erase}, - get_fn{&meta_sequence_container_proxy::get}, - storage{std::move(instance)} - {} - - [[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT; - inline bool resize(size_type); - inline bool clear(); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline std::pair insert(iterator, meta_any); - inline std::pair erase(iterator); - [[nodiscard]] inline meta_any operator[](size_type); - [[nodiscard]] inline explicit operator bool() const ENTT_NOEXCEPT; - -private: - meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr; - size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr; - bool(* resize_fn)(any &, size_type) = nullptr; - bool(* clear_fn)(any &) = nullptr; - iterator(* begin_fn)(any &) = nullptr; - iterator(* end_fn)(any &) = nullptr; - std::pair(* insert_fn)(any &, iterator, meta_any &) = nullptr; - std::pair(* erase_fn)(any &, iterator) = nullptr; - meta_any(* get_fn)(any &, size_type) = nullptr; - any storage{}; -}; - - -/*! @brief Proxy object for associative containers. */ -class meta_associative_container { - template - struct meta_associative_container_proxy; - - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; - - /*! @brief Default constructor. */ - meta_associative_container() ENTT_NOEXCEPT = default; - - /** - * @brief Construct a proxy object for associative containers. - * @tparam Type Type of container to wrap. - * @param instance The container to wrap. - */ - template - meta_associative_container(std::in_place_type_t, any instance) ENTT_NOEXCEPT - : key_only_container{is_key_only_meta_associative_container_v}, - key_type_fn{&meta_associative_container_proxy::key_type}, - mapped_type_fn{&meta_associative_container_proxy::mapped_type}, - value_type_fn{&meta_associative_container_proxy::value_type}, - size_fn{&meta_associative_container_proxy::size}, - clear_fn{&meta_associative_container_proxy::clear}, - begin_fn{&meta_associative_container_proxy::begin}, - end_fn{&meta_associative_container_proxy::end}, - insert_fn{&meta_associative_container_proxy::insert}, - erase_fn{&meta_associative_container_proxy::erase}, - find_fn{&meta_associative_container_proxy::find}, - storage{std::move(instance)} - {} - - [[nodiscard]] inline bool key_only() const ENTT_NOEXCEPT; - [[nodiscard]] inline meta_type key_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline meta_type mapped_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline meta_type value_type() const ENTT_NOEXCEPT; - [[nodiscard]] inline size_type size() const ENTT_NOEXCEPT; - inline bool clear(); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline bool insert(meta_any, meta_any); - inline bool erase(meta_any); - [[nodiscard]] inline iterator find(meta_any); - [[nodiscard]] inline explicit operator bool() const ENTT_NOEXCEPT; - -private: - bool key_only_container{}; - meta_type(* key_type_fn)() ENTT_NOEXCEPT = nullptr; - meta_type(* mapped_type_fn)() ENTT_NOEXCEPT = nullptr; - meta_type(* value_type_fn)() ENTT_NOEXCEPT = nullptr; - size_type(* size_fn)(const any &) ENTT_NOEXCEPT = nullptr; - bool(* clear_fn)(any &) = nullptr; - iterator(* begin_fn)(any &) = nullptr; - iterator(* end_fn)(any &) = nullptr; - bool(* insert_fn)(any &, meta_any &, meta_any &) = nullptr; - bool(* erase_fn)(any &, meta_any &) = nullptr; - iterator(* find_fn)(any &, meta_any &) = nullptr; - any storage{}; -}; - - -/*! @brief Opaque wrapper for values of any type. */ -class meta_any { - enum class operation { DTOR, REF, CREF, DEREF, CDEREF, SEQ, CSEQ, ASSOC, CASSOC }; - - using vtable_type = void(const operation, const any &, void *); - - template - static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) { - if constexpr(!std::is_void_v) { - switch(op) { - case operation::DTOR: - if constexpr(!std::is_lvalue_reference_v) { - if(auto *curr = static_cast(to); curr->dtor) { - curr->dtor(const_cast(from).data()); - } - } - break; - case operation::REF: - case operation::CREF: - *static_cast(to) = (op == operation::REF ? meta_any{std::ref(any_cast(const_cast(from)))} : meta_any{std::cref(any_cast &>(from))}); - break; - case operation::DEREF: - case operation::CDEREF: - if constexpr(is_meta_pointer_like_v>) { - using element_type = std::remove_const_t>::element_type>; - - if constexpr(std::is_function_v) { - *static_cast(to) = any_cast>(from); - } else if constexpr(!std::is_same_v) { - using adl_meta_pointer_like_type = adl_meta_pointer_like>; - - if constexpr(std::is_lvalue_reference_v &>()))>) { - auto &&obj = adl_meta_pointer_like_type::dereference(any_cast &>(from)); - *static_cast(to) = (op == operation::DEREF ? meta_any{std::ref(obj)} : meta_any{std::cref(obj)}); - } else { - *static_cast(to) = adl_meta_pointer_like_type::dereference(any_cast &>(from)); - } - } - } - break; - case operation::SEQ: - case operation::CSEQ: - if constexpr(is_complete_v>>) { - *static_cast(to) = { std::in_place_type>, (op == operation::SEQ ? const_cast(from).as_ref() : from.as_ref()) }; - } - break; - case operation::ASSOC: - case operation::CASSOC: - if constexpr(is_complete_v>>) { - *static_cast(to) = { std::in_place_type>, (op == operation::ASSOC ? const_cast(from).as_ref() : from.as_ref()) }; - } - break; - } - } - } - -public: - /*! @brief Default constructor. */ - meta_any() ENTT_NOEXCEPT - : storage{}, - node{}, - vtable{&basic_vtable} - {} - - /** - * @brief Constructs a meta any by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit meta_any(std::in_place_type_t, Args &&... args) - : storage{std::in_place_type, std::forward(args)...}, - node{internal::meta_info::resolve()}, - vtable{&basic_vtable} - {} - - /** - * @brief Constructs a meta any that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - meta_any(std::reference_wrapper value) - : meta_any{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs a meta any from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template, meta_any>>> - meta_any(Type &&value) - : meta_any{std::in_place_type>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - meta_any(const meta_any &other) = default; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - meta_any(meta_any &&other) ENTT_NOEXCEPT - : storage{std::move(other.storage)}, - node{std::exchange(other.node, nullptr)}, - vtable{std::exchange(other.vtable, &basic_vtable)} - {} - - /*! @brief Frees the internal storage, whatever it means. */ - ~meta_any() { - vtable(operation::DTOR, storage, node); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This meta any object. - */ - meta_any & operator=(const meta_any &other) { - std::exchange(vtable, other.vtable)(operation::DTOR, storage, node); - storage = other.storage; - node = other.node; - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This meta any object. - */ - meta_any & operator=(meta_any &&other) { - std::exchange(vtable, std::exchange(other.vtable, &basic_vtable))(operation::DTOR, storage, node); - storage = std::move(other.storage); - node = std::exchange(other.node, nullptr); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This meta any object. - */ - template - meta_any & operator=(std::reference_wrapper value) { - emplace(value.get()); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This meta any object. - */ - template - std::enable_if_t, meta_any>, meta_any &> - operator=(Type &&value) { - emplace>(std::forward(value)); - return *this; - } - - /** - * @brief Returns the type of the underlying object. - * @return The type of the underlying object, if any. - */ - [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT; - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return storage.data(); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return storage.data(); - } - - /** - * @brief Invokes the underlying function, if possible. - * - * @sa meta_func::invoke - * - * @tparam Args Types of arguments to use to invoke the function. - * @param id Unique identifier. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ - template - meta_any invoke(const id_type id, Args &&... args) const; - - /*! @copydoc invoke */ - template - meta_any invoke(const id_type id, Args &&... args); - - /** - * @brief Sets the value of a given variable. - * - * The type of the value must be such that a cast or conversion to the type - * of the variable is possible. Otherwise, invoking the setter does nothing. - * - * @tparam Type Type of value to assign. - * @param id Unique identifier. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - bool set(const id_type id, Type &&value); - - /** - * @brief Gets the value of a given variable. - * @param id Unique identifier. - * @return A meta any containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(const id_type id) const; - - /*! @copydoc get */ - [[nodiscard]] meta_any get(const id_type id); - - /** - * @brief Tries to cast an instance to a given type. - * @tparam Type Type to which to cast the instance. - * @return A (possibly null) pointer to the contained instance. - */ - template - [[nodiscard]] const Type * try_cast() const { - if(node) { - if(const auto info = type_id(); node->info == info) { - return any_cast(&storage); - } else if(const auto *base = internal::meta_visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) { - return static_cast(base->cast(storage.data())); - } - } - - return nullptr; - } - - /*! @copydoc try_cast */ - template - [[nodiscard]] Type * try_cast() { - if(node) { - if(const auto info = type_id(); node->info == info) { - return any_cast(&storage); - } else if(const auto *base = internal::meta_visit<&internal::meta_type_node::base>([info](const auto *curr) { return curr->type()->info == info; }, node); base) { - return static_cast(const_cast *>(base->cast(static_cast &>(storage).data()))); - } - } - - return nullptr; - } - - /** - * @brief Tries to cast an instance to a given type. - * - * The type of the instance must be such that the cast is possible. - * - * @warning - * Attempting to perform an invalid cast results in undefined behavior. - * - * @tparam Type Type to which to cast the instance. - * @return A reference to the contained instance. - */ - template - [[nodiscard]] Type cast() const { - auto * const actual = try_cast>(); - ENTT_ASSERT(actual); - return static_cast(*actual); - } - - /*! @copydoc cast */ - template - [[nodiscard]] Type cast() { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = try_cast>(); - ENTT_ASSERT(instance); - return static_cast(*instance); - } - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return A valid meta any object if there exists a viable conversion, an - * invalid one otherwise. - */ - template - [[nodiscard]] meta_any allow_cast() const { - if(try_cast>() != nullptr) { - return as_ref(); - } else if(node) { - if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id()](const auto *curr) { return curr->type()->info == info; }, node); conv) { - return conv->conv(storage.data()); - } - } - - return {}; - } - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return True if there exists a viable conversion, false otherwise. - */ - template - bool allow_cast() { - // forces const on non-reference types to make them work also with wrappers for const references - if(try_cast>() != nullptr) { - return true; - } else if(node) { - if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id()](const auto *curr) { return curr->type()->info == info; }, node); conv) { - *this = conv->conv(std::as_const(storage).data()); - return true; - } - } - - return false; - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); - storage.emplace(std::forward(args)...); - node = internal::meta_info::resolve(); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); - storage.reset(); - node = nullptr; - } - - /** - * @brief Returns a sequence container proxy. - * @return A sequence container proxy for the underlying object. - */ - [[nodiscard]] meta_sequence_container as_sequence_container() ENTT_NOEXCEPT { - meta_sequence_container proxy; - vtable(operation::SEQ, storage, &proxy); - return proxy; - } - - /*! @copydoc as_sequence_container */ - [[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT { - meta_sequence_container proxy; - vtable(operation::CSEQ, storage, &proxy); - return proxy; - } - - /** - * @brief Returns an associative container proxy. - * @return An associative container proxy for the underlying object. - */ - [[nodiscard]] meta_associative_container as_associative_container() ENTT_NOEXCEPT { - meta_associative_container proxy; - vtable(operation::ASSOC, storage, &proxy); - return proxy; - } - - /*! @copydoc as_associative_container */ - [[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT { - meta_associative_container proxy; - vtable(operation::CASSOC, storage, &proxy); - return proxy; - } - - /** - * @brief Indirection operator for dereferencing opaque objects. - * @return A meta any that shares a reference to an unmanaged object if the - * wrapped element is dereferenceable, an invalid meta any otherwise. - */ - [[nodiscard]] meta_any operator*() ENTT_NOEXCEPT { - meta_any ret{}; - vtable(operation::DEREF, storage, &ret); - return ret; - } - - /*! @copydoc operator* */ - [[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT { - meta_any ret{}; - vtable(operation::CDEREF, storage, &ret); - return ret; - } - - /** - * @brief Returns false if a wrapper is invalid, true otherwise. - * @return False if the wrapper is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - [[nodiscard]] bool operator==(const meta_any &other) const { - return (!node && !other.node) || (node && other.node && node->info == other.node->info && storage == other.storage); - } - - /** - * @brief Aliasing constructor. - * @return A meta any that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any as_ref() ENTT_NOEXCEPT { - meta_any ref{}; - vtable(operation::REF, storage, &ref); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] meta_any as_ref() const ENTT_NOEXCEPT { - meta_any ref{}; - vtable(operation::CREF, storage, &ref); - return ref; - } - -private: - any storage; - internal::meta_type_node *node; - vtable_type *vtable; -}; - - -/** - * @brief Checks if two wrappers differ in their content. - * @param lhs A meta any object, either empty or not. - * @param rhs A meta any object, either empty or not. - * @return True if the two wrappers differ in their content, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const meta_any &lhs, const meta_any &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Opaque pointers to instances of any type. - * - * A handle doesn't perform copies and isn't responsible for the contained - * object. It doesn't prolong the lifetime of the pointed instance.
- * Handles are used to generate references to actual objects when needed. - */ -struct meta_handle { - /*! @brief Default constructor. */ - meta_handle() = default; - - - /*! @brief Default copy constructor, deleted on purpose. */ - meta_handle(const meta_handle &) = delete; - - /*! @brief Default move constructor. */ - meta_handle(meta_handle &&) = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This meta handle. - */ - meta_handle & operator=(const meta_handle &) = delete; - - /** - * @brief Default move assignment operator. - * @return This meta handle. - */ - meta_handle & operator=(meta_handle &&) = default; - - /** - * @brief Creates a handle that points to an unmanaged object. - * @tparam Type Type of object to use to initialize the handle. - * @param value An instance of an object to use to initialize the handle. - */ - template, meta_handle>>> - meta_handle(Type &value) ENTT_NOEXCEPT - : meta_handle{} - { - if constexpr(std::is_same_v, meta_any>) { - any = value.as_ref(); - } else { - any.emplace(value); - } - } - - /** - * @brief Returns false if a handle is invalid, true otherwise. - * @return False if the handle is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(any); - } - - /** - * @brief Access operator for accessing the contained opaque object. - * @return A meta any that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any * operator->() { - return &any; - } - - /*! @copydoc operator-> */ - [[nodiscard]] const meta_any * operator->() const { - return &any; - } - -private: - meta_any any; -}; - - -/*! @brief Opaque wrapper for properties of any type. */ -struct meta_prop { - /*! @brief Node type. */ - using node_type = internal::meta_prop_node; - - /** - * @brief Constructs an instance from a given node. - * @param curr The underlying node with which to construct the instance. - */ - meta_prop(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /** - * @brief Returns the stored key as a const reference. - * @return A meta any containing the key stored with the property. - */ - [[nodiscard]] meta_any key() const { - return node->id.as_ref(); - } - - /** - * @brief Returns the stored value by copy. - * @return A meta any containing the value stored with the property. - */ - [[nodiscard]] meta_any value() const { - return node->value; - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for constructors. */ -struct meta_ctor { - /*! @brief Node type. */ - using node_type = internal::meta_ctor_node; - /*! @brief Unsigned integer type. */ - using size_type = typename node_type::size_type; - - /*! @copydoc meta_prop::meta_prop */ - meta_ctor(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /** - * @brief Returns the type to which an object belongs. - * @return The type to which the object belongs. - */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; - - /** - * @brief Returns the number of arguments accepted by a constructor. - * @return The number of arguments accepted by the constructor. - */ - [[nodiscard]] size_type arity() const ENTT_NOEXCEPT { - return node->arity; - } - - /** - * @brief Returns the type of the i-th argument of a constructor. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a constructor. - */ - [[nodiscard]] meta_type arg(size_type index) const ENTT_NOEXCEPT; - - /** - * @brief Creates an instance of the underlying type, if possible. - * - * Parameters must be such that a cast or conversion to the required types - * is possible. Otherwise, an empty and thus invalid wrapper is returned. - * - * @param args Parameters to use to construct the instance. - * @param sz Number of parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - [[nodiscard]] meta_any invoke(meta_any * const args, const size_type sz) const { - return sz == arity() ? node->invoke(args) : meta_any{}; - } - - /** - * @copybrief invoke - * - * @sa invoke - * - * @tparam Args Types of arguments to use to construct the instance. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - template - [[nodiscard]] meta_any invoke([[maybe_unused]] Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return invoke(arguments, sizeof...(Args)); - } - - /** - * @brief Returns a range to use to visit all properties. - * @return An iterable range to use to visit all properties. - */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for data members. */ -struct meta_data { - /*! @brief Node type. */ - using node_type = internal::meta_data_node; - - /*! @copydoc meta_prop::meta_prop */ - meta_data(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /*! @copydoc meta_type::id */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { - return node->id; - } - - /*! @copydoc meta_ctor::parent */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; - - /** - * @brief Indicates whether a data member is constant or not. - * @return True if the data member is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const ENTT_NOEXCEPT { - return node->is_const; - } - - /** - * @brief Indicates whether a data member is static or not. - * @return True if the data member is static, false otherwise. - */ - [[nodiscard]] bool is_static() const ENTT_NOEXCEPT { - return node->is_static; - } - - /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT; - - /** - * @brief Sets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the setter results in an undefined - * behavior.
- * The type of the value must be such that a cast or conversion to the type - * of the variable is possible. Otherwise, invoking the setter does nothing. - * - * @tparam Type Type of value to assign. - * @param instance An opaque instance of the underlying type. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - bool set(meta_handle instance, Type &&value) const { - return node->set && node->set(std::move(instance), std::forward(value)); - } - - /** - * @brief Gets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the getter results in an undefined behavior. - * - * @param instance An opaque instance of the underlying type. - * @return A meta any containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(meta_handle instance) const { - return node->get(std::move(instance)); - } - - /*! @copydoc meta_ctor::prop */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for member functions. */ -struct meta_func { - /*! @brief Node type. */ - using node_type = internal::meta_func_node; - /*! @brief Unsigned integer type. */ - using size_type = typename node_type::size_type; - - /*! @copydoc meta_prop::meta_prop */ - meta_func(const node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /*! @copydoc meta_type::id */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { - return node->id; - } - - /*! @copydoc meta_ctor::parent */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; - - /** - * @brief Returns the number of arguments accepted by a member function. - * @return The number of arguments accepted by the member function. - */ - [[nodiscard]] size_type arity() const ENTT_NOEXCEPT { - return node->arity; - } - - /** - * @brief Indicates whether a member function is constant or not. - * @return True if the member function is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const ENTT_NOEXCEPT { - return node->is_const; - } - - /** - * @brief Indicates whether a member function is static or not. - * @return True if the member function is static, false otherwise. - */ - [[nodiscard]] bool is_static() const ENTT_NOEXCEPT { - return node->is_static; - } - - /** - * @brief Returns the return type of a member function. - * @return The return type of the member function. - */ - [[nodiscard]] inline meta_type ret() const ENTT_NOEXCEPT; - - /** - * @brief Returns the type of the i-th argument of a member function. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a member function. - */ - [[nodiscard]] inline meta_type arg(size_type index) const ENTT_NOEXCEPT; - - /** - * @brief Invokes the underlying function, if possible. - * - * To invoke a member function, the parameters must be such that a cast or - * conversion to the required types is possible. Otherwise, an empty and - * thus invalid wrapper is returned.
- * It must be possible to cast the instance to the parent type of the member - * function. Otherwise, invoking the underlying function results in an - * undefined behavior. - * - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @param sz Number of parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ - meta_any invoke(meta_handle instance, meta_any * const args, const size_type sz) const { - return sz == arity() ? node->invoke(std::move(instance), args) : meta_any{}; - } - - /** - * @copybrief invoke - * - * @sa invoke - * - * @tparam Args Types of arguments to use to invoke the function. - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the new instance, if any. - */ - template - meta_any invoke(meta_handle instance, Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return invoke(std::move(instance), arguments, sizeof...(Args)); - } - - /*! @copydoc meta_ctor::prop */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - -private: - const node_type *node; -}; - - -/*! @brief Opaque wrapper for types. */ -class meta_type { - static bool can_cast_or_convert(const internal::meta_type_node *type, const type_info info) ENTT_NOEXCEPT { - if(type->info == info) { - return true; - } - - for(const auto *curr = type->conv; curr; curr = curr->next) { - if(curr->type()->info == info) { - return true; - } - } - - for(const auto *curr = type->base; curr; curr = curr->next) { - if(auto *target = curr->type(); can_cast_or_convert(target, info)) { - return true; - } - } - - return false; - } - - template - [[nodiscard]] static const internal::meta_ctor_node * ctor(const internal::meta_ctor_node *curr, std::index_sequence) { - for(; curr; curr = curr->next) { - if(curr->arity == sizeof...(Args) && (can_cast_or_convert(internal::meta_info::resolve(), curr->arg(Index).info()) && ...)) { - return curr; - } - } - - return nullptr; - } - -public: - /*! @brief Node type. */ - using node_type = internal::meta_type_node; - /*! @brief Node type. */ - using base_node_type = internal::meta_base_node; - /*! @brief Unsigned integer type. */ - using size_type = typename node_type::size_type; - - /*! @copydoc meta_prop::meta_prop */ - meta_type(node_type *curr = nullptr) ENTT_NOEXCEPT - : node{curr} - {} - - /** - * @brief Constructs an instance from a given base node. - * @param curr The base node with which to construct the instance. - */ - meta_type(base_node_type *curr) ENTT_NOEXCEPT - : node{curr ? curr->type() : nullptr} - {} - - /** - * @brief Returns the type info object of the underlying type. - * @return The type info object of the underlying type. - */ - [[nodiscard]] type_info info() const ENTT_NOEXCEPT { - return node->info; - } - - /** - * @brief Returns the identifier assigned to a type. - * @return The identifier assigned to the type. - */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { - return node->id; - } - - /** - * @brief Returns the size of the underlying type if known. - * @return The size of the underlying type if known, 0 otherwise. - */ - [[nodiscard]] size_type size_of() const ENTT_NOEXCEPT { - return node->size_of; - } - - /** - * @brief Checks whether a type refers to void or not. - * @return True if the underlying type is void, false otherwise. - */ - [[nodiscard]] bool is_void() const ENTT_NOEXCEPT { - return node->is_void; - } - - /** - * @brief Checks whether a type refers to an integral type or not. - * @return True if the underlying type is an integral type, false otherwise. - */ - [[nodiscard]] bool is_integral() const ENTT_NOEXCEPT { - return node->is_integral; - } - - /** - * @brief Checks whether a type refers to a floating-point type or not. - * @return True if the underlying type is a floating-point type, false - * otherwise. - */ - [[nodiscard]] bool is_floating_point() const ENTT_NOEXCEPT { - return node->is_floating_point; - } - - /** - * @brief Checks whether a type refers to an array type or not. - * @return True if the underlying type is an array type, false otherwise. - */ - [[nodiscard]] bool is_array() const ENTT_NOEXCEPT { - return node->is_array; - } - - /** - * @brief Checks whether a type refers to an enum or not. - * @return True if the underlying type is an enum, false otherwise. - */ - [[nodiscard]] bool is_enum() const ENTT_NOEXCEPT { - return node->is_enum; - } - - /** - * @brief Checks whether a type refers to an union or not. - * @return True if the underlying type is an union, false otherwise. - */ - [[nodiscard]] bool is_union() const ENTT_NOEXCEPT { - return node->is_union; - } - - /** - * @brief Checks whether a type refers to a class or not. - * @return True if the underlying type is a class, false otherwise. - */ - [[nodiscard]] bool is_class() const ENTT_NOEXCEPT { - return node->is_class; - } - - /** - * @brief Checks whether a type refers to a pointer or not. - * @return True if the underlying type is a pointer, false otherwise. - */ - [[nodiscard]] bool is_pointer() const ENTT_NOEXCEPT { - return node->is_pointer; - } - - /** - * @brief Checks whether a type refers to a function pointer or not. - * @return True if the underlying type is a function pointer, false - * otherwise. - */ - [[nodiscard]] bool is_function_pointer() const ENTT_NOEXCEPT { - return node->is_function_pointer; - } - - /** - * @brief Checks whether a type refers to a pointer to data member or not. - * @return True if the underlying type is a pointer to data member, false - * otherwise. - */ - [[nodiscard]] bool is_member_object_pointer() const ENTT_NOEXCEPT { - return node->is_member_object_pointer; - } - - /** - * @brief Checks whether a type refers to a pointer to member function or - * not. - * @return True if the underlying type is a pointer to member function, - * false otherwise. - */ - [[nodiscard]] bool is_member_function_pointer() const ENTT_NOEXCEPT { - return node->is_member_function_pointer; - } - - /** - * @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_pointer_like() const ENTT_NOEXCEPT { - return node->is_pointer_like; - } - - /** - * @brief Checks whether a type refers to a sequence container or not. - * @return True if the type is a sequence container, false otherwise. - */ - [[nodiscard]] bool is_sequence_container() const ENTT_NOEXCEPT { - return node->is_sequence_container; - } - - /** - * @brief Checks whether a type refers to an associative container or not. - * @return True if the type is an associative container, false otherwise. - */ - [[nodiscard]] bool is_associative_container() const ENTT_NOEXCEPT { - return node->is_associative_container; - } - - /** - * @brief Checks whether a type refers to a recognized class template - * specialization or not. - * @return True if the type is a recognized class template specialization, - * false otherwise. - */ - [[nodiscard]] bool is_template_specialization() const ENTT_NOEXCEPT { - return node->template_info.is_template_specialization; - } - - /** - * @brief Returns the number of template arguments, if any. - * @return The number of template arguments, if any. - */ - [[nodiscard]] size_type template_arity() const ENTT_NOEXCEPT { - return node->template_info.arity; - } - - /** - * @brief Returns a tag for the class template of the underlying type. - * - * @sa meta_class_template_tag - * - * @return The tag for the class template of the underlying type. - */ - [[nodiscard]] inline meta_type template_type() const ENTT_NOEXCEPT { - return is_template_specialization() ? node->template_info.type() : meta_type{}; - } - - /** - * @brief Returns the type of the i-th template argument of a type. - * @param index Index of the template argument of which to return the type. - * @return The type of the i-th template argument of a type. - */ - [[nodiscard]] inline meta_type template_arg(size_type index) const ENTT_NOEXCEPT { - return index < template_arity() ? node->template_info.arg(index) : meta_type{}; - } - - /** - * @brief Provides the number of dimensions of an array type. - * @return The number of dimensions in case of array types, 0 otherwise. - */ - [[nodiscard]] size_type rank() const ENTT_NOEXCEPT { - return node->rank; - } - - /** - * @brief The number of elements along the given dimension of an array type. - * @param dim The dimension of which to return the number of elements. - * @return The number of elements along the given dimension in case of array - * types, 0 otherwise. - */ - [[nodiscard]] size_type extent(size_type dim = {}) const ENTT_NOEXCEPT { - return node->extent(dim); - } - - /** - * @brief Provides the type for which the pointer is defined. - * @return The type for which the pointer is defined or this type if it - * doesn't refer to a pointer type. - */ - [[nodiscard]] meta_type remove_pointer() const ENTT_NOEXCEPT { - return node->remove_pointer(); - } - - /** - * @brief Provides the type for which the array is defined. - * @return The type for which the array is defined or this type if it - * doesn't refer to an array type. - */ - [[nodiscard]] meta_type remove_extent() const ENTT_NOEXCEPT { - return node->remove_extent(); - } - - /** - * @brief Returns a range to use to visit top-level base meta types. - * @return An iterable range to use to visit top-level base meta types. - */ - [[nodiscard]] meta_range base() const ENTT_NOEXCEPT { - return node->base; - } - - /** - * @brief Returns the base meta type associated with a given identifier. - * @param id Unique identifier. - * @return The base meta type associated with the given identifier, if any. - */ - [[nodiscard]] meta_type base(const id_type id) const { - return internal::meta_visit<&node_type::base>([id](const auto *curr) { return curr->type()->id == id; }, node); - } - - /** - * @brief Returns a range to use to visit top-level constructors. - * @return An iterable range to use to visit top-level constructors. - */ - [[nodiscard]] meta_range ctor() const ENTT_NOEXCEPT { - return node->ctor; - } - - /** - * @brief Returns a constructor for a given list of types of arguments. - * @tparam Args Constructor arguments. - * @return The requested constructor, if any. - */ - template - [[nodiscard]] meta_ctor ctor() const { - return ctor(node->ctor, std::make_index_sequence{}); - } - - /** - * @brief Returns a range to use to visit top-level data. - * @return An iterable range to use to visit top-level data. - */ - [[nodiscard]] meta_range data() const ENTT_NOEXCEPT { - return node->data; - } - - /** - * @brief Returns the data associated with a given identifier. - * - * The data of the base classes will also be visited, if any. - * - * @param id Unique identifier. - * @return The data associated with the given identifier, if any. - */ - [[nodiscard]] meta_data data(const id_type id) const { - return internal::meta_visit<&node_type::data>([id](const auto *curr) { return curr->id == id; }, node); - } - - /** - * @brief Returns a range to use to visit top-level functions. - * @return An iterable range to use to visit top-level functions. - */ - [[nodiscard]] meta_range func() const ENTT_NOEXCEPT { - return node->func; - } - - /** - * @brief Returns the function associated with a given identifier. - * - * The functions of the base classes will also be visited, if any.
- * In the case of overloaded functions, the first one with the required - * identifier will be returned. - * - * @param id Unique identifier. - * @return The function associated with the given identifier, if any. - */ - [[nodiscard]] meta_func func(const id_type id) const { - return internal::meta_visit<&node_type::func>([id](const auto *curr) { return curr->id == id; }, node); - } - - /** - * @brief Creates an instance of the underlying type, if possible. - * - * Parameters must be such that a cast or conversion to the required types - * is possible. Otherwise, an empty and thus invalid wrapper is returned. - * - * @param args Parameters to use to construct the instance. - * @param sz Number of parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - [[nodiscard]] meta_any construct(meta_any * const args, const size_type sz) const { - meta_any ret{}; - internal::meta_visit<&node_type::ctor>([args, sz, &ret](const auto *curr) { return (curr->arity == sz) && (ret = curr->invoke(args)); }, node); - return ret; - } - - /** - * @copybrief construct - * - * @sa construct - * - * @tparam Args Types of arguments to use to construct the instance. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ - template - [[nodiscard]] meta_any construct(Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return construct(arguments, sizeof...(Args)); - } - - /** - * @brief Invokes a function given an identifier, if possible. - * - * It must be possible to cast the instance to the parent type of the member - * function. Otherwise, invoking the underlying function results in an - * undefined behavior. - * - * @sa meta_func::invoke - * - * @param id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @param sz Number of parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ - meta_any invoke(const id_type id, meta_handle instance, meta_any * const args, const size_type sz) const { - const internal::meta_func_node* candidate{}; - size_type extent{sz + 1u}; - bool ambiguous{}; - - for(auto *it = internal::meta_visit<&node_type::func>([id, sz](const auto *curr) { return curr->id == id && curr->arity == sz; }, node); it && it->id == id && it->arity == sz; it = it->next) { - size_type direct{}; - size_type ext{}; - - for(size_type next{}; next < sz && next == (direct + ext); ++next) { - const auto type = args[next].type(); - const auto req = it->arg(next).info(); - type.info() == req ? ++direct : (ext += can_cast_or_convert(type.node, req)); - } - - if((direct + ext) == sz) { - if(ext < extent) { - candidate = it; - extent = ext; - ambiguous = false; - } else if(ext == extent) { - ambiguous = true; - } - } - } - - return (candidate && !ambiguous) ? candidate->invoke(std::move(instance), args) : meta_any{}; - } - - /** - * @copybrief invoke - * - * @sa invoke - * - * @param id Unique identifier. - * @tparam Args Types of arguments to use to invoke the function. - * @param instance An opaque instance of the underlying type. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the new instance, if any. - */ - template - meta_any invoke(const id_type id, meta_handle instance, Args &&... args) const { - meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; - return invoke(id, std::move(instance), arguments, sizeof...(Args)); - } - - /** - * @brief Sets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the setter results in an undefined - * behavior.
- * The type of the value must be such that a cast or conversion to the type - * of the variable is possible. Otherwise, invoking the setter does nothing. - * - * @tparam Type Type of value to assign. - * @param id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - bool set(const id_type id, meta_handle instance, Type &&value) const { - auto const candidate = data(id); - return candidate ? candidate.set(std::move(instance), std::forward(value)) : false; - } - - /** - * @brief Gets the value of a given variable. - * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the getter results in an undefined behavior. - * - * @param id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @return A meta any containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(const id_type id, meta_handle instance) const { - auto const candidate = data(id); - return candidate ? candidate.get(std::move(instance)) : meta_any{}; - } - - /** - * @brief Returns a range to use to visit top-level properties. - * @return An iterable range to use to visit top-level properties. - */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; - } - - /** - * @brief Returns the property associated with a given key. - * - * Properties of the base classes will also be visited, if any. - * - * @param key The key to use to search for a property. - * @return The property associated with the given key, if any. - */ - [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(node == nullptr); - } - - /** - * @brief Checks if two objects refer to the same type. - * @param other The object with which to compare. - * @return True if the objects refer to the same type, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_type &other) const ENTT_NOEXCEPT { - return (!node && !other.node) || (node && other.node && node->info == other.node->info); - } - - /** - * @brief Resets a type and all its parts. - * - * This function 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 list of searchable types. - */ - void reset() ENTT_NOEXCEPT { - auto** it = internal::meta_context::global(); - - while(*it && *it != node) { - it = &(*it)->next; - } - - if(*it) { - *it = (*it)->next; - } - - const auto unregister_all = y_combinator{ - [](auto &&self, auto **curr, auto... member) { - while(*curr) { - auto *prev = *curr; - (self(&(prev->*member)), ...); - *curr = prev->next; - prev->next = nullptr; - } - } - }; - - unregister_all(&node->prop); - unregister_all(&node->base); - unregister_all(&node->conv); - unregister_all(&node->ctor, &internal::meta_ctor_node::prop); - unregister_all(&node->data, &internal::meta_data_node::prop); - unregister_all(&node->func, &internal::meta_func_node::prop); - - node->id = {}; - node->ctor = node->def_ctor; - node->dtor = nullptr; - } - -private: - node_type *node; -}; - - -/** - * @brief Checks if two objects refer to the same type. - * @param lhs An object, either valid or not. - * @param rhs An object, either valid or not. - * @return False if the objects refer to the same node, true otherwise. - */ -[[nodiscard]] inline bool operator!=(const meta_type &lhs, const meta_type &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -[[nodiscard]] inline meta_type meta_any::type() const ENTT_NOEXCEPT { - return node; -} - - -template -meta_any meta_any::invoke(const id_type id, Args &&... args) const { - return type().invoke(id, *this, std::forward(args)...); -} - - -template -meta_any meta_any::invoke(const id_type id, Args &&... args) { - return type().invoke(id, *this, std::forward(args)...); -} - - -template -bool meta_any::set(const id_type id, Type &&value) { - return type().set(id, *this, std::forward(value)); -} - - -[[nodiscard]] inline meta_any meta_any::get(const id_type id) const { - return type().get(id, *this); -} - - -[[nodiscard]] inline meta_any meta_any::get(const id_type id) { - return type().get(id, *this); -} - - -[[nodiscard]] inline meta_type meta_ctor::parent() const ENTT_NOEXCEPT { - return node->parent; -} - - -[[nodiscard]] inline meta_type meta_ctor::arg(size_type index) const ENTT_NOEXCEPT { - return index < arity() ? node->arg(index) : meta_type{}; -} - - -[[nodiscard]] inline meta_type meta_data::parent() const ENTT_NOEXCEPT { - return node->parent; -} - - -[[nodiscard]] inline meta_type meta_data::type() const ENTT_NOEXCEPT { - return node->type(); -} - - -[[nodiscard]] inline meta_type meta_func::parent() const ENTT_NOEXCEPT { - return node->parent; -} - - -[[nodiscard]] inline meta_type meta_func::ret() const ENTT_NOEXCEPT { - return node->ret(); -} - - -[[nodiscard]] inline meta_type meta_func::arg(size_type index) const ENTT_NOEXCEPT { - return index < arity() ? node->arg(index) : meta_type{}; -} - - -/*! @brief Opaque iterator for sequence containers. */ -class meta_sequence_container::meta_iterator { - /*! @brief A sequence container can access the underlying iterator. */ - friend class meta_sequence_container; - - enum class operation { INCR, DEREF }; - - using vtable_type = void(const operation, const any &, void *); - - template - static void basic_vtable(const operation op, const any &from, void *to) { - switch(op) { - case operation::INCR: - ++any_cast(const_cast(from)); - break; - case operation::DEREF: - static_cast(to)->emplace::reference>(*any_cast(from)); - break; - } - } - -public: - /*! @brief Signed integer type. */ - using difference_type = std::ptrdiff_t; - /*! @brief Type of elements returned by the iterator. */ - using value_type = meta_any; - /*! @brief Pointer type, `void` on purpose. */ - using pointer = void; - /*! @brief Reference type, it is **not** an actual reference. */ - using reference = value_type; - /*! @brief Iterator category. */ - using iterator_category = std::input_iterator_tag; - - /*! @brief Default constructor. */ - meta_iterator() ENTT_NOEXCEPT = default; - - /** - * @brief Constructs a meta iterator from a given iterator. - * @tparam It Type of actual iterator with which to build the meta iterator. - * @param iter The actual iterator with which to build the meta iterator. - */ - template - meta_iterator(It iter) - : vtable{&basic_vtable}, - handle{std::move(iter)} - {} - - /*! @brief Pre-increment operator. @return This iterator. */ - meta_iterator & operator++() ENTT_NOEXCEPT { - return vtable(operation::INCR, handle, nullptr), *this; - } - - /*! @brief Post-increment operator. @return This iterator. */ - meta_iterator operator++(int) ENTT_NOEXCEPT { - meta_iterator orig = *this; - return ++(*this), orig; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return True if the iterators refer to the same element, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT { - return handle == other.handle; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return False if the iterators refer to the same element, true otherwise. - */ - [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - /** - * @brief Indirection operator. - * @return The element to which the iterator points. - */ - [[nodiscard]] reference operator*() const { - meta_any other; - vtable(operation::DEREF, handle, &other); - return other; - } - - /** - * @brief Returns false if an iterator is invalid, true otherwise. - * @return False if the iterator is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(handle); - } - -private: - vtable_type *vtable{}; - any handle{}; -}; - - -template -struct meta_sequence_container::meta_sequence_container_proxy { - using traits_type = meta_sequence_container_traits; - - [[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); - } - - [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT { - return traits_type::size(any_cast(container)); - } - - [[nodiscard]] static bool resize(any &container, size_type sz) { - auto * const cont = any_cast(&container); - return cont ? traits_type::resize(*cont, sz) : false; - } - - [[nodiscard]] static bool clear(any &container) { - auto * const cont = any_cast(&container); - return cont ? traits_type::clear(*cont) : false; - } - - [[nodiscard]] static iterator begin(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{traits_type::begin(*cont)}; - } - - return iterator{traits_type::cbegin(any_cast(container))}; - } - - [[nodiscard]] static iterator end(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{traits_type::end(*cont)}; - } - - return iterator{traits_type::cend(any_cast(container))}; - } - - [[nodiscard]] static std::pair insert(any &container, iterator it, meta_any &value) { - if(auto * const cont = any_cast(&container); cont) { - // this abomination is necessary because only on macos value_type and const_reference are different types for std::vector - if(value.allow_cast() || value.allow_cast()) { - const auto *element = value.try_cast>(); - auto ret = traits_type::insert(*cont, any_cast(it.handle), element ? *element : value.cast()); - return { iterator{std::move(ret.first)}, ret.second }; - } - } - - return {}; - } - - [[nodiscard]] static std::pair erase(any &container, iterator it) { - if(auto * const cont = any_cast(&container); cont) { - auto ret = traits_type::erase(*cont, any_cast(it.handle)); - return { iterator{std::move(ret.first)}, ret.second }; - } - - return {}; - } - - [[nodiscard]] static meta_any get(any &container, size_type pos) { - if(auto * const cont = any_cast(&container); cont) { - return meta_any{std::in_place_type, traits_type::get(*cont, pos)}; - } - - return meta_any{std::in_place_type, traits_type::cget(any_cast(container), pos)}; - } -}; - - -/** - * @brief Returns the meta value type of a container. - * @return The meta value type of the container. - */ -[[nodiscard]] inline meta_type meta_sequence_container::value_type() const ENTT_NOEXCEPT { - return value_type_fn(); -} - - -/** - * @brief Returns the size of a container. - * @return The size of the container. - */ -[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const ENTT_NOEXCEPT { - return size_fn(storage); -} - - -/** - * @brief Resizes a container to contain a given number of elements. - * @param sz The new size of the container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::resize(size_type sz) { - return resize_fn(storage, sz); -} - - -/** - * @brief Clears the content of a container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::clear() { - return clear_fn(storage); -} - - -/** - * @brief Returns an iterator to the first element of a container. - * @return An iterator to the first element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() { - return begin_fn(storage); -} - - -/** - * @brief Returns an iterator that is past the last element of a container. - * @return An iterator that is past the last element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() { - return end_fn(storage); -} - - -/** - * @brief Inserts an element at a specified location of a container. - * @param it Iterator before which the element will be inserted. - * @param value Element value to insert. - * @return A pair consisting of an iterator to the inserted element (in case of - * success) and a bool denoting whether the insertion took place. - */ -inline std::pair meta_sequence_container::insert(iterator it, meta_any value) { - return insert_fn(storage, it, value); -} - - -/** - * @brief Removes a given element from a container. - * @param it Iterator to the element to remove. - * @return A pair consisting of an iterator following the last removed element - * (in case of success) and a bool denoting whether the insertion took place. - */ -inline std::pair meta_sequence_container::erase(iterator it) { - return erase_fn(storage, it); -} - - -/** - * @brief Returns a reference to the element at a given location of a container - * (no bounds checking is performed). - * @param pos The position of the element to return. - * @return A reference to the requested element properly wrapped. - */ -[[nodiscard]] inline meta_any meta_sequence_container::operator[](size_type pos) { - return get_fn(storage, pos); -} - - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_sequence_container::operator bool() const ENTT_NOEXCEPT { - return static_cast(storage); -} - - -/*! @brief Opaque iterator for associative containers. */ -class meta_associative_container::meta_iterator { - enum operation { INCR, DEREF }; - - using vtable_type = void(const operation, const any &, void *); - - template - static void basic_vtable(const operation op, const any &from, void *to) { - switch(op) { - case operation::INCR: - ++any_cast(const_cast(from)); - break; - case operation::DEREF: - if constexpr(KeyOnly) { - static_cast *>(to)->first = std::cref(*any_cast(from)); - } else { - *static_cast *>(to) = std::make_pair(std::cref(any_cast(from)->first), std::ref(any_cast(from)->second)); - } - break; - } - } - -public: - /*! @brief Signed integer type. */ - using difference_type = std::ptrdiff_t; - /*! @brief Type of elements returned by the iterator. */ - using value_type = std::pair; - /*! @brief Pointer type, `void` on purpose. */ - using pointer = void; - /*! @brief Reference type, it is **not** an actual reference. */ - using reference = value_type; - /*! @brief Iterator category. */ - using iterator_category = std::input_iterator_tag; - - /*! @brief Default constructor. */ - meta_iterator() ENTT_NOEXCEPT = default; - - /** - * @brief Constructs an meta iterator from a given iterator. - * @tparam KeyOnly True if the container is also key-only, false otherwise. - * @tparam It Type of actual iterator with which to build the meta iterator. - * @param iter The actual iterator with which to build the meta iterator. - */ - template - meta_iterator(std::integral_constant, It iter) - : vtable{&basic_vtable}, - handle{std::move(iter)} - {} - - /*! @brief Pre-increment operator. @return This iterator. */ - meta_iterator & operator++() ENTT_NOEXCEPT { - return vtable(operation::INCR, handle, nullptr), *this; - } - - /*! @brief Post-increment operator. @return This iterator. */ - meta_iterator operator++(int) ENTT_NOEXCEPT { - meta_iterator orig = *this; - return ++(*this), orig; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return True if the iterators refer to the same element, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_iterator &other) const ENTT_NOEXCEPT { - return handle == other.handle; - } - - /** - * @brief Checks if two iterators refer to the same element. - * @param other The iterator with which to compare. - * @return False if the iterators refer to the same element, true otherwise. - */ - [[nodiscard]] bool operator!=(const meta_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - /** - * @brief Indirection operator. - * @return The element to which the iterator points. - */ - [[nodiscard]] reference operator*() const { - reference other; - vtable(operation::DEREF, handle, &other); - return other; - } - - /** - * @brief Returns false if an iterator is invalid, true otherwise. - * @return False if the iterator is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(handle); - } - -private: - vtable_type *vtable{}; - any handle{}; -}; - - -template -struct meta_associative_container::meta_associative_container_proxy { - using traits_type = meta_associative_container_traits; - - [[nodiscard]] static meta_type key_type() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); - } - - [[nodiscard]] static meta_type mapped_type() ENTT_NOEXCEPT { - if constexpr(is_key_only_meta_associative_container_v) { - return meta_type{}; - } else { - return internal::meta_info::resolve(); - } - } - - [[nodiscard]] static meta_type value_type() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); - } - - [[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT { - return traits_type::size(any_cast(container)); - } - - [[nodiscard]] static bool clear(any &container) { - auto * const cont = any_cast(&container); - return cont ? traits_type::clear(*cont) : false; - } - - [[nodiscard]] static iterator begin(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{is_key_only_meta_associative_container{}, traits_type::begin(*cont)}; - } - - return iterator{is_key_only_meta_associative_container{}, traits_type::cbegin(any_cast(container))}; - } - - [[nodiscard]] static iterator end(any &container) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{is_key_only_meta_associative_container{}, traits_type::end(*cont)}; - } - - return iterator{is_key_only_meta_associative_container{}, traits_type::cend(any_cast(container))}; - } - - [[nodiscard]] static bool insert(any &container, meta_any &key, meta_any &value) { - if(auto * const cont = any_cast(&container); cont && key.allow_cast()) { - if constexpr(is_key_only_meta_associative_container_v) { - return traits_type::insert(*cont, key.cast()); - } else { - if(value.allow_cast()) { - return traits_type::insert(*cont, key.cast(), value.cast()); - } - } - } - - return false; - } - - [[nodiscard]] static bool erase(any &container, meta_any &key) { - if(auto * const cont = any_cast(&container); cont && key.allow_cast()) { - return traits_type::erase(*cont, key.cast()); - } - - return false; - } - - [[nodiscard]] static iterator find(any &container, meta_any &key) { - if(key.allow_cast()) { - if(auto * const cont = any_cast(&container); cont) { - return iterator{is_key_only_meta_associative_container{}, traits_type::find(*cont, key.cast())}; - } - - return iterator{is_key_only_meta_associative_container{}, traits_type::cfind(any_cast(container), key.cast())}; - } - - return {}; - } -}; - - -/** - * @brief Returns true if a container is also key-only, false otherwise. - * @return True if the associative container is also key-only, false otherwise. - */ -[[nodiscard]] inline bool meta_associative_container::key_only() const ENTT_NOEXCEPT { - return key_only_container; -} - - -/** - * @brief Returns the meta key type of a container. - * @return The meta key type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::key_type() const ENTT_NOEXCEPT { - return key_type_fn(); -} - - -/** - * @brief Returns the meta mapped type of a container. - * @return The meta mapped type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::mapped_type() const ENTT_NOEXCEPT { - return mapped_type_fn(); -} - - -/*! @copydoc meta_sequence_container::value_type */ -[[nodiscard]] inline meta_type meta_associative_container::value_type() const ENTT_NOEXCEPT { - return value_type_fn(); -} - - -/*! @copydoc meta_sequence_container::size */ -[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const ENTT_NOEXCEPT { - return size_fn(storage); -} - - -/*! @copydoc meta_sequence_container::clear */ -inline bool meta_associative_container::clear() { - return clear_fn(storage); -} - - -/*! @copydoc meta_sequence_container::begin */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() { - return begin_fn(storage); -} - - -/*! @copydoc meta_sequence_container::end */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() { - return end_fn(storage); -} - - -/** - * @brief Inserts an element (a key/value pair) into a container. - * @param key The key of the element to insert. - * @param value The value of the element to insert. - * @return A bool denoting whether the insertion took place. - */ -inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { - return insert_fn(storage, key, value); -} - - -/** - * @brief Removes the specified element from a container. - * @param key The key of the element to remove. - * @return A bool denoting whether the removal took place. - */ -inline bool meta_associative_container::erase(meta_any key) { - return erase_fn(storage, key); -} - - -/** - * @brief Returns an iterator to the element with a given key, if any. - * @param key The key of the element to search. - * @return An iterator to the element with the given key, if any. - */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) { - return find_fn(storage, key); -} - - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_associative_container::operator bool() const ENTT_NOEXCEPT { - return static_cast(storage); -} - - -} - - -#endif - -// #include "meta/node.hpp" -#ifndef ENTT_META_NODE_HPP -#define ENTT_META_NODE_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" - -// #include "../core/fwd.hpp" - -// #include "../core/type_info.hpp" - -// #include "../core/type_traits.hpp" - -// #include "type_traits.hpp" - - - -namespace entt { - - -class meta_any; -class meta_type; -struct meta_handle; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct meta_type_node; - - -struct meta_prop_node { - meta_prop_node * next; - const meta_any &id; - meta_any &value; -}; - - -struct meta_base_node { - meta_type_node * const parent; - meta_base_node * next; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - const void *(* const cast)(const void *) ENTT_NOEXCEPT; -}; - - -struct meta_conv_node { - meta_type_node * const parent; - meta_conv_node * next; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - meta_any(* const conv)(const void *); -}; - - -struct meta_ctor_node { - using size_type = std::size_t; - meta_type_node * const parent; - meta_ctor_node * next; - meta_prop_node * prop; - const size_type arity; - meta_type(* const arg)(const size_type) ENTT_NOEXCEPT; - meta_any(* const invoke)(meta_any * const); -}; - - -struct meta_data_node { - id_type id; - meta_type_node * const parent; - meta_data_node * next; - meta_prop_node * prop; - const bool is_const; - const bool is_static; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - bool(* const set)(meta_handle, meta_any); - meta_any(* const get)(meta_handle); -}; - - -struct meta_func_node { - using size_type = std::size_t; - id_type id; - meta_type_node * const parent; - meta_func_node * next; - meta_prop_node * prop; - const size_type arity; - const bool is_const; - const bool is_static; - meta_type_node *(* const ret)() ENTT_NOEXCEPT; - meta_type(* const arg)(const size_type) ENTT_NOEXCEPT; - meta_any(* const invoke)(meta_handle, meta_any *); -}; - - -struct meta_template_info { - using size_type = std::size_t; - const bool is_template_specialization; - const size_type arity; - meta_type_node *(* const type)() ENTT_NOEXCEPT; - meta_type_node *(* const arg)(const size_type) ENTT_NOEXCEPT; -}; - - -struct meta_type_node { - using size_type = std::size_t; - const type_info info; - id_type id; - meta_type_node * next; - meta_prop_node * prop; - const size_type size_of; - const bool is_void; - const bool is_integral; - const bool is_floating_point; - const bool is_array; - const bool is_enum; - const bool is_union; - const bool is_class; - const bool is_pointer; - const bool is_function_pointer; - const bool is_member_object_pointer; - const bool is_member_function_pointer; - const bool is_pointer_like; - const bool is_sequence_container; - const bool is_associative_container; - const meta_template_info template_info; - const size_type rank; - size_type(* const extent)(const size_type) ENTT_NOEXCEPT ; - meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT; - meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT; - meta_ctor_node * const def_ctor; - meta_ctor_node *ctor{nullptr}; - meta_base_node *base{nullptr}; - meta_conv_node *conv{nullptr}; - meta_data_node *data{nullptr}; - meta_func_node *func{nullptr}; - void(* dtor)(void *){nullptr}; -}; - - -template -auto meta_visit(const Op &op, const Node *node) --> std::decay_t*Member)> { - for(auto *curr = node->*Member; curr; curr = curr->next) { - if(op(curr)) { - return curr; - } - } - - if constexpr(std::is_same_v) { - for(auto *curr = node->base; curr; curr = curr->next) { - if(auto *ret = meta_visit(op, curr->type()); ret) { - return ret; - } - } - } - - return nullptr; -} - - -template -meta_type_node * meta_arg_node(type_list, const std::size_t index) ENTT_NOEXCEPT; - - -template -class ENTT_API meta_node { - static_assert(std::is_same_v>>, "Invalid type"); - - template - [[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence) ENTT_NOEXCEPT { - meta_type_node::size_type ext{}; - ((ext = (dim == Index ? std::extent_v : ext)), ...); - return ext; - } - - [[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) ENTT_NOEXCEPT { - if constexpr(std::is_default_constructible_v) { - static meta_ctor_node node{ - type, - nullptr, - nullptr, - 0u, - nullptr, - [](meta_any * const) { return meta_any{std::in_place_type}; } - }; - - return &node; - } else { - return nullptr; - } - } - - [[nodiscard]] static meta_template_info meta_template_descriptor() ENTT_NOEXCEPT { - if constexpr(is_complete_v>) { - return { - true, - meta_template_traits::args_type::size, - &meta_node::class_type>::resolve, - [](const std::size_t index) ENTT_NOEXCEPT { - return meta_arg_node(typename meta_template_traits::args_type{}, index); - } - }; - } else { - return { false, 0u, nullptr, nullptr }; - } - } - -public: - [[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT { - static meta_type_node node{ - type_id(), - {}, - nullptr, - nullptr, - size_of_v, - std::is_void_v, - std::is_integral_v, - std::is_floating_point_v, - std::is_array_v, - std::is_enum_v, - std::is_union_v, - std::is_class_v, - std::is_pointer_v, - std::is_pointer_v && std::is_function_v>, - std::is_member_object_pointer_v, - std::is_member_function_pointer_v, - is_meta_pointer_like_v, - is_complete_v>, - is_complete_v>, - meta_template_descriptor(), - std::rank_v, - [](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence>{}); }, - &meta_node>>>::resolve, - &meta_node>>>::resolve, - meta_default_constructor(&node), - meta_default_constructor(&node) - }; - - return &node; - } -}; - - -template -struct meta_info: meta_node>> {}; - - -template -meta_type_node * meta_arg_node(type_list, const std::size_t index) ENTT_NOEXCEPT { - meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info::resolve()...}; - return args[index + 1u]; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -} - - -#endif - -// #include "meta/pointer.hpp" -#ifndef ENTT_META_POINTER_HPP -#define ENTT_META_POINTER_HPP - - -#include -#include -// #include "type_traits.hpp" - - - -namespace entt { - - -/** - * @brief Makes plain pointers pointer-like types for the meta system. - * @tparam Type Element type. - */ -template -struct is_meta_pointer_like - : std::true_type -{}; - - -/** - * @brief Partial specialization used to reject pointers to arrays. - * @tparam Type Type of elements of the array. - * @tparam N Number of elements of the array. - */ -template -struct is_meta_pointer_like - : std::false_type -{}; - - -/** - * @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta - * system. - * @tparam Type Element type. - */ -template -struct is_meta_pointer_like> - : 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 -struct is_meta_pointer_like> - : std::true_type -{}; - - -} - - -#endif - -// #include "meta/policy.hpp" -#ifndef ENTT_META_POLICY_HPP -#define ENTT_META_POLICY_HPP - - -namespace entt { - - -/*! @brief Empty class type used to request the _as ref_ policy. */ -struct as_ref_t {}; - - -/*! @brief Empty class type used to request the _as cref_ policy. */ -struct as_cref_t {}; - - -/*! @brief Empty class type used to request the _as-is_ policy. */ -struct as_is_t {}; - - -/*! @brief Empty class type used to request the _as void_ policy. */ -struct as_void_t {}; - - -} - - -#endif - -// #include "meta/range.hpp" -#ifndef ENTT_META_RANGE_HPP -#define ENTT_META_RANGE_HPP - - -#include -#include - - -namespace entt { - - -/** - * @brief Iterable range to use to iterate all types of meta objects. - * @tparam Type Type of meta objects returned. - * @tparam Node Type of meta nodes iterated. - */ -template -class meta_range { - struct range_iterator { - using difference_type = std::ptrdiff_t; - using value_type = Type; - using pointer = void; - using reference = value_type; - using iterator_category = std::input_iterator_tag; - using node_type = Node; - - range_iterator() ENTT_NOEXCEPT = default; - - range_iterator(node_type *head) ENTT_NOEXCEPT - : it{head} - {} - - range_iterator & operator++() ENTT_NOEXCEPT { - return (it = it->next), *this; - } - - range_iterator operator++(int) ENTT_NOEXCEPT { - range_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return it; - } - - [[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - node_type *it{}; - }; - -public: - /*! @brief Node type. */ - using node_type = Node; - /*! @brief Input iterator type. */ - using iterator = range_iterator; - - /*! @brief Default constructor. */ - meta_range() ENTT_NOEXCEPT = default; - - /** - * @brief Constructs a meta range from a given node. - * @param head The underlying node with which to construct the range. - */ - meta_range(node_type *head) - : node{head} - {} - - /** - * @brief Returns an iterator to the beginning. - * @return An iterator to the first meta object of the range. - */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return iterator{node}; - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last meta object of the - * range. - */ - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{}; - } - -private: - node_type *node{nullptr}; -}; - - -} - - -#endif - -// #include "meta/resolve.hpp" -#ifndef ENTT_META_RESOLVE_HPP -#define ENTT_META_RESOLVE_HPP - - -#include -// #include "../core/type_info.hpp" - -// #include "ctx.hpp" - -// #include "meta.hpp" - -// #include "node.hpp" - -// #include "range.hpp" - - - -namespace entt { - - -/** - * @brief Returns the meta type associated with a given type. - * @tparam Type Type to use to search for a meta type. - * @return The meta type associated with the given type, if any. - */ -template -[[nodiscard]] meta_type resolve() ENTT_NOEXCEPT { - return internal::meta_info::resolve(); -} - - -/** - * @brief Returns a range to use to visit all meta types. - * @return An iterable range to use to visit all meta types. - */ -[[nodiscard]] inline meta_range resolve() { - return *internal::meta_context::global(); -} - - -/** - * @brief Returns the meta type associated with a given identifier, if any. - * @param id Unique identifier. - * @return The meta type associated with the given identifier, if any. - */ -[[nodiscard]] inline meta_type resolve(const id_type id) ENTT_NOEXCEPT { - for(auto *curr = *internal::meta_context::global(); curr; curr = curr->next) { - if(curr->id == id) { - return curr; - } - } - - return {}; -} - - -/** - * @brief Returns the meta type associated with a given type info object, if - * any. - * @param info The type info object of the requested type. - * @return The meta type associated with the given type info object, if any. - */ -[[nodiscard]] inline meta_type resolve(const type_info info) ENTT_NOEXCEPT { - for(auto *curr = *internal::meta_context::global(); curr; curr = curr->next) { - if(curr->info == info) { - return curr; - } - } - - return {}; -} - - -} - - -#endif - -// #include "meta/template.hpp" -#ifndef ENTT_META_TEMPLATE_HPP -#define ENTT_META_TEMPLATE_HPP - - -// #include "../core/type_traits.hpp" - - - -namespace entt { - - -/*! @brief Utility class to disambiguate class templates. */ -template typename> -struct meta_class_template_tag {}; - - -/** - * @brief General purpose traits class for generating meta template information. - * @tparam Clazz Type of class template. - * @tparam Args Types of template arguments. - */ -template typename Clazz, typename... Args> -struct meta_template_traits> { - /*! @brief Wrapped class template. */ - using class_type = meta_class_template_tag; - /*! @brief List of template arguments. */ - using args_type = type_list; -}; - - -} - - -#endif - -// #include "meta/type_traits.hpp" -#ifndef ENTT_META_TYPE_TRAITS_HPP -#define ENTT_META_TYPE_TRAITS_HPP - - -#include - - -namespace entt { - - -/** - * @brief Traits class template to be specialized to enable support for meta - * template information. - */ -template -struct meta_template_traits; - - -/** - * @brief Traits class template to be specialized to enable support for meta - * sequence containers. - */ -template -struct meta_sequence_container_traits; - - -/** - * @brief Traits class template to be specialized to enable support for meta - * associative containers. - */ -template -struct meta_associative_container_traits; - - -/** - * @brief Provides the member constant `value` to true if a meta associative - * container claims to wrap a key-only type, false otherwise. - * @tparam Type Potentially key-only meta associative container type. - */ -template -struct is_key_only_meta_associative_container: std::true_type {}; - - -/*! @copydoc is_key_only_meta_associative_container */ -template -struct is_key_only_meta_associative_container::type::mapped_type>> - : std::false_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially key-only meta associative container type. - */ -template -inline constexpr auto is_key_only_meta_associative_container_v = is_key_only_meta_associative_container::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 -struct is_meta_pointer_like: std::false_type {}; - - -/** - * @brief Partial specialization to ensure that const pointer-like types are - * also accepted. - * @tparam Type Potentially pointer-like type. - */ -template -struct is_meta_pointer_like: is_meta_pointer_like {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially pointer-like type. - */ -template -inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like::value; - - -} - - -#endif - -// #include "meta/utility.hpp" -#ifndef ENTT_META_UTILITY_HPP -#define ENTT_META_UTILITY_HPP - - -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/type_traits.hpp" - -// #include "meta.hpp" - -// #include "node.hpp" - -// #include "policy.hpp" - - - -namespace entt { - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct meta_function_descriptor; - - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Class Actual owner of the member function. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor { - /*! @brief Meta function return type. */ - using return_type = Ret; - /*! @brief Meta function arguments. */ - using args_type = std::conditional_t, type_list, type_list>; - - /*! @brief True if the meta function is const, false otherwise. */ - static constexpr auto is_const = true; - /*! @brief True if the meta function is static, false otherwise. */ - static constexpr auto is_static = !std::is_same_v; -}; - - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Class Actual owner of the member function. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor { - /*! @brief Meta function return type. */ - using return_type = Ret; - /*! @brief Meta function arguments. */ - using args_type = std::conditional_t, type_list, type_list>; - - /*! @brief True if the meta function is const, false otherwise. */ - static constexpr auto is_const = false; - /*! @brief True if the meta function is static, false otherwise. */ - static constexpr auto is_static = !std::is_same_v; -}; - - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor { - /*! @brief Meta function return type. */ - using return_type = Ret; - /*! @brief Meta function arguments. */ - using args_type = type_list; - - /*! @brief True if the meta function is const, false otherwise. */ - static constexpr auto is_const = false; - /*! @brief True if the meta function is static, false otherwise. */ - static constexpr auto is_static = true; -}; - - -/** - * @brief Meta function helper. - * - * Converts a function type to be associated with a reflected type into its meta - * function descriptor. - * - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Candidate The actual function to associate with the reflected type. - */ -template -class meta_function_helper { - template - static constexpr meta_function_descriptor get_rid_of_noexcept(Ret(Class:: *)(Args...) const); - - template - static constexpr meta_function_descriptor get_rid_of_noexcept(Ret(Class:: *)(Args...)); - - template - static constexpr meta_function_descriptor get_rid_of_noexcept(Ret(*)(Args...)); - -public: - /*! @brief The meta function descriptor of the given function. */ - using type = decltype(get_rid_of_noexcept(std::declval())); -}; - - -/** - * @brief Helper type. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Candidate The actual function to associate with the reflected type. - */ -template -using meta_function_helper_t = typename meta_function_helper::type; - - -/** - * @brief Returns the meta type of the i-th element of a list of arguments. - * @tparam Args Actual types of arguments. - * @return The meta type of the i-th element of the list of arguments. - */ -template -[[nodiscard]] static meta_type meta_arg(type_list, const std::size_t index) ENTT_NOEXCEPT { - return internal::meta_arg_node(type_list{}, index); -} - - -/** - * @brief Constructs an instance given a list of erased parameters, if possible. - * @tparam Type Actual type of the instance to construct. - * @tparam Args Types of arguments expected. - * @tparam Index Indexes to use to extract erased arguments from their list. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ -template -[[nodiscard]] meta_any meta_construct(meta_any * const args, std::index_sequence) { - if(((args+Index)->allow_cast() && ...)) { - return Type{(args+Index)->cast()...}; - } - - return {}; -} - - -/** - * @brief Sets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to set. - * @param instance An opaque instance of the underlying type, if required. - * @param value Parameter to use to set the variable. - * @return True in case of success, false otherwise. - */ -template -[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) { - if constexpr(!std::is_same_v && !std::is_same_v) { - if constexpr(std::is_function_v>> || std::is_member_function_pointer_v) { - using descriptor = meta_function_helper_t; - using data_type = type_list_element_t, typename descriptor::args_type>; - - if(auto * const clazz = instance->try_cast(); clazz) { - if(value.allow_cast()) { - std::invoke(Data, *clazz, value.cast()); - return true; - } - } - } else if constexpr(std::is_member_object_pointer_v) { - using data_type = std::remove_reference_t().*Data)>; - - if constexpr(!std::is_array_v && !std::is_const_v) { - if(auto * const clazz = instance->try_cast(); clazz) { - if(value.allow_cast()) { - std::invoke(Data, clazz) = value.cast(); - return true; - } - } - } - } else { - using data_type = std::remove_reference_t; - - if constexpr(!std::is_array_v && !std::is_const_v) { - if(value.allow_cast()) { - *Data = value.cast(); - return true; - } - } - } - } - - return false; -} - - -/** - * @brief Gets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to get. - * @tparam Policy Optional policy (no policy set by default). - * @param instance An opaque instance of the underlying type, if required. - * @return A meta any containing the value of the underlying variable. - */ -template -[[nodiscard]] meta_any meta_getter([[maybe_unused]] meta_handle instance) { - [[maybe_unused]] auto dispatch = [](auto &&value) { - if constexpr(std::is_same_v) { - return meta_any{std::in_place_type, std::forward(value)}; - } else if constexpr(std::is_same_v) { - return meta_any{std::reference_wrapper{std::forward(value)}}; - } else if constexpr(std::is_same_v) { - return meta_any{std::cref(std::forward(value))}; - } else { - static_assert(std::is_same_v, "Policy not supported"); - return meta_any{std::forward(value)}; - } - }; - - if constexpr(std::is_function_v>> || std::is_member_function_pointer_v) { - auto * const clazz = instance->try_cast, const Type, Type>>(); - return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{}; - } else if constexpr(std::is_member_object_pointer_v) { - if constexpr(std::is_array_v().*Data)>>>) { - return meta_any{}; - } else { - if(auto * clazz = instance->try_cast(); clazz) { - return dispatch(std::invoke(Data, *clazz)); - } else { - auto * fallback = instance->try_cast(); - return fallback ? dispatch(std::invoke(Data, *fallback)) : meta_any{}; - } - } - } else if constexpr(std::is_pointer_v) { - if constexpr(std::is_array_v>) { - return meta_any{}; - } else { - return dispatch(*Data); - } - } else { - return dispatch(Data); - } -} - - -/** - * @brief Invokes a function given a list of erased parameters, if possible. - * @tparam Type Reflected type to which the function is associated. - * @tparam Candidate The actual function to invoke. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Index Indexes to use to extract erased arguments from their list. - * @param instance An opaque instance of the underlying type, if required. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence) { - using descriptor = meta_function_helper_t; - - auto dispatch = [](auto &&... params) { - if constexpr(std::is_void_v> || std::is_same_v) { - std::invoke(Candidate, std::forward(params)...); - return meta_any{std::in_place_type}; - } else if constexpr(std::is_same_v) { - return meta_any{std::reference_wrapper{std::invoke(Candidate, std::forward(params)...)}}; - } else if constexpr(std::is_same_v) { - return meta_any{std::cref(std::invoke(Candidate, std::forward(params)...))}; - } else { - static_assert(std::is_same_v, "Policy not supported"); - return meta_any{std::invoke(Candidate, std::forward(params)...)}; - } - }; - - if constexpr(std::is_invocable_v...>) { - if(const auto * const clazz = instance->try_cast(); clazz && ((args+Index)->allow_cast>() && ...)) { - return dispatch(*clazz, (args+Index)->cast>()...); - } - } else if constexpr(std::is_invocable_v...>) { - if(auto * const clazz = instance->try_cast(); clazz && ((args+Index)->allow_cast>() && ...)) { - return dispatch(*clazz, (args+Index)->cast>()...); - } - } else { - if(((args+Index)->allow_cast>() && ...)) { - return dispatch((args+Index)->cast>()...); - } - } - - return meta_any{}; -} - - -} - - -#endif - -// #include "platform/android-ndk-r17.hpp" -#ifndef ENTT_PLATFORM_ANDROID_NDK_R17_HPP -#define ENTT_PLATFORM_ANDROID_NDK_R17_HPP - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -#ifdef __ANDROID__ -#include -#if __NDK_MAJOR__ == 17 - - -#include -#include -#include - - -namespace std { - - -namespace internal { - - -template -constexpr auto is_invocable(int) -> decltype(std::invoke(std::declval(), std::declval()...), std::true_type{}); - - -template -constexpr std::false_type is_invocable(...); - - -template -constexpr auto is_invocable_r(int) --> std::enable_if_t(), std::declval()...)), Ret>, std::true_type>; - - -template -constexpr std::false_type is_invocable_r(...); - - -} - - -template -struct is_invocable: decltype(internal::is_invocable(0)) {}; - - -template -inline constexpr bool is_invocable_v = std::is_invocable::value; - - -template -struct is_invocable_r: decltype(internal::is_invocable_r(0)) {}; - - -template -inline constexpr bool is_invocable_r_v = std::is_invocable_r::value; - - -template -struct invoke_result { - using type = decltype(std::invoke(std::declval(), std::declval()...)); -}; - - -template -using invoke_result_t = typename std::invoke_result::type; - - -} - - -#endif -#endif - - -/** - * Internal details not to be documented. - * @endcond - */ - - -#endif - -// #include "poly/poly.hpp" -#ifndef ENTT_POLY_POLY_HPP -#define ENTT_POLY_POLY_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "../core/any.hpp" -#ifndef ENTT_CORE_ANY_HPP -#define ENTT_CORE_ANY_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - -// #include "type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "hashed_string.hpp" -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct fnv1a_traits; - - -template<> -struct fnv1a_traits { - using type = std::uint32_t; - static constexpr std::uint32_t offset = 2166136261; - static constexpr std::uint32_t prime = 16777619; -}; - - -template<> -struct fnv1a_traits { - using type = std::uint64_t; - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string { - using traits_type = internal::fnv1a_traits; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {} - const Char *str; - }; - - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT { - auto value = traits_type::offset; - - while(*curr != 0) { - value = (value ^ static_cast(*(curr++))) * traits_type::prime; - } - - return value; - } - -public: - /*! @brief Character type. */ - using value_type = Char; - /*! @brief Unsigned integer type. */ - using hash_type = id_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifer. - * @param size Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT { - id_type partial{traits_type::offset}; - while(size--) { partial = (partial^(str++)[0])*traits_type::prime; } - return partial; - } - - /** - * @brief Returns directly the numeric representation of a string. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * const auto value = basic_hashed_string::to_value("my.png"); - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - * @return The numeric representation of the string. - */ - template - [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT { - return helper(str); - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { - return helper(wrapper.str); - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() ENTT_NOEXCEPT - : str{nullptr}, hash{} - {} - - /** - * @brief Constructs a hashed string from an array of const characters. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * basic_hashed_string hs{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param curr Human-readable identifer. - */ - template - constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT - : str{curr}, hash{helper(curr)} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT - : str{wrapper.str}, hash{helper(wrapper.str)} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - [[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT { - return str; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { - return hash; - } - - /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const value_type *str; - hash_type hash; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the character type of the hashed string directly from a - * human-readable identifer provided to the constructor. - * - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ -template -basic_hashed_string(const Char (&str)[N]) --> basic_hashed_string; - - -/** - * @brief Compares two hashed strings. - * @tparam Char Character type. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const basic_hashed_string &lhs, const basic_hashed_string &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - - -inline namespace literals { - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_string{str}; -} - - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_wstring{str}; -} - - -} - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief A SBO friendly, type-safe container for single values of any type. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_any { - enum class operation { COPY, MOVE, DTOR, COMP, ADDR, CADDR, REF, CREF, TYPE }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void *(const operation, const basic_any &, const void *); - - template - static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v; - - template - [[nodiscard]] static bool compare(const void *lhs, const void *rhs) { - if constexpr(!std::is_function_v && is_equality_comparable_v) { - return *static_cast(lhs) == *static_cast(rhs); - } else { - return lhs == rhs; - } - } - - template - static Type & as(const void *to) { - return *const_cast(static_cast(to)); - } - - template - static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(std::is_void_v) { - switch(op) { - case operation::COPY: - case operation::MOVE: - case operation::REF: - case operation::CREF: - as(to).vtable = from.vtable; - break; - default: - break; - } - } else if constexpr(std::is_lvalue_reference_v) { - using base_type = std::decay_t; - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to) = *static_cast(from.instance); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - as(to).vtable = from.vtable; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif - - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - as(to).vtable = from.vtable; - break; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = std::exchange(as(&from).instance, nullptr); - as(to).vtable = from.vtable; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; - } - } - - return nullptr; - } - - template - void initialize([[maybe_unused]] Args &&... args) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - if constexpr(std::is_aggregate_v) { - new (&storage) Type{std::forward(args)...}; - } else { - new (&storage) Type(std::forward(args)...); - } - } else { - if constexpr(std::is_aggregate_v) { - instance = new Type{std::forward(args)...}; - } else { - instance = new Type(std::forward(args)...); - } - } - } - } - -public: - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : basic_any{std::in_place_type} - {} - - /** - * @brief Constructs an any by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_any(std::in_place_type_t, Args &&... args) - : instance{}, - vtable{&basic_vtable} - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs an any that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - basic_any(std::reference_wrapper value) ENTT_NOEXCEPT - : basic_any{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs an any from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template, basic_any>>> - basic_any(Type &&value) - : basic_any{std::in_place_type>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any &other) - : basic_any{std::in_place_type} - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{std::in_place_type} - { - other.vtable(operation::MOVE, other, this); - } - - /*! @brief Frees the internal storage, whatever it means. */ - ~basic_any() { - vtable(operation::DTOR, *this, nullptr); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This any object. - */ - basic_any & operator=(const basic_any &other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::COPY, other, this); - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This any object. - */ - basic_any & operator=(basic_any &&other) { - vtable(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { - emplace(value.get()); - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - std::enable_if_t, basic_any>, basic_any &> - operator=(Type &&value) { - emplace>(std::forward(value)); - return *this; - } - - /** - * @brief Returns the type of the contained object. - * @return The type of the contained object, if any. - */ - [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info{}; - vtable(operation::TYPE, *this, &info); - return info; - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return vtable(operation::CADDR, *this, nullptr); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return const_cast(vtable(operation::ADDR, *this, nullptr)); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - } - - /** - * @brief Returns false if a wrapper is empty, true otherwise. - * @return False if the wrapper is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(vtable(operation::CADDR, *this, nullptr) == nullptr); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - bool operator==(const basic_any &other) const ENTT_NOEXCEPT { - return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); - } - - /** - * @brief Aliasing constructor. - * @return An any that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::REF, *this, &ref); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - basic_any ref{}; - vtable(operation::CREF, *this, &ref); - return ref; - } - -private: - union { const void *instance; storage_type storage; }; - vtable_type *vtable; -}; - - -/** - * @brief Checks if two wrappers differ in their content. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param lhs A wrapper, either empty or not. - * @param rhs A wrapper, either empty or not. - * @return True if the two wrappers differ in their content, false otherwise. - */ -template -[[nodiscard]] inline bool operator!=(const basic_any &lhs, const basic_any &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Performs type-safe access to the contained object. - * @tparam Type Type to which conversion is required. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param data Target any object. - * @return The element converted to the requested type. - */ -template -Type any_cast(const basic_any &data) ENTT_NOEXCEPT { - const auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(*instance); -} - - -/*! @copydoc any_cast */ -template -Type any_cast(basic_any &&data) ENTT_NOEXCEPT { - // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast>(&data); - ENTT_ASSERT(instance); - return static_cast(std::move(*instance)); -} - - -/*! @copydoc any_cast */ -template -const Type * any_cast(const basic_any *data) ENTT_NOEXCEPT { - return (data->type() == type_id() ? static_cast(data->data()) : nullptr); -} - - -/*! @copydoc any_cast */ -template -Type * any_cast(basic_any *data) ENTT_NOEXCEPT { - // last attempt to make wrappers for const references return their values - return (data->type() == type_id() ? static_cast(static_cast, Type> *>(data)->data()) : nullptr); -} - - -} - - -#endif - -// #include "../core/type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" - -// #include "hashed_string.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "../core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_POLY_FWD_HPP -#define ENTT_POLY_FWD_HPP - - -#include - - -namespace entt { - - -template)> -class basic_poly; - - -/** - * @brief Alias declaration for the most common use case. - * @tparam Concept Concept descriptor. - */ -template -using poly = basic_poly; - - -} - - -#endif - - - -namespace entt { - - -/*! @brief Inspector class used to infer the type of the virtual table. */ -struct poly_inspector { - /** - * @brief Generic conversion operator (definition only). - * @tparam Type Type to which conversion is requested. - */ - template - operator Type &&() const; - - /** - * @brief Dummy invocation function (definition only). - * @tparam Member Index of the function to invoke. - * @tparam Args Types of arguments to pass to the function. - * @param args The arguments to pass to the function. - * @return A poly inspector convertible to any type. - */ - template - poly_inspector invoke(Args &&... args) const; - - /*! @copydoc invoke */ - template - poly_inspector invoke(Args &&... args); -}; - - -/** - * @brief Static virtual table factory. - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - */ -template -class poly_vtable { - using inspector = typename Concept::template type; - - template - static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(basic_any &, Args...); - - template - static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const basic_any &, Args...); - - template - static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const basic_any &, Args...); - - template - static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(basic_any &, Args...); - - template - static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const basic_any &, Args...); - - template - static auto make_vtable(value_list) - -> decltype(std::make_tuple(vtable_entry(Candidate)...)); - - template - [[nodiscard]] static constexpr auto make_vtable(type_list) { - if constexpr(sizeof...(Func) == 0) { - return decltype(make_vtable(typename Concept::template impl{})){}; - } else if constexpr((std::is_function_v && ...)) { - return decltype(std::make_tuple(vtable_entry(std::declval())...)){}; - } - } - - template - static void fill_vtable_entry(Ret(* &entry)(Any &, Args...)) { - if constexpr(std::is_invocable_r_v) { - entry = +[](Any &, Args... args) -> Ret { - return std::invoke(Candidate, std::forward(args)...); - }; - } else { - entry = +[](Any &instance, Args... args) -> Ret { - return static_cast(std::invoke(Candidate, any_cast &>(instance), std::forward(args)...)); - }; - } - } - - template - [[nodiscard]] static auto fill_vtable(std::index_sequence) { - type impl{}; - (fill_vtable_entry>>(std::get(impl)), ...); - return impl; - } - -public: - /*! @brief Virtual table type. */ - using type = decltype(make_vtable(Concept{})); - - /** - * @brief Returns a static virtual table for a specific concept and type. - * @tparam Type The type for which to generate the virtual table. - * @return A static virtual table for the given concept and type. - */ - template - [[nodiscard]] static const auto * instance() { - static_assert(std::is_same_v>, "Type differs from its decayed form"); - static const auto vtable = fill_vtable(std::make_index_sequence::size>{}); - return &vtable; - } -}; - - -/** - * @brief Poly base class used to inject functionalities into concepts. - * @tparam Poly The outermost poly class. - */ -template -struct poly_base { - /** - * @brief Invokes a function from the static virtual table. - * @tparam Member Index of the function to invoke. - * @tparam Args Types of arguments to pass to the function. - * @param self A reference to the poly object that made the call. - * @param args The arguments to pass to the function. - * @return The return value of the invoked function, if any. - */ - template - [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&... args) const { - const auto &poly = static_cast(self); - return std::get(*poly.vtable)(poly.storage, std::forward(args)...); - } - - /*! @copydoc invoke */ - template - [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&... args) { - auto &poly = static_cast(self); - return std::get(*poly.vtable)(poly.storage, std::forward(args)...); - } -}; - - -/** - * @brief Shortcut for calling `poly_base::invoke`. - * @tparam Member Index of the function to invoke. - * @tparam Poly A fully defined poly object. - * @tparam Args Types of arguments to pass to the function. - * @param self A reference to the poly object that made the call. - * @param args The arguments to pass to the function. - * @return The return value of the invoked function, if any. - */ -template -decltype(auto) poly_call(Poly &&self, Args &&... args) { - return std::forward(self).template invoke(self, std::forward(args)...); -} - - -/** - * @brief Static polymorphism made simple and within everyone's reach. - * - * Static polymorphism is a very powerful tool in C++, albeit sometimes - * cumbersome to obtain.
- * This class aims to make it simple and easy to use. - * - * @note - * Both deduced and defined static virtual tables are supported.
- * Moreover, the `poly` class template also works with unmanaged objects. - * - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_poly: private Concept::template type>> { - /*! @brief A poly base is allowed to snoop into a poly object. */ - friend struct poly_base; - - using vtable_type = typename poly_vtable::type; - -public: - /*! @brief Concept type. */ - using concept_type = typename Concept::template type>; - - /*! @brief Default constructor. */ - basic_poly() ENTT_NOEXCEPT - : storage{}, - vtable{} - {} - - /** - * @brief Constructs a poly by directly initializing the new object. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_poly(std::in_place_type_t, Args &&... args) - : storage{std::in_place_type, std::forward(args)...}, - vtable{poly_vtable::template instance>>()} - {} - - /** - * @brief Constructs a poly that holds an unmanaged object. - * @tparam Type Type of object to use to initialize the poly. - * @param value An instance of an object to use to initialize the poly. - */ - template - basic_poly(std::reference_wrapper value) - : basic_poly{std::in_place_type, value.get()} - {} - - /** - * @brief Constructs a poly from a given value. - * @tparam Type Type of object to use to initialize the poly. - * @param value An instance of an object to use to initialize the poly. - */ - template>, basic_poly>>> - basic_poly(Type &&value) ENTT_NOEXCEPT - : basic_poly{std::in_place_type>>, std::forward(value)} - {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_poly(const basic_poly &other) = default; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_poly(basic_poly &&other) ENTT_NOEXCEPT - : basic_poly{} - { - swap(*this, other); - } - - /** - * @brief Assignment operator. - * @param other The instance to assign from. - * @return This poly object. - */ - basic_poly & operator=(basic_poly other) { - swap(other, *this); - return *this; - } - - /** - * @brief Returns the type of the contained object. - * @return The type of the contained object, if any. - */ - [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - return storage.type(); - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void * data() const ENTT_NOEXCEPT { - return storage.data(); - } - - /*! @copydoc data */ - [[nodiscard]] void * data() ENTT_NOEXCEPT { - return storage.data(); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&... args) { - *this = basic_poly{std::in_place_type, std::forward(args)...}; - } - - /*! @brief Destroys contained object */ - void reset() { - *this = basic_poly{}; - } - - /** - * @brief Returns false if a poly is empty, true otherwise. - * @return False if the poly is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return !(vtable == nullptr); - } - - /** - * @brief Returns a pointer to the underlying concept. - * @return A pointer to the underlying concept. - */ - [[nodiscard]] concept_type * operator->() ENTT_NOEXCEPT { - return this; - } - - /*! @copydoc operator-> */ - [[nodiscard]] const concept_type * operator->() const ENTT_NOEXCEPT { - return this; - } - - /** - * @brief Swaps two poly objects. - * @param lhs A valid poly object. - * @param rhs A valid poly object. - */ - friend void swap(basic_poly &lhs, basic_poly &rhs) { - using std::swap; - swap(lhs.storage, rhs.storage); - swap(lhs.vtable, rhs.vtable); - } - - /** - * @brief Aliasing constructor. - * @return A poly that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_poly as_ref() ENTT_NOEXCEPT { - basic_poly ref = std::as_const(*this).as_ref(); - ref.storage = storage.as_ref(); - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_poly as_ref() const ENTT_NOEXCEPT { - basic_poly ref{}; - ref.storage = storage.as_ref(); - ref.vtable = vtable; - return ref; - } - -private: - basic_any storage; - const vtable_type *vtable; -}; - - -} - - -#endif - -// #include "process/process.hpp" -#ifndef ENTT_PROCESS_PROCESS_HPP -#define ENTT_PROCESS_PROCESS_HPP - - -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - - - -namespace entt { - - -/** - * @brief Base class for processes. - * - * This class stays true to the CRTP idiom. Derived classes must specify what's - * the intended type for elapsed times.
- * A process should expose publicly the following member functions whether - * required: - * - * * @code{.cpp} - * void update(Delta, void *); - * @endcode - * - * It's invoked once per tick until a process is explicitly aborted or it - * terminates either with or without errors. Even though it's not mandatory to - * declare this member function, as a rule of thumb each process should at - * least define it to work properly. The `void *` parameter is an opaque - * pointer to user data (if any) forwarded directly to the process during an - * update. - * - * * @code{.cpp} - * void init(); - * @endcode - * - * It's invoked when the process joins the running queue of a scheduler. This - * happens as soon as it's attached to the scheduler if the process is a top - * level one, otherwise when it replaces its parent if the process is a - * continuation. - * - * * @code{.cpp} - * void succeeded(); - * @endcode - * - * It's invoked in case of success, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void failed(); - * @endcode - * - * It's invoked in case of errors, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void aborted(); - * @endcode - * - * It's invoked only if a process is explicitly aborted. There is no guarantee - * that it executes in the same tick, this depends solely on whether the - * process is aborted immediately or not. - * - * Derived classes can change the internal state of a process by invoking the - * `succeed` and `fail` protected member functions and even pause or unpause the - * process itself. - * - * @sa scheduler - * - * @tparam Derived Actual type of process that extends the class template. - * @tparam Delta Type to use to provide elapsed time. - */ -template -class process { - enum class state: unsigned int { - UNINITIALIZED = 0, - RUNNING, - PAUSED, - SUCCEEDED, - FAILED, - ABORTED, - FINISHED, - REJECTED - }; - - template - auto next(std::integral_constant) - -> decltype(std::declval().init(), void()) { - static_cast(this)->init(); - } - - template - auto next(std::integral_constant, Delta delta, void *data) - -> decltype(std::declval().update(delta, data), void()) { - static_cast(this)->update(delta, data); - } - - template - auto next(std::integral_constant) - -> decltype(std::declval().succeeded(), void()) { - static_cast(this)->succeeded(); - } - - template - auto next(std::integral_constant) - -> decltype(std::declval().failed(), void()) { - static_cast(this)->failed(); - } - - template - auto next(std::integral_constant) - -> decltype(std::declval().aborted(), void()) { - static_cast(this)->aborted(); - } - - void next(...) const ENTT_NOEXCEPT {} - -protected: - /** - * @brief Terminates a process with success if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - */ - void succeed() ENTT_NOEXCEPT { - if(alive()) { - current = state::SUCCEEDED; - } - } - - /** - * @brief Terminates a process with errors if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - */ - void fail() ENTT_NOEXCEPT { - if(alive()) { - current = state::FAILED; - } - } - - /** - * @brief Stops a process if it's in a running state. - * - * The function is idempotent and it does nothing if the process isn't - * running. - */ - void pause() ENTT_NOEXCEPT { - if(current == state::RUNNING) { - current = state::PAUSED; - } - } - - /** - * @brief Restarts a process if it's paused. - * - * The function is idempotent and it does nothing if the process isn't - * paused. - */ - void unpause() ENTT_NOEXCEPT { - if(current == state::PAUSED) { - current = state::RUNNING; - } - } - -public: - /*! @brief Type used to provide elapsed time. */ - using delta_type = Delta; - - /*! @brief Default destructor. */ - virtual ~process() { - static_assert(std::is_base_of_v, "Incorrect use of the class template"); - } - - /** - * @brief Aborts a process if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - * - * @param immediately Requests an immediate operation. - */ - void abort(const bool immediately = false) { - if(alive()) { - current = state::ABORTED; - - if(immediately) { - tick({}); - } - } - } - - /** - * @brief Returns true if a process is either running or paused. - * @return True if the process is still alive, false otherwise. - */ - [[nodiscard]] bool alive() const ENTT_NOEXCEPT { - return current == state::RUNNING || current == state::PAUSED; - } - - /** - * @brief Returns true if a process is already terminated. - * @return True if the process is terminated, false otherwise. - */ - [[nodiscard]] bool dead() const ENTT_NOEXCEPT { - return current == state::FINISHED; - } - - /** - * @brief Returns true if a process is currently paused. - * @return True if the process is paused, false otherwise. - */ - [[nodiscard]] bool paused() const ENTT_NOEXCEPT { - return current == state::PAUSED; - } - - /** - * @brief Returns true if a process terminated with errors. - * @return True if the process terminated with errors, false otherwise. - */ - [[nodiscard]] bool rejected() const ENTT_NOEXCEPT { - return current == state::REJECTED; - } - - /** - * @brief Updates a process and its internal state if required. - * @param delta Elapsed time. - * @param data Optional data. - */ - void tick(const Delta delta, void *data = nullptr) { - switch (current) { - case state::UNINITIALIZED: - next(std::integral_constant{}); - current = state::RUNNING; - break; - case state::RUNNING: - next(std::integral_constant{}, delta, data); - break; - default: - // suppress warnings - break; - } - - // if it's dead, it must be notified and removed immediately - switch(current) { - case state::SUCCEEDED: - next(std::integral_constant{}); - current = state::FINISHED; - break; - case state::FAILED: - next(std::integral_constant{}); - current = state::REJECTED; - break; - case state::ABORTED: - next(std::integral_constant{}); - current = state::REJECTED; - break; - default: - // suppress warnings - break; - } - } - -private: - state current{state::UNINITIALIZED}; -}; - - -/** - * @brief Adaptor for lambdas and functors to turn them into processes. - * - * Lambdas and functors can't be used directly with a scheduler for they are not - * properly defined processes with managed life cycles.
- * This class helps in filling the gap and turning lambdas and functors into - * full featured processes usable by a scheduler. - * - * The signature of the function call operator should be equivalent to the - * following: - * - * @code{.cpp} - * void(Delta delta, void *data, auto succeed, auto fail); - * @endcode - * - * Where: - * - * * `delta` is the elapsed time. - * * `data` is an opaque pointer to user data if any, `nullptr` otherwise. - * * `succeed` is a function to call when a process terminates with success. - * * `fail` is a function to call when a process terminates with errors. - * - * The signature of the function call operator of both `succeed` and `fail` - * is equivalent to the following: - * - * @code{.cpp} - * void(); - * @endcode - * - * Usually users shouldn't worry about creating adaptors. A scheduler will - * create them internally each and avery time a lambda or a functor is used as - * a process. - * - * @sa process - * @sa scheduler - * - * @tparam Func Actual type of process. - * @tparam Delta Type to use to provide elapsed time. - */ -template -struct process_adaptor: process, Delta>, private Func { - /** - * @brief Constructs a process adaptor from a lambda or a functor. - * @tparam Args Types of arguments to use to initialize the actual process. - * @param args Parameters to use to initialize the actual process. - */ - template - process_adaptor(Args &&... args) - : Func{std::forward(args)...} - {} - - /** - * @brief Updates a process and its internal state if required. - * @param delta Elapsed time. - * @param data Optional data. - */ - void update(const Delta delta, void *data) { - Func::operator()(delta, data, [this]() { this->succeed(); }, [this]() { this->fail(); }); - } -}; - - -} - - -#endif - -// #include "process/scheduler.hpp" -#ifndef ENTT_PROCESS_SCHEDULER_HPP -#define ENTT_PROCESS_SCHEDULER_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "process.hpp" -#ifndef ENTT_PROCESS_PROCESS_HPP -#define ENTT_PROCESS_PROCESS_HPP - - -#include -#include -// #include "../config/config.h" - - - -namespace entt { - - -/** - * @brief Base class for processes. - * - * This class stays true to the CRTP idiom. Derived classes must specify what's - * the intended type for elapsed times.
- * A process should expose publicly the following member functions whether - * required: - * - * * @code{.cpp} - * void update(Delta, void *); - * @endcode - * - * It's invoked once per tick until a process is explicitly aborted or it - * terminates either with or without errors. Even though it's not mandatory to - * declare this member function, as a rule of thumb each process should at - * least define it to work properly. The `void *` parameter is an opaque - * pointer to user data (if any) forwarded directly to the process during an - * update. - * - * * @code{.cpp} - * void init(); - * @endcode - * - * It's invoked when the process joins the running queue of a scheduler. This - * happens as soon as it's attached to the scheduler if the process is a top - * level one, otherwise when it replaces its parent if the process is a - * continuation. - * - * * @code{.cpp} - * void succeeded(); - * @endcode - * - * It's invoked in case of success, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void failed(); - * @endcode - * - * It's invoked in case of errors, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void aborted(); - * @endcode - * - * It's invoked only if a process is explicitly aborted. There is no guarantee - * that it executes in the same tick, this depends solely on whether the - * process is aborted immediately or not. - * - * Derived classes can change the internal state of a process by invoking the - * `succeed` and `fail` protected member functions and even pause or unpause the - * process itself. - * - * @sa scheduler - * - * @tparam Derived Actual type of process that extends the class template. - * @tparam Delta Type to use to provide elapsed time. - */ -template -class process { - enum class state: unsigned int { - UNINITIALIZED = 0, - RUNNING, - PAUSED, - SUCCEEDED, - FAILED, - ABORTED, - FINISHED, - REJECTED - }; - - template - auto next(std::integral_constant) - -> decltype(std::declval().init(), void()) { - static_cast(this)->init(); - } - - template - auto next(std::integral_constant, Delta delta, void *data) - -> decltype(std::declval().update(delta, data), void()) { - static_cast(this)->update(delta, data); - } - - template - auto next(std::integral_constant) - -> decltype(std::declval().succeeded(), void()) { - static_cast(this)->succeeded(); - } - - template - auto next(std::integral_constant) - -> decltype(std::declval().failed(), void()) { - static_cast(this)->failed(); - } - - template - auto next(std::integral_constant) - -> decltype(std::declval().aborted(), void()) { - static_cast(this)->aborted(); - } - - void next(...) const ENTT_NOEXCEPT {} - -protected: - /** - * @brief Terminates a process with success if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - */ - void succeed() ENTT_NOEXCEPT { - if(alive()) { - current = state::SUCCEEDED; - } - } - - /** - * @brief Terminates a process with errors if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - */ - void fail() ENTT_NOEXCEPT { - if(alive()) { - current = state::FAILED; - } - } - - /** - * @brief Stops a process if it's in a running state. - * - * The function is idempotent and it does nothing if the process isn't - * running. - */ - void pause() ENTT_NOEXCEPT { - if(current == state::RUNNING) { - current = state::PAUSED; - } - } - - /** - * @brief Restarts a process if it's paused. - * - * The function is idempotent and it does nothing if the process isn't - * paused. - */ - void unpause() ENTT_NOEXCEPT { - if(current == state::PAUSED) { - current = state::RUNNING; - } - } - -public: - /*! @brief Type used to provide elapsed time. */ - using delta_type = Delta; - - /*! @brief Default destructor. */ - virtual ~process() { - static_assert(std::is_base_of_v, "Incorrect use of the class template"); - } - - /** - * @brief Aborts a process if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - * - * @param immediately Requests an immediate operation. - */ - void abort(const bool immediately = false) { - if(alive()) { - current = state::ABORTED; - - if(immediately) { - tick({}); - } - } - } - - /** - * @brief Returns true if a process is either running or paused. - * @return True if the process is still alive, false otherwise. - */ - [[nodiscard]] bool alive() const ENTT_NOEXCEPT { - return current == state::RUNNING || current == state::PAUSED; - } - - /** - * @brief Returns true if a process is already terminated. - * @return True if the process is terminated, false otherwise. - */ - [[nodiscard]] bool dead() const ENTT_NOEXCEPT { - return current == state::FINISHED; - } - - /** - * @brief Returns true if a process is currently paused. - * @return True if the process is paused, false otherwise. - */ - [[nodiscard]] bool paused() const ENTT_NOEXCEPT { - return current == state::PAUSED; - } - - /** - * @brief Returns true if a process terminated with errors. - * @return True if the process terminated with errors, false otherwise. - */ - [[nodiscard]] bool rejected() const ENTT_NOEXCEPT { - return current == state::REJECTED; - } - - /** - * @brief Updates a process and its internal state if required. - * @param delta Elapsed time. - * @param data Optional data. - */ - void tick(const Delta delta, void *data = nullptr) { - switch (current) { - case state::UNINITIALIZED: - next(std::integral_constant{}); - current = state::RUNNING; - break; - case state::RUNNING: - next(std::integral_constant{}, delta, data); - break; - default: - // suppress warnings - break; - } - - // if it's dead, it must be notified and removed immediately - switch(current) { - case state::SUCCEEDED: - next(std::integral_constant{}); - current = state::FINISHED; - break; - case state::FAILED: - next(std::integral_constant{}); - current = state::REJECTED; - break; - case state::ABORTED: - next(std::integral_constant{}); - current = state::REJECTED; - break; - default: - // suppress warnings - break; - } - } - -private: - state current{state::UNINITIALIZED}; -}; - - -/** - * @brief Adaptor for lambdas and functors to turn them into processes. - * - * Lambdas and functors can't be used directly with a scheduler for they are not - * properly defined processes with managed life cycles.
- * This class helps in filling the gap and turning lambdas and functors into - * full featured processes usable by a scheduler. - * - * The signature of the function call operator should be equivalent to the - * following: - * - * @code{.cpp} - * void(Delta delta, void *data, auto succeed, auto fail); - * @endcode - * - * Where: - * - * * `delta` is the elapsed time. - * * `data` is an opaque pointer to user data if any, `nullptr` otherwise. - * * `succeed` is a function to call when a process terminates with success. - * * `fail` is a function to call when a process terminates with errors. - * - * The signature of the function call operator of both `succeed` and `fail` - * is equivalent to the following: - * - * @code{.cpp} - * void(); - * @endcode - * - * Usually users shouldn't worry about creating adaptors. A scheduler will - * create them internally each and avery time a lambda or a functor is used as - * a process. - * - * @sa process - * @sa scheduler - * - * @tparam Func Actual type of process. - * @tparam Delta Type to use to provide elapsed time. - */ -template -struct process_adaptor: process, Delta>, private Func { - /** - * @brief Constructs a process adaptor from a lambda or a functor. - * @tparam Args Types of arguments to use to initialize the actual process. - * @param args Parameters to use to initialize the actual process. - */ - template - process_adaptor(Args &&... args) - : Func{std::forward(args)...} - {} - - /** - * @brief Updates a process and its internal state if required. - * @param delta Elapsed time. - * @param data Optional data. - */ - void update(const Delta delta, void *data) { - Func::operator()(delta, data, [this]() { this->succeed(); }, [this]() { this->fail(); }); - } -}; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Cooperative scheduler for processes. - * - * A cooperative scheduler runs processes and helps managing their life cycles. - * - * Each process is invoked once per tick. If a process terminates, it's - * removed automatically from the scheduler and it's never invoked again.
- * A process can also have a child. In this case, the process is replaced with - * its child when it terminates if it returns with success. In case of errors, - * both the process and its child are discarded. - * - * Example of use (pseudocode): - * - * @code{.cpp} - * scheduler.attach([](auto delta, void *, auto succeed, auto fail) { - * // code - * }).then(arguments...); - * @endcode - * - * In order to invoke all scheduled processes, call the `update` member function - * passing it the elapsed time to forward to the tasks. - * - * @sa process - * - * @tparam Delta Type to use to provide elapsed time. - */ -template -class scheduler { - struct process_handler { - using instance_type = std::unique_ptr; - using update_fn_type = bool(process_handler &, Delta, void *); - using abort_fn_type = void(process_handler &, bool); - using next_type = std::unique_ptr; - - instance_type instance; - update_fn_type *update; - abort_fn_type *abort; - next_type next; - }; - - struct continuation { - continuation(process_handler *ref) - : handler{ref} - { - ENTT_ASSERT(handler); - } - - template - continuation then(Args &&... args) { - static_assert(std::is_base_of_v, Proc>, "Invalid process type"); - auto proc = typename process_handler::instance_type{new Proc{std::forward(args)...}, &scheduler::deleter}; - handler->next.reset(new process_handler{std::move(proc), &scheduler::update, &scheduler::abort, nullptr}); - handler = handler->next.get(); - return *this; - } - - template - continuation then(Func &&func) { - return then, Delta>>(std::forward(func)); - } - - private: - process_handler *handler; - }; - - template - [[nodiscard]] static bool update(process_handler &handler, const Delta delta, void *data) { - auto *process = static_cast(handler.instance.get()); - process->tick(delta, data); - - if(process->rejected()) { - return true; - } else if(process->dead()) { - if(handler.next) { - handler = std::move(*handler.next); - // forces the process to exit the uninitialized state - return handler.update(handler, {}, nullptr); - } - - return true; - } - - return false; - } - - template - static void abort(process_handler &handler, const bool immediately) { - static_cast(handler.instance.get())->abort(immediately); - } - - template - static void deleter(void *proc) { - delete static_cast(proc); - } - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - - /*! @brief Default constructor. */ - scheduler() = default; - - /*! @brief Default move constructor. */ - scheduler(scheduler &&) = default; - - /*! @brief Default move assignment operator. @return This scheduler. */ - scheduler & operator=(scheduler &&) = default; - - /** - * @brief Number of processes currently scheduled. - * @return Number of processes currently scheduled. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return handlers.size(); - } - - /** - * @brief Returns true if at least a process is currently scheduled. - * @return True if there are scheduled processes, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return handlers.empty(); - } - - /** - * @brief Discards all scheduled processes. - * - * Processes aren't aborted. They are discarded along with their children - * and never executed again. - */ - void clear() { - handlers.clear(); - } - - /** - * @brief Schedules a process for the next tick. - * - * Returned value is an opaque object that can be used to attach a child to - * the given process. The child is automatically scheduled when the process - * terminates and only if the process returns with success. - * - * Example of use (pseudocode): - * - * @code{.cpp} - * // schedules a task in the form of a process class - * scheduler.attach(arguments...) - * // appends a child in the form of a lambda function - * .then([](auto delta, void *, auto succeed, auto fail) { - * // code - * }) - * // appends a child in the form of another process class - * .then(); - * @endcode - * - * @tparam Proc Type of process to schedule. - * @tparam Args Types of arguments to use to initialize the process. - * @param args Parameters to use to initialize the process. - * @return An opaque object to use to concatenate processes. - */ - template - auto attach(Args &&... args) { - static_assert(std::is_base_of_v, Proc>, "Invalid process type"); - auto proc = typename process_handler::instance_type{new Proc{std::forward(args)...}, &scheduler::deleter}; - process_handler handler{std::move(proc), &scheduler::update, &scheduler::abort, nullptr}; - // forces the process to exit the uninitialized state - handler.update(handler, {}, nullptr); - return continuation{&handlers.emplace_back(std::move(handler))}; - } - - /** - * @brief Schedules a process for the next tick. - * - * A process can be either a lambda or a functor. The scheduler wraps both - * of them in a process adaptor internally.
- * The signature of the function call operator should be equivalent to the - * following: - * - * @code{.cpp} - * void(Delta delta, void *data, auto succeed, auto fail); - * @endcode - * - * Where: - * - * * `delta` is the elapsed time. - * * `data` is an opaque pointer to user data if any, `nullptr` otherwise. - * * `succeed` is a function to call when a process terminates with success. - * * `fail` is a function to call when a process terminates with errors. - * - * The signature of the function call operator of both `succeed` and `fail` - * is equivalent to the following: - * - * @code{.cpp} - * void(); - * @endcode - * - * Returned value is an opaque object that can be used to attach a child to - * the given process. The child is automatically scheduled when the process - * terminates and only if the process returns with success. - * - * Example of use (pseudocode): - * - * @code{.cpp} - * // schedules a task in the form of a lambda function - * scheduler.attach([](auto delta, void *, auto succeed, auto fail) { - * // code - * }) - * // appends a child in the form of another lambda function - * .then([](auto delta, void *, auto succeed, auto fail) { - * // code - * }) - * // appends a child in the form of a process class - * .then(arguments...); - * @endcode - * - * @sa process_adaptor - * - * @tparam Func Type of process to schedule. - * @param func Either a lambda or a functor to use as a process. - * @return An opaque object to use to concatenate processes. - */ - template - auto attach(Func &&func) { - using Proc = process_adaptor, Delta>; - return attach(std::forward(func)); - } - - /** - * @brief Updates all scheduled processes. - * - * All scheduled processes are executed in no specific order.
- * If a process terminates with success, it's replaced with its child, if - * any. Otherwise, if a process terminates with an error, it's removed along - * with its child. - * - * @param delta Elapsed time. - * @param data Optional data. - */ - void update(const Delta delta, void *data = nullptr) { - auto sz = handlers.size(); - - for(auto pos = handlers.size(); pos; --pos) { - auto &handler = handlers[pos-1]; - - if(const auto dead = handler.update(handler, delta, data); dead) { - std::swap(handler, handlers[--sz]); - } - } - - handlers.erase(handlers.begin() + sz, handlers.end()); - } - - /** - * @brief Aborts all scheduled processes. - * - * Unless an immediate operation is requested, the abort is scheduled for - * the next tick. Processes won't be executed anymore in any case.
- * Once a process is fully aborted and thus finished, it's discarded along - * with its child, if any. - * - * @param immediately Requests an immediate operation. - */ - void abort(const bool immediately = false) { - decltype(handlers) exec; - exec.swap(handlers); - - for(auto &&handler: exec) { - handler.abort(handler, immediately); - } - - std::move(handlers.begin(), handlers.end(), std::back_inserter(exec)); - handlers.swap(exec); - } - -private: - std::vector handlers{}; -}; - - -} - - -#endif - -// #include "resource/cache.hpp" -#ifndef ENTT_RESOURCE_CACHE_HPP -#define ENTT_RESOURCE_CACHE_HPP - - -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "../core/fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - -// #include "handle.hpp" -#ifndef ENTT_RESOURCE_HANDLE_HPP -#define ENTT_RESOURCE_HANDLE_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" -#ifndef ENTT_RESOURCE_FWD_HPP -#define ENTT_RESOURCE_FWD_HPP - - -namespace entt { - - -template -struct resource_cache; - - -template -struct resource_handle; - - -template -class resource_loader; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Shared resource handle. - * - * A shared resource handle is a small class that wraps a resource and keeps it - * alive even if it's deleted from the cache. It can be either copied or - * moved. A handle shares a reference to the same resource with all the other - * handles constructed for the same identifier.
- * As a rule of thumb, resources should never be copied nor moved. Handles are - * the way to go to keep references to them. - * - * @tparam Resource Type of resource managed by a handle. - */ -template -struct resource_handle { - /*! @brief Default constructor. */ - resource_handle() ENTT_NOEXCEPT = default; - - /** - * @brief Creates a handle from a shared pointer, namely a resource. - * @param res A pointer to a properly initialized resource. - */ - resource_handle(std::shared_ptr res) ENTT_NOEXCEPT - : resource{std::move(res)} - {} - - /** - * @brief Gets a reference to the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource. - * - * @return A reference to the managed resource. - */ - [[nodiscard]] const Resource & get() const ENTT_NOEXCEPT { - ENTT_ASSERT(static_cast(resource)); - return *resource; - } - - /*! @copydoc get */ - [[nodiscard]] Resource & get() ENTT_NOEXCEPT { - return const_cast(std::as_const(*this).get()); - } - - /*! @copydoc get */ - [[nodiscard]] operator const Resource & () const ENTT_NOEXCEPT { - return get(); - } - - /*! @copydoc get */ - [[nodiscard]] operator Resource & () ENTT_NOEXCEPT { - return get(); - } - - /*! @copydoc get */ - [[nodiscard]] const Resource & operator *() const ENTT_NOEXCEPT { - return get(); - } - - /*! @copydoc get */ - [[nodiscard]] Resource & operator *() ENTT_NOEXCEPT { - return get(); - } - - /** - * @brief Gets a pointer to the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource. - * - * @return A pointer to the managed resource or `nullptr` if the handle - * contains no resource at all. - */ - [[nodiscard]] const Resource * operator->() const ENTT_NOEXCEPT { - ENTT_ASSERT(static_cast(resource)); - return resource.get(); - } - - /*! @copydoc operator-> */ - [[nodiscard]] Resource * operator->() ENTT_NOEXCEPT { - return const_cast(std::as_const(*this).operator->()); - } - - /** - * @brief Returns true if a handle contains a resource, false otherwise. - * @return True if the handle contains a resource, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(resource); - } - -private: - std::shared_ptr resource; -}; - - -} - - -#endif - -// #include "loader.hpp" -#ifndef ENTT_RESOURCE_LOADER_HPP -#define ENTT_RESOURCE_LOADER_HPP - - -// #include "fwd.hpp" - -// #include "handle.hpp" - - - -namespace entt { - - -/** - * @brief Base class for resource loaders. - * - * Resource loaders must inherit from this class and stay true to the CRTP - * idiom. Moreover, a resource loader must expose a public, const member - * function named `load` that accepts a variable number of arguments and returns - * a handle to the resource just created.
- * As an example: - * - * @code{.cpp} - * struct my_resource {}; - * - * struct my_loader: entt::resource_loader { - * resource_handle load(int value) const { - * // use the integer value somehow - * return std::make_shared(); - * } - * }; - * @endcode - * - * In general, resource loaders should not have a state or retain data of any - * type. They should let the cache manage their resources instead. - * - * @note - * Base class and CRTP idiom aren't strictly required with the current - * implementation. One could argue that a cache can easily work with loaders of - * any type. However, future changes won't be breaking ones by forcing the use - * of a base class today and that's why the model is already in its place. - * - * @tparam Loader Type of the derived class. - * @tparam Resource Type of resource for which to use the loader. - */ -template -class resource_loader { - /*! @brief Resource loaders are friends of their caches. */ - friend struct resource_cache; - - /** - * @brief Loads the resource and returns it. - * @tparam Args Types of arguments for the loader. - * @param args Arguments for the loader. - * @return The resource just loaded or an empty pointer in case of errors. - */ - template - [[nodiscard]] resource_handle get(Args &&... args) const { - return static_cast(this)->load(std::forward(args)...); - } -}; - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Simple cache for resources of a given type. - * - * Minimal implementation of a cache for resources of a given type. It doesn't - * offer much functionalities but it's suitable for small or medium sized - * applications and can be freely inherited to add targeted functionalities for - * large sized applications. - * - * @tparam Resource Type of resources managed by a cache. - */ -template -struct resource_cache { - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Type of resources managed by a cache. */ - using resource_type = Resource; - - /*! @brief Default constructor. */ - resource_cache() = default; - - /*! @brief Default move constructor. */ - resource_cache(resource_cache &&) = default; - - /*! @brief Default move assignment operator. @return This cache. */ - resource_cache & operator=(resource_cache &&) = default; - - /** - * @brief Number of resources managed by a cache. - * @return Number of resources currently stored. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return resources.size(); - } - - /** - * @brief Returns true if a cache contains no resources, false otherwise. - * @return True if the cache contains no resources, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return resources.empty(); - } - - /** - * @brief Clears a cache and discards all its resources. - * - * Handles are not invalidated and the memory used by a resource isn't - * freed as long as at least a handle keeps the resource itself alive. - */ - void clear() ENTT_NOEXCEPT { - resources.clear(); - } - - /** - * @brief Loads the resource that corresponds to a given identifier. - * - * In case an identifier isn't already present in the cache, it loads its - * resource and stores it aside for future uses. Arguments are forwarded - * directly to the loader in order to construct properly the requested - * resource. - * - * @note - * If the identifier is already present in the cache, this function does - * nothing and the arguments are simply discarded. - * - * @warning - * If the resource cannot be loaded correctly, the returned handle will be - * invalid and any use of it will result in undefined behavior. - * - * @tparam Loader Type of loader to use to load the resource if required. - * @tparam Args Types of arguments to use to load the resource if required. - * @param id Unique resource identifier. - * @param args Arguments to use to load the resource if required. - * @return A handle for the given resource. - */ - template - resource_handle load(const id_type id, Args &&... args) { - static_assert(std::is_base_of_v, Loader>, "Invalid loader type"); - - if(auto it = resources.find(id); it == resources.cend()) { - if(auto handle = temp(std::forward(args)...); handle) { - return (resources[id] = std::move(handle)); - } - } else { - return it->second; - } - - return {}; - } - - /** - * @brief Reloads a resource or loads it for the first time if not present. - * - * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * cache.discard(id); - * cache.load(id, args...); - * @endcode - * - * Arguments are forwarded directly to the loader in order to construct - * properly the requested resource. - * - * @warning - * If the resource cannot be loaded correctly, the returned handle will be - * invalid and any use of it will result in undefined behavior. - * - * @tparam Loader Type of loader to use to load the resource. - * @tparam Args Types of arguments to use to load the resource. - * @param id Unique resource identifier. - * @param args Arguments to use to load the resource. - * @return A handle for the given resource. - */ - template - resource_handle reload(const id_type id, Args &&... args) { - return (discard(id), load(id, std::forward(args)...)); - } - - /** - * @brief Creates a temporary handle for a resource. - * - * Arguments are forwarded directly to the loader in order to construct - * properly the requested resource. The handle isn't stored aside and the - * cache isn't in charge of the lifetime of the resource itself. - * - * @tparam Loader Type of loader to use to load the resource. - * @tparam Args Types of arguments to use to load the resource. - * @param args Arguments to use to load the resource. - * @return A handle for the given resource. - */ - template - [[nodiscard]] resource_handle temp(Args &&... args) const { - return Loader{}.get(std::forward(args)...); - } - - /** - * @brief Creates a handle for a given resource identifier. - * - * A resource handle can be in a either valid or invalid state. In other - * terms, a resource handle is properly initialized with a resource if the - * cache contains the resource itself. Otherwise the returned handle is - * uninitialized and accessing it results in undefined behavior. - * - * @sa resource_handle - * - * @param id Unique resource identifier. - * @return A handle for the given resource. - */ - [[nodiscard]] resource_handle handle(const id_type id) const { - if(auto it = resources.find(id); it != resources.cend()) { - return it->second; - } - - return {}; - } - - /** - * @brief Checks if a cache contains a given identifier. - * @param id Unique resource identifier. - * @return True if the cache contains the resource, false otherwise. - */ - [[nodiscard]] bool contains(const id_type id) const { - return (resources.find(id) != resources.cend()); - } - - /** - * @brief Discards the resource that corresponds to a given identifier. - * - * Handles are not invalidated and the memory used by the resource isn't - * freed as long as at least a handle keeps the resource itself alive. - * - * @param id Unique resource identifier. - */ - void discard(const id_type id) { - if(auto it = resources.find(id); it != resources.end()) { - resources.erase(it); - } - } - - /** - * @brief Iterates all resources. - * - * The function object is invoked for each element. It is provided with - * either the resource identifier, the resource handle or both of them.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entt::id_type); - * void(entt::resource_handle); - * void(const entt::id_type, entt::resource_handle); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - auto begin = resources.begin(); - auto end = resources.end(); - - while(begin != end) { - auto curr = begin++; - - if constexpr(std::is_invocable_v) { - func(curr->first); - } else if constexpr(std::is_invocable_v>) { - func(curr->second); - } else { - func(curr->first, curr->second); - } - } - } - -private: - std::unordered_map> resources; -}; - - -} - - -#endif - -// #include "resource/handle.hpp" -#ifndef ENTT_RESOURCE_HANDLE_HPP -#define ENTT_RESOURCE_HANDLE_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Shared resource handle. - * - * A shared resource handle is a small class that wraps a resource and keeps it - * alive even if it's deleted from the cache. It can be either copied or - * moved. A handle shares a reference to the same resource with all the other - * handles constructed for the same identifier.
- * As a rule of thumb, resources should never be copied nor moved. Handles are - * the way to go to keep references to them. - * - * @tparam Resource Type of resource managed by a handle. - */ -template -struct resource_handle { - /*! @brief Default constructor. */ - resource_handle() ENTT_NOEXCEPT = default; - - /** - * @brief Creates a handle from a shared pointer, namely a resource. - * @param res A pointer to a properly initialized resource. - */ - resource_handle(std::shared_ptr res) ENTT_NOEXCEPT - : resource{std::move(res)} - {} - - /** - * @brief Gets a reference to the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource. - * - * @return A reference to the managed resource. - */ - [[nodiscard]] const Resource & get() const ENTT_NOEXCEPT { - ENTT_ASSERT(static_cast(resource)); - return *resource; - } - - /*! @copydoc get */ - [[nodiscard]] Resource & get() ENTT_NOEXCEPT { - return const_cast(std::as_const(*this).get()); - } - - /*! @copydoc get */ - [[nodiscard]] operator const Resource & () const ENTT_NOEXCEPT { - return get(); - } - - /*! @copydoc get */ - [[nodiscard]] operator Resource & () ENTT_NOEXCEPT { - return get(); - } - - /*! @copydoc get */ - [[nodiscard]] const Resource & operator *() const ENTT_NOEXCEPT { - return get(); - } - - /*! @copydoc get */ - [[nodiscard]] Resource & operator *() ENTT_NOEXCEPT { - return get(); - } - - /** - * @brief Gets a pointer to the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource. - * - * @return A pointer to the managed resource or `nullptr` if the handle - * contains no resource at all. - */ - [[nodiscard]] const Resource * operator->() const ENTT_NOEXCEPT { - ENTT_ASSERT(static_cast(resource)); - return resource.get(); - } - - /*! @copydoc operator-> */ - [[nodiscard]] Resource * operator->() ENTT_NOEXCEPT { - return const_cast(std::as_const(*this).operator->()); - } - - /** - * @brief Returns true if a handle contains a resource, false otherwise. - * @return True if the handle contains a resource, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(resource); - } - -private: - std::shared_ptr resource; -}; - - -} - - -#endif - -// #include "resource/loader.hpp" -#ifndef ENTT_RESOURCE_LOADER_HPP -#define ENTT_RESOURCE_LOADER_HPP - - -// #include "fwd.hpp" - -// #include "handle.hpp" - - - -namespace entt { - - -/** - * @brief Base class for resource loaders. - * - * Resource loaders must inherit from this class and stay true to the CRTP - * idiom. Moreover, a resource loader must expose a public, const member - * function named `load` that accepts a variable number of arguments and returns - * a handle to the resource just created.
- * As an example: - * - * @code{.cpp} - * struct my_resource {}; - * - * struct my_loader: entt::resource_loader { - * resource_handle load(int value) const { - * // use the integer value somehow - * return std::make_shared(); - * } - * }; - * @endcode - * - * In general, resource loaders should not have a state or retain data of any - * type. They should let the cache manage their resources instead. - * - * @note - * Base class and CRTP idiom aren't strictly required with the current - * implementation. One could argue that a cache can easily work with loaders of - * any type. However, future changes won't be breaking ones by forcing the use - * of a base class today and that's why the model is already in its place. - * - * @tparam Loader Type of the derived class. - * @tparam Resource Type of resource for which to use the loader. - */ -template -class resource_loader { - /*! @brief Resource loaders are friends of their caches. */ - friend struct resource_cache; - - /** - * @brief Loads the resource and returns it. - * @tparam Args Types of arguments for the loader. - * @param args Arguments for the loader. - * @return The resource just loaded or an empty pointer in case of errors. - */ - template - [[nodiscard]] resource_handle get(Args &&... args) const { - return static_cast(this)->load(std::forward(args)...); - } -}; - - -} - - -#endif - -// #include "signal/delegate.hpp" -#ifndef ENTT_SIGNAL_DELEGATE_HPP -#define ENTT_SIGNAL_DELEGATE_HPP - - -#include -#include -#include -#include -#include -// #include "../core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // Unfortunately, doxygen cannot parse such a construct. - /*! @cond TURN_OFF_DOXYGEN */ - : choice_t - /*! @endcond */ -{}; - - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - - -/** - * @brief Identity type trait. - * - * Useful to establish non-deduced contexts in template argument deduction - * (waiting for C++20) or to provide types through function arguments. - * - * @tparam Type A type. - */ -template -struct type_identity { - /*! @brief Identity type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Type A type. - */ -template -using type_identity_t = typename type_identity::type; - - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - * @tparam The size of the type if `sizeof` accepts it, 0 otherwise. - */ -template -struct size_of: std::integral_constant {}; - - -/*! @copydoc size_of */ -template -struct size_of> - : std::integral_constant -{}; - - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr auto size_of_v = size_of::value; - - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_t = Type; - - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_v = Value; - - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = std::integral_constant; - - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Type First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = Type; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = typename type_list_element::type; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -constexpr type_list operator+(type_list, type_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = typename type_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = typename type_list_cat::type; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_unique; - - -/** - * @brief Removes duplicates types from a type list. - * @tparam Type One of the types provided by the given type list. - * @tparam Other The other types provided by the given type list. - */ -template -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = std::conditional_t< - std::disjunction_v...>, - typename type_list_unique>::type, - type_list_cat_t, typename type_list_unique>::type> - >; -}; - - -/*! @brief Removes duplicates types from a type list. */ -template<> -struct type_list_unique> { - /*! @brief A type list without duplicate types. */ - using type = type_list<>; -}; - - -/** - * @brief Helper type. - * @tparam Type A type list. - */ -template -using type_list_unique_t = typename type_list_unique::type; - - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other>: std::disjunction...> {}; - - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr auto type_list_contains_v = type_list_contains::value; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = typename type_list_diff::type; - - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> -{}; - - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -constexpr value_list operator+(value_list, value_list) { return {}; } - - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = typename value_list_cat, List...>::type; -}; - - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = typename value_list_cat::type; - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>) --> decltype(std::declval() == std::declval()) { return true; } - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>); -} - - -template -[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>) --> decltype(std::declval(), std::declval() == std::declval()) { - return is_equality_comparable(choice<2>) && is_equality_comparable(choice<2>); -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Provides the member constant `value` to true if a given type is - * equality comparable, false otherwise. - * @tparam Type Potentially equality comparable type. - */ -template -struct is_equality_comparable: std::bool_constant(choice<2>)> {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially equality comparable type. - */ -template -inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; - - -/*! @brief Same as std::is_invocable, but with tuples. */ -template -struct is_applicable: std::false_type {}; - - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** -* @copybrief is_applicable -* @tparam Func A valid function type. -* @tparam Tuple Tuple-like type. -* @tparam Args The list of arguments to use to probe the function type. -*/ -template class Tuple, typename... Args> -struct is_applicable>: std::is_invocable {}; - - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_v = is_applicable::value; - - -/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: std::false_type {}; - - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: std::is_invocable_r {}; - - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr auto is_applicable_r_v = is_applicable_r::value; - - -/** -* @brief Provides the member constant `value` to true if a given type is -* complete, false otherwise. -* @tparam Type Potential complete type. -*/ -template -struct is_complete: std::false_type {}; - - -/*! @copydoc is_complete */ -template -struct is_complete>: std::true_type {}; - - -/** -* @brief Helper variable template. -* @tparam Type Potential complete type. -*/ -template -inline constexpr auto is_complete_v = is_complete::value; - - -/** - * @brief Provides the member constant `value` to true if a given type is empty - * and the empty type optimization is enabled, false otherwise. - * @tparam Type Potential empty type. - */ -template -struct is_empty: ENTT_IS_EMPTY(Type) {}; - - -/** - * @brief Helper variable template. - * @tparam Type Potential empty type. - */ -template -inline constexpr auto is_empty_v = is_empty::value; - - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::remove_const_t; -}; - - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = std::add_const_t; -}; - - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = typename constness_as::type; - - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); - - template - static Class * clazz(Ret(Class:: *)(Args...)); - - template - static Class * clazz(Ret(Class:: *)(Args...) const); - - template - static Class * clazz(Type Class:: *); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = std::remove_pointer_t()))>; -}; - - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = typename member_class::type; - - -} - - -#endif - -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -# define ENTT_NOEXCEPT noexcept -#endif - - -#ifndef ENTT_USE_ATOMIC -# define ENTT_MAYBE_ATOMIC(Type) Type -#else -# include -# define ENTT_MAYBE_ATOMIC(Type) std::atomic -#endif - - -#ifndef ENTT_ID_TYPE -# include -# define ENTT_ID_TYPE std::uint32_t -#endif - - -#ifdef ENTT_PAGE_SIZE -static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two"); -#else -# define ENTT_PAGE_SIZE 4096 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition) assert(condition) -#endif - - -#ifndef ENTT_NO_ETO -# include -# define ENTT_IS_EMPTY(Type) std::is_empty -#else -# include -# define ENTT_IS_EMPTY(Type) std::false_type -#endif - - -#ifndef ENTT_STANDARD_CPP -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - - -#endif - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Type Class:: *, Other &&...) -> Type(*)(); - - -template -using function_pointer_t = decltype(internal::function_pointer(std::declval()...)); - - -template -[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) { - return std::index_sequence_for{}; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/*! @brief Used to wrap a function or a member of a specified type. */ -template -struct connect_arg_t {}; - - -/*! @brief Constant of type connect_arg_t used to disambiguate calls. */ -template -inline constexpr connect_arg_t connect_arg{}; - - -/** - * @brief Basic delegate implementation. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - */ -template -class delegate; - - -/** - * @brief Utility class to use to send around functions and members. - * - * Unmanaged delegate for function pointers and members. Users of this class are - * in charge of disconnecting instances before deleting them. - * - * A delegate can be used as a general purpose invoker without memory overhead - * for free functions possibly with payloads and bound or unbound members. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class delegate { - template - [[nodiscard]] auto wrap(std::index_sequence) ENTT_NOEXCEPT { - return [](const void *, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - return static_cast(std::invoke(Candidate, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type &, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, *curr, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type *, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, curr, std::forward>>(std::get(arguments))...)); - }; - } - -public: - /*! @brief Function type of the contained target. */ - using function_type = Ret(const void *, Args...); - /*! @brief Function type of the delegate. */ - using type = Ret(Args...); - /*! @brief Return type of the delegate. */ - using result_type = Ret; - - /*! @brief Default constructor. */ - delegate() ENTT_NOEXCEPT - : fn{nullptr}, data{nullptr} - {} - - /** - * @brief Constructs a delegate and connects a free function or an unbound - * member. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - delegate(connect_arg_t) ENTT_NOEXCEPT { - connect(); - } - - /** - * @brief Constructs a delegate and connects a free function with payload or - * a bound member. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - delegate(connect_arg_t, Type &&value_or_instance) ENTT_NOEXCEPT { - connect(std::forward(value_or_instance)); - } - - /** - * @brief Constructs a delegate and connects an user defined function with - * optional payload. - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - connect(function, payload); - } - - /** - * @brief Connects a free function or an unbound member to a delegate. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - void connect() ENTT_NOEXCEPT { - data = nullptr; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *, Args... args) -> Ret { - return Ret(std::invoke(Candidate, std::forward(args)...)); - }; - } else if constexpr(std::is_member_pointer_v) { - fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); - } else { - fn = wrap(internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the delegate.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the delegate itself. - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid reference that fits the purpose. - */ - template - void connect(Type &value_or_instance) ENTT_NOEXCEPT { - data = &value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, *curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * @sa connect(Type &) - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - */ - template - void connect(Type *value_or_instance) ENTT_NOEXCEPT { - data = value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects an user defined function with optional payload to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of an instance overcomes - * the one of the delegate.
- * The payload is returned as the first argument to the target function in - * all cases. - * - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - fn = function; - data = payload; - } - - /** - * @brief Resets a delegate. - * - * After a reset, a delegate cannot be invoked anymore. - */ - void reset() ENTT_NOEXCEPT { - fn = nullptr; - data = nullptr; - } - - /** - * @brief Returns the instance or the payload linked to a delegate, if any. - * @return An opaque pointer to the underlying data. - */ - [[nodiscard]] const void * instance() const ENTT_NOEXCEPT { - return data; - } - - /** - * @brief Triggers a delegate. - * - * The delegate invokes the underlying function and returns the result. - * - * @warning - * Attempting to trigger an invalid delegate results in undefined - * behavior. - * - * @param args Arguments to use to invoke the underlying function. - * @return The value returned by the underlying function. - */ - Ret operator()(Args... args) const { - ENTT_ASSERT(static_cast(*this)); - return fn(data, std::forward(args)...); - } - - /** - * @brief Checks whether a delegate actually stores a listener. - * @return False if the delegate is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - // no need to test also data - return !(fn == nullptr); - } - - /** - * @brief Compares the contents of two delegates. - * @param other Delegate with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const delegate &other) const ENTT_NOEXCEPT { - return fn == other.fn && data == other.data; - } - -private: - function_type *fn; - const void *data; -}; - - -/** - * @brief Compares the contents of two delegates. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @param lhs A valid delegate object. - * @param rhs A valid delegate object. - * @return True if the two contents differ, false otherwise. - */ -template -[[nodiscard]] bool operator!=(const delegate &lhs, const delegate &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - */ -template -delegate(connect_arg_t) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - */ -template -delegate(connect_arg_t, Type &&) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) --> delegate; - - -} - - -#endif - -// #include "signal/dispatcher.hpp" -#ifndef ENTT_SIGNAL_DISPATCHER_HPP -#define ENTT_SIGNAL_DISPATCHER_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/fwd.hpp" -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - -template)> -class basic_any; - - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any; - - -} - - -#endif - -// #include "../core/type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "../core/attribute.h" -#ifndef ENTT_CORE_ATTRIBUTE_H -#define ENTT_CORE_ATTRIBUTE_H - - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - - -#endif - -// #include "hashed_string.hpp" -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct fnv1a_traits; - - -template<> -struct fnv1a_traits { - using type = std::uint32_t; - static constexpr std::uint32_t offset = 2166136261; - static constexpr std::uint32_t prime = 16777619; -}; - - -template<> -struct fnv1a_traits { - using type = std::uint64_t; - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; -}; - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string { - using traits_type = internal::fnv1a_traits; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {} - const Char *str; - }; - - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT { - auto value = traits_type::offset; - - while(*curr != 0) { - value = (value ^ static_cast(*(curr++))) * traits_type::prime; - } - - return value; - } - -public: - /*! @brief Character type. */ - using value_type = Char; - /*! @brief Unsigned integer type. */ - using hash_type = id_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifer. - * @param size Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT { - id_type partial{traits_type::offset}; - while(size--) { partial = (partial^(str++)[0])*traits_type::prime; } - return partial; - } - - /** - * @brief Returns directly the numeric representation of a string. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * const auto value = basic_hashed_string::to_value("my.png"); - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - * @return The numeric representation of the string. - */ - template - [[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT { - return helper(str); - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { - return helper(wrapper.str); - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() ENTT_NOEXCEPT - : str{nullptr}, hash{} - {} - - /** - * @brief Constructs a hashed string from an array of const characters. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * basic_hashed_string hs{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param curr Human-readable identifer. - */ - template - constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT - : str{curr}, hash{helper(curr)} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT - : str{wrapper.str}, hash{helper(wrapper.str)} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - [[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT { - return str; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { - return hash; - } - - /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - [[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const value_type *str; - hash_type hash; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the character type of the hashed string directly from a - * human-readable identifer provided to the constructor. - * - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ -template -basic_hashed_string(const Char (&str)[N]) --> basic_hashed_string; - - -/** - * @brief Compares two hashed strings. - * @tparam Char Character type. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -template -[[nodiscard]] constexpr bool operator!=(const basic_hashed_string &lhs, const basic_hashed_string &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - - -inline namespace literals { - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_string{str}; -} - - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT { - return entt::hashed_wstring{str}; -} - - -} - - -} - - -#endif - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - - -template -[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT { -#if defined ENTT_PRETTY_FUNCTION - std::string_view pretty_function{ENTT_PRETTY_FUNCTION}; - auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1); - auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return std::string_view{""}; -#endif -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT { - constexpr auto value = stripped_type_name(); - return value; -} - - -template -[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT { - static const auto value = stripped_type_name(); - return value; -} - - -template().find_first_of('.')> -[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - - -template -[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_seq final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() ENTT_NOEXCEPT { - static const id_type value = internal::type_seq::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); } -}; - - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); } -}; - - -/*! @brief Implementation specific information about a type. */ -class type_info final { - template - friend type_info type_id() ENTT_NOEXCEPT; - - type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT - : seq_value{seq_v}, - hash_value{hash_v}, - name_value{name_v} - {} - -public: - /*! @brief Default constructor. */ - type_info() ENTT_NOEXCEPT - : type_info({}, {}, {}) - {} - - /*! @brief Default copy constructor. */ - type_info(const type_info &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - type_info(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Default copy assignment operator. - * @return This type info object. - */ - type_info & operator=(const type_info &) ENTT_NOEXCEPT = default; - - /** - * @brief Default move assignment operator. - * @return This type info object. - */ - type_info & operator=(type_info &&) ENTT_NOEXCEPT = default; - - /** - * @brief Checks if a type info object is properly initialized. - * @return True if the object is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return name_value.data() != nullptr; - } - - /** - * @brief Type sequential identifier. - * @return Type sequential identifier. - */ - [[nodiscard]] id_type seq() const ENTT_NOEXCEPT { - return seq_value; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] id_type hash() const ENTT_NOEXCEPT { - return hash_value; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] std::string_view name() const ENTT_NOEXCEPT { - return name_value; - } - - /** - * @brief Compares the contents of two type info objects. - * @param other Object with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT { - return hash_value == other.hash_value; - } - -private: - id_type seq_value; - id_type hash_value; - std::string_view name_value; -}; - - -/** - * @brief Compares the contents of two type info objects. - * @param lhs A type info object. - * @param rhs A type info object. - * @return True if the two contents differ, false otherwise. - */ -[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Returns the type info object for a given type. - * @tparam Type Type for which to generate a type info object. - * @return The type info object for the given type. - */ -template -[[nodiscard]] type_info type_id() ENTT_NOEXCEPT { - return type_info{ - type_seq>>::value(), - type_hash>>::value(), - type_name>>::value() - }; -} - - -} - - -#endif - -// #include "sigh.hpp" -#ifndef ENTT_SIGNAL_SIGH_HPP -#define ENTT_SIGNAL_SIGH_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "delegate.hpp" -#ifndef ENTT_SIGNAL_DELEGATE_HPP -#define ENTT_SIGNAL_DELEGATE_HPP - - -#include -#include -#include -#include -#include -// #include "../core/type_traits.hpp" - -// #include "../config/config.h" - - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...); - - -template -auto function_pointer(Type Class:: *, Other &&...) -> Type(*)(); - - -template -using function_pointer_t = decltype(internal::function_pointer(std::declval()...)); - - -template -[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) { - return std::index_sequence_for{}; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond - */ - - -/*! @brief Used to wrap a function or a member of a specified type. */ -template -struct connect_arg_t {}; - - -/*! @brief Constant of type connect_arg_t used to disambiguate calls. */ -template -inline constexpr connect_arg_t connect_arg{}; - - -/** - * @brief Basic delegate implementation. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - */ -template -class delegate; - - -/** - * @brief Utility class to use to send around functions and members. - * - * Unmanaged delegate for function pointers and members. Users of this class are - * in charge of disconnecting instances before deleting them. - * - * A delegate can be used as a general purpose invoker without memory overhead - * for free functions possibly with payloads and bound or unbound members. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class delegate { - template - [[nodiscard]] auto wrap(std::index_sequence) ENTT_NOEXCEPT { - return [](const void *, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - return static_cast(std::invoke(Candidate, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type &, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, *curr, std::forward>>(std::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type *, std::index_sequence) ENTT_NOEXCEPT { - return [](const void *payload, Args... args) -> Ret { - [[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward(args)...); - Type *curr = static_cast(const_cast *>(payload)); - return static_cast(std::invoke(Candidate, curr, std::forward>>(std::get(arguments))...)); - }; - } - -public: - /*! @brief Function type of the contained target. */ - using function_type = Ret(const void *, Args...); - /*! @brief Function type of the delegate. */ - using type = Ret(Args...); - /*! @brief Return type of the delegate. */ - using result_type = Ret; - - /*! @brief Default constructor. */ - delegate() ENTT_NOEXCEPT - : fn{nullptr}, data{nullptr} - {} - - /** - * @brief Constructs a delegate and connects a free function or an unbound - * member. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - delegate(connect_arg_t) ENTT_NOEXCEPT { - connect(); - } - - /** - * @brief Constructs a delegate and connects a free function with payload or - * a bound member. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - delegate(connect_arg_t, Type &&value_or_instance) ENTT_NOEXCEPT { - connect(std::forward(value_or_instance)); - } - - /** - * @brief Constructs a delegate and connects an user defined function with - * optional payload. - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - connect(function, payload); - } - - /** - * @brief Connects a free function or an unbound member to a delegate. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - void connect() ENTT_NOEXCEPT { - data = nullptr; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *, Args... args) -> Ret { - return Ret(std::invoke(Candidate, std::forward(args)...)); - }; - } else if constexpr(std::is_member_pointer_v) { - fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); - } else { - fn = wrap(internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the delegate.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the delegate itself. - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid reference that fits the purpose. - */ - template - void connect(Type &value_or_instance) ENTT_NOEXCEPT { - data = &value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, *curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * @sa connect(Type &) - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - */ - template - void connect(Type *value_or_instance) ENTT_NOEXCEPT { - data = value_or_instance; - - if constexpr(std::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> Ret { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(std::invoke(Candidate, curr, std::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects an user defined function with optional payload to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of an instance overcomes - * the one of the delegate.
- * The payload is returned as the first argument to the target function in - * all cases. - * - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT { - fn = function; - data = payload; - } - - /** - * @brief Resets a delegate. - * - * After a reset, a delegate cannot be invoked anymore. - */ - void reset() ENTT_NOEXCEPT { - fn = nullptr; - data = nullptr; - } - - /** - * @brief Returns the instance or the payload linked to a delegate, if any. - * @return An opaque pointer to the underlying data. - */ - [[nodiscard]] const void * instance() const ENTT_NOEXCEPT { - return data; - } - - /** - * @brief Triggers a delegate. - * - * The delegate invokes the underlying function and returns the result. - * - * @warning - * Attempting to trigger an invalid delegate results in undefined - * behavior. - * - * @param args Arguments to use to invoke the underlying function. - * @return The value returned by the underlying function. - */ - Ret operator()(Args... args) const { - ENTT_ASSERT(static_cast(*this)); - return fn(data, std::forward(args)...); - } - - /** - * @brief Checks whether a delegate actually stores a listener. - * @return False if the delegate is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - // no need to test also data - return !(fn == nullptr); - } - - /** - * @brief Compares the contents of two delegates. - * @param other Delegate with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const delegate &other) const ENTT_NOEXCEPT { - return fn == other.fn && data == other.data; - } - -private: - function_type *fn; - const void *data; -}; - - -/** - * @brief Compares the contents of two delegates. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @param lhs A valid delegate object. - * @param rhs A valid delegate object. - * @return True if the two contents differ, false otherwise. - */ -template -[[nodiscard]] bool operator!=(const delegate &lhs, const delegate &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - */ -template -delegate(connect_arg_t) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - */ -template -delegate(connect_arg_t, Type &&) --> delegate>>; - - -/** - * @brief Deduction guide. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) --> delegate; - - -} - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_SIGNAL_FWD_HPP -#define ENTT_SIGNAL_FWD_HPP - - -namespace entt { - - -template -class delegate; - - -class dispatcher; - - -template -class emitter; - - -class connection; - - -struct scoped_connection; - - -template -class sink; - - -template -class sigh; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Sink class. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - */ -template -class sink; - - -/** - * @brief Unmanaged signal handler. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - */ -template -class sigh; - - -/** - * @brief Unmanaged signal handler. - * - * It works directly with references to classes and pointers to member functions - * as well as pointers to free functions. Users of this class are in charge of - * disconnecting instances before deleting them. - * - * This class serves mainly two purposes: - * - * * Creating signals to use later to notify a bunch of listeners. - * * Collecting results from a set of functions like in a voting system. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class sigh { - /*! @brief A sink is allowed to modify a signal. */ - friend class sink; - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Sink type. */ - using sink_type = sink; - - /** - * @brief Instance type when it comes to connecting member functions. - * @tparam Class Type of class to which the member function belongs. - */ - template - using instance_type = Class *; - - /** - * @brief Number of listeners connected to the signal. - * @return Number of listeners currently connected. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return calls.size(); - } - - /** - * @brief Returns false if at least a listener is connected to the signal. - * @return True if the signal has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return calls.empty(); - } - - /** - * @brief Triggers a signal. - * - * All the listeners are notified. Order isn't guaranteed. - * - * @param args Arguments to use to invoke listeners. - */ - void publish(Args... args) const { - for(auto &&call: std::as_const(calls)) { - call(args...); - } - } - - /** - * @brief Collects return values from the listeners. - * - * The collector must expose a call operator with the following properties: - * - * * The return type is either `void` or such that it's convertible to - * `bool`. In the second case, a true value will stop the iteration. - * * The list of parameters is empty if `Ret` is `void`, otherwise it - * contains a single element such that `Ret` is convertible to it. - * - * @tparam Func Type of collector to use, if any. - * @param func A valid function object. - * @param args Arguments to use to invoke listeners. - */ - template - void collect(Func func, Args... args) const { - for(auto &&call: calls) { - if constexpr(std::is_void_v) { - if constexpr(std::is_invocable_r_v) { - call(args...); - if(func()) { break; } - } else { - call(args...); - func(); - } - } else { - if constexpr(std::is_invocable_r_v) { - if(func(call(args...))) { break; } - } else { - func(call(args...)); - } - } - } - } - -private: - std::vector> calls; -}; - - -/** - * @brief Connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it. - */ -class connection { - /*! @brief A sink is allowed to create connection objects. */ - template - friend class sink; - - connection(delegate fn, void *ref) - : disconnect{fn}, signal{ref} - {} - -public: - /*! @brief Default constructor. */ - connection() = default; - - /** - * @brief Checks whether a connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(disconnect); - } - - /*! @brief Breaks the connection. */ - void release() { - if(disconnect) { - disconnect(signal); - disconnect.reset(); - } - } - -private: - delegate disconnect; - void *signal{}; -}; - - -/** - * @brief Scoped connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it.
- * A scoped connection automatically breaks the link between the two objects - * when it goes out of scope. - */ -struct scoped_connection { - /*! @brief Default constructor. */ - scoped_connection() = default; - - /** - * @brief Constructs a scoped connection from a basic connection. - * @param other A valid connection object. - */ - scoped_connection(const connection &other) - : conn{other} - {} - - /*! @brief Default copy constructor, deleted on purpose. */ - scoped_connection(const scoped_connection &) = delete; - - /*! @brief Automatically breaks the link on destruction. */ - ~scoped_connection() { - conn.release(); - } - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This scoped connection. - */ - scoped_connection & operator=(const scoped_connection &) = delete; - - /** - * @brief Acquires a connection. - * @param other The connection object to acquire. - * @return This scoped connection. - */ - scoped_connection & operator=(connection other) { - conn = std::move(other); - return *this; - } - - /** - * @brief Checks whether a scoped connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(conn); - } - - /*! @brief Breaks the connection. */ - void release() { - conn.release(); - } - -private: - connection conn; -}; - - -/** - * @brief Sink class. - * - * A sink is used to connect listeners to signals and to disconnect them.
- * The function type for a listener is the one of the signal to which it - * belongs. - * - * The clear separation between a signal and a sink permits to store the former - * as private data member without exposing the publish functionality to the - * users of the class. - * - * @warning - * Lifetime of a sink must not overcome that of the signal to which it refers. - * In any other case, attempting to use a sink results in undefined behavior. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class sink { - using signal_type = sigh; - using difference_type = typename std::iterator_traits::difference_type; - - template - static void release(Type value_or_instance, void *signal) { - sink{*static_cast(signal)}.disconnect(value_or_instance); - } - - template - static void release(void *signal) { - sink{*static_cast(signal)}.disconnect(); - } - -public: - /** - * @brief Constructs a sink that is allowed to modify a given signal. - * @param ref A valid reference to a signal object. - */ - sink(sigh &ref) ENTT_NOEXCEPT - : offset{}, - signal{&ref} - {} - - /** - * @brief Returns false if at least a listener is connected to the sink. - * @return True if the sink has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return signal->calls.empty(); - } - - /** - * @brief Returns a sink that connects before a given free function or an - * unbound member. - * @tparam Function A valid free function pointer. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before() { - delegate call{}; - call.template connect(); - - const auto &calls = signal->calls; - const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); - - sink other{*this}; - other.offset = std::distance(it, calls.cend()); - return other; - } - - /** - * @brief Returns a sink that connects before a free function with payload - * or a bound member. - * @tparam Candidate Member or free function to look for. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type &&value_or_instance) { - delegate call{}; - call.template connect(value_or_instance); - - const auto &calls = signal->calls; - const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); - - sink other{*this}; - other.offset = std::distance(it, calls.cend()); - return other; - } - - /** - * @brief Returns a sink that connects before a given instance or specific - * payload. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type &value_or_instance) { - return before(&value_or_instance); - } - - /** - * @brief Returns a sink that connects before a given instance or specific - * payload. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type *value_or_instance) { - sink other{*this}; - - if(value_or_instance) { - const auto &calls = signal->calls; - const auto it = std::find_if(calls.cbegin(), calls.cend(), [value_or_instance](const auto &delegate) { - return delegate.instance() == value_or_instance; - }); - - other.offset = std::distance(it, calls.cend()); - } - - return other; - } - - /** - * @brief Returns a sink that connects before anything else. - * @return A properly initialized sink object. - */ - [[nodiscard]] sink before() { - sink other{*this}; - other.offset = signal->calls.size(); - return other; - } - - /** - * @brief Connects a free function or an unbound member to a signal. - * - * The signal handler performs checks to avoid multiple connections for the - * same function. - * - * @tparam Candidate Function or member to connect to the signal. - * @return A properly initialized connection object. - */ - template - connection connect() { - disconnect(); - - delegate call{}; - call.template connect(); - signal->calls.insert(signal->calls.end() - offset, std::move(call)); - - delegate conn{}; - conn.template connect<&release>(); - return { std::move(conn), signal }; - } - - /** - * @brief Connects a free function with payload or a bound member to a - * signal. - * - * The signal isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the signal. On the other side, the signal handler performs - * checks to avoid multiple connections for the same function.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the signal itself. - * - * @tparam Candidate Function or member to connect to the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized connection object. - */ - template - connection connect(Type &&value_or_instance) { - disconnect(value_or_instance); - - delegate call{}; - call.template connect(value_or_instance); - signal->calls.insert(signal->calls.end() - offset, std::move(call)); - - delegate conn{}; - conn.template connect<&release>(value_or_instance); - return { std::move(conn), signal }; - } - - /** - * @brief Disconnects a free function or an unbound member from a signal. - * @tparam Candidate Function or member to disconnect from the signal. - */ - template - void disconnect() { - auto &calls = signal->calls; - delegate call{}; - call.template connect(); - calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); - } - - /** - * @brief Disconnects a free function with payload or a bound member from a - * signal. - * @tparam Candidate Function or member to disconnect from the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &&value_or_instance) { - auto &calls = signal->calls; - delegate call{}; - call.template connect(value_or_instance); - calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &value_or_instance) { - disconnect(&value_or_instance); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type *value_or_instance) { - if(value_or_instance) { - auto &calls = signal->calls; - calls.erase(std::remove_if(calls.begin(), calls.end(), [value_or_instance](const auto &delegate) { - return delegate.instance() == value_or_instance; - }), calls.end()); - } - } - - /*! @brief Disconnects all the listeners from a signal. */ - void disconnect() { - signal->calls.clear(); - } - -private: - difference_type offset; - signal_type *signal; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the function type of a sink directly from the signal it - * refers to. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -sink(sigh &) --> sink; - - -} - - -#endif - - - -namespace entt { - - -/** - * @brief Basic dispatcher implementation. - * - * A dispatcher can be used either to trigger an immediate event or to enqueue - * events to be published all together once per tick.
- * Listeners are provided in the form of member functions. For each event of - * type `Event`, listeners are such that they can be invoked with an argument of - * type `Event &`, no matter what the return type is. - * - * The dispatcher creates instances of the `sigh` class internally. Refer to the - * documentation of the latter for more details. - */ -class dispatcher { - struct basic_pool { - virtual ~basic_pool() = default; - virtual void publish() = 0; - virtual void disconnect(void *) = 0; - virtual void clear() ENTT_NOEXCEPT = 0; - }; - - template - struct pool_handler final: basic_pool { - static_assert(std::is_same_v>, "Invalid event type"); - - using signal_type = sigh; - using sink_type = typename signal_type::sink_type; - - void publish() override { - const auto length = events.size(); - - for(std::size_t pos{}; pos < length; ++pos) { - signal.publish(events[pos]); - } - - events.erase(events.cbegin(), events.cbegin()+length); - } - - void disconnect(void *instance) override { - sink().disconnect(instance); - } - - void clear() ENTT_NOEXCEPT override { - events.clear(); - } - - [[nodiscard]] sink_type sink() ENTT_NOEXCEPT { - return entt::sink{signal}; - } - - template - void trigger(Args &&... args) { - Event instance{std::forward(args)...}; - signal.publish(instance); - } - - template - void enqueue(Args &&... args) { - if constexpr(std::is_aggregate_v) { - events.push_back(Event{std::forward(args)...}); - } else { - events.emplace_back(std::forward(args)...); - } - } - - private: - signal_type signal{}; - std::vector events; - }; - - template - [[nodiscard]] pool_handler & assure() { - const auto index = type_seq::value(); - - if(!(index < pools.size())) { - pools.resize(std::size_t(index)+1u); - } - - if(!pools[index]) { - pools[index].reset(new pool_handler{}); - } - - return static_cast &>(*pools[index]); - } - -public: - /*! @brief Default constructor. */ - dispatcher() = default; - - /*! @brief Default move constructor. */ - dispatcher(dispatcher &&) = default; - - /*! @brief Default move assignment operator. @return This dispatcher. */ - dispatcher & operator=(dispatcher &&) = default; - - /** - * @brief Returns a sink object for the given event. - * - * A sink is an opaque object used to connect listeners to events. - * - * The function type for a listener is _compatible_ with: - * @code{.cpp} - * void(Event &); - * @endcode - * - * The order of invocation of the listeners isn't guaranteed. - * - * @sa sink - * - * @tparam Event Type of event of which to get the sink. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto sink() { - return assure().sink(); - } - - /** - * @brief Triggers an immediate event of the given type. - * - * All the listeners registered for the given type are immediately notified. - * The event is discarded after the execution. - * - * @tparam Event Type of event to trigger. - * @tparam Args Types of arguments to use to construct the event. - * @param args Arguments to use to construct the event. - */ - template - void trigger(Args &&... args) { - assure().trigger(std::forward(args)...); - } - - /** - * @brief Triggers an immediate event of the given type. - * - * All the listeners registered for the given type are immediately notified. - * The event is discarded after the execution. - * - * @tparam Event Type of event to trigger. - * @param event An instance of the given type of event. - */ - template - void trigger(Event &&event) { - assure>().trigger(std::forward(event)); - } - - /** - * @brief Enqueues an event of the given type. - * - * An event of the given type is queued. No listener is invoked. Use the - * `update` member function to notify listeners when ready. - * - * @tparam Event Type of event to enqueue. - * @tparam Args Types of arguments to use to construct the event. - * @param args Arguments to use to construct the event. - */ - template - void enqueue(Args &&... args) { - assure().enqueue(std::forward(args)...); - } - - /** - * @brief Enqueues an event of the given type. - * - * An event of the given type is queued. No listener is invoked. Use the - * `update` member function to notify listeners when ready. - * - * @tparam Event Type of event to enqueue. - * @param event An instance of the given type of event. - */ - template - void enqueue(Event &&event) { - assure>().enqueue(std::forward(event)); - } - - /** - * @brief Utility function to disconnect everything related to a given value - * or instance from a dispatcher. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &value_or_instance) { - disconnect(&value_or_instance); - } - - /** - * @brief Utility function to disconnect everything related to a given value - * or instance from a dispatcher. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type *value_or_instance) { - for(auto &&cpool: pools) { - if(cpool) { - cpool->disconnect(value_or_instance); - } - } - } - - /** - * @brief Discards all the events queued so far. - * - * If no types are provided, the dispatcher will clear all the existing - * pools. - * - * @tparam Event Type of events to discard. - */ - template - void clear() { - if constexpr(sizeof...(Event) == 0) { - for(auto &&cpool: pools) { - if(cpool) { - cpool->clear(); - } - } - } else { - (assure().clear(), ...); - } - } - - /** - * @brief Delivers all the pending events of the given type. - * - * This method is blocking and it doesn't return until all the events are - * delivered to the registered listeners. It's responsibility of the users - * to reduce at a minimum the time spent in the bodies of the listeners. - * - * @tparam Event Type of events to send. - */ - template - void update() { - assure().publish(); - } - - /** - * @brief Delivers all the pending events. - * - * This method is blocking and it doesn't return until all the events are - * delivered to the registered listeners. It's responsibility of the users - * to reduce at a minimum the time spent in the bodies of the listeners. - */ - void update() const { - for(auto pos = pools.size(); pos; --pos) { - if(auto &&cpool = pools[pos-1]; cpool) { - cpool->publish(); - } - } - } - -private: - std::vector> pools; -}; - - -} - - -#endif - -// #include "signal/emitter.hpp" -#ifndef ENTT_SIGNAL_EMITTER_HPP -#define ENTT_SIGNAL_EMITTER_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/fwd.hpp" - -// #include "../core/type_info.hpp" - - - -namespace entt { - - -/** - * @brief General purpose event emitter. - * - * The emitter class template follows the CRTP idiom. To create a custom emitter - * type, derived classes must inherit directly from the base class as: - * - * @code{.cpp} - * struct my_emitter: emitter { - * // ... - * } - * @endcode - * - * Pools for the type of events are created internally on the fly. It's not - * required to specify in advance the full list of accepted types.
- * Moreover, whenever an event is published, an emitter provides the listeners - * with a reference to itself along with a reference to the event. Therefore - * listeners have an handy way to work with it without incurring in the need of - * capturing a reference to the emitter. - * - * @tparam Derived Actual type of emitter that extends the class template. - */ -template -class emitter { - struct basic_pool { - virtual ~basic_pool() = default; - virtual bool empty() const ENTT_NOEXCEPT = 0; - virtual void clear() ENTT_NOEXCEPT = 0; - }; - - template - struct pool_handler final: basic_pool { - static_assert(std::is_same_v>, "Invalid event type"); - - using listener_type = std::function; - using element_type = std::pair; - using container_type = std::list; - using connection_type = typename container_type::iterator; - - [[nodiscard]] bool empty() const ENTT_NOEXCEPT override { - auto pred = [](auto &&element) { return element.first; }; - - return std::all_of(once_list.cbegin(), once_list.cend(), pred) && - std::all_of(on_list.cbegin(), on_list.cend(), pred); - } - - void clear() ENTT_NOEXCEPT override { - if(publishing) { - for(auto &&element: once_list) { - element.first = true; - } - - for(auto &&element: on_list) { - element.first = true; - } - } else { - once_list.clear(); - on_list.clear(); - } - } - - connection_type once(listener_type listener) { - return once_list.emplace(once_list.cend(), false, std::move(listener)); - } - - connection_type on(listener_type listener) { - return on_list.emplace(on_list.cend(), false, std::move(listener)); - } - - void erase(connection_type conn) { - conn->first = true; - - if(!publishing) { - auto pred = [](auto &&element) { return element.first; }; - once_list.remove_if(pred); - on_list.remove_if(pred); - } - } - - void publish(Event &event, Derived &ref) { - container_type swap_list; - once_list.swap(swap_list); - - publishing = true; - - for(auto &&element: on_list) { - element.first ? void() : element.second(event, ref); - } - - for(auto &&element: swap_list) { - element.first ? void() : element.second(event, ref); - } - - publishing = false; - - on_list.remove_if([](auto &&element) { return element.first; }); - } - - private: - bool publishing{false}; - container_type once_list{}; - container_type on_list{}; - }; - - template - [[nodiscard]] pool_handler * assure() { - const auto index = type_seq::value(); - - if(!(index < pools.size())) { - pools.resize(std::size_t(index)+1u); - } - - if(!pools[index]) { - pools[index].reset(new pool_handler{}); - } - - return static_cast *>(pools[index].get()); - } - - template - [[nodiscard]] const pool_handler * assure() const { - const auto index = type_seq::value(); - return (!(index < pools.size()) || !pools[index]) ? nullptr : static_cast *>(pools[index].get()); - } - -public: - /** @brief Type of listeners accepted for the given event. */ - template - using listener = typename pool_handler::listener_type; - - /** - * @brief Generic connection type for events. - * - * Type of the connection object returned by the event emitter whenever a - * listener for the given type is registered.
- * It can be used to break connections still in use. - * - * @tparam Event Type of event for which the connection is created. - */ - template - struct connection: private pool_handler::connection_type { - /** @brief Event emitters are friend classes of connections. */ - friend class emitter; - - /*! @brief Default constructor. */ - connection() = default; - - /** - * @brief Creates a connection that wraps its underlying instance. - * @param conn A connection object to wrap. - */ - connection(typename pool_handler::connection_type conn) - : pool_handler::connection_type{std::move(conn)} - {} - }; - - /*! @brief Default constructor. */ - emitter() = default; - - /*! @brief Default destructor. */ - virtual ~emitter() { - static_assert(std::is_base_of_v, Derived>, "Incorrect use of the class template"); - } - - /*! @brief Default move constructor. */ - emitter(emitter &&) = default; - - /*! @brief Default move assignment operator. @return This emitter. */ - emitter & operator=(emitter &&) = default; - - /** - * @brief Emits the given event. - * - * All the listeners registered for the specific event type are invoked with - * the given event. The event type must either have a proper constructor for - * the arguments provided or be an aggregate type. - * - * @tparam Event Type of event to publish. - * @tparam Args Types of arguments to use to construct the event. - * @param args Parameters to use to initialize the event. - */ - template - void publish(Args &&... args) { - Event instance{std::forward(args)...}; - assure()->publish(instance, *static_cast(this)); - } - - /** - * @brief Registers a long-lived listener with the event emitter. - * - * This method can be used to register a listener designed to be invoked - * more than once for the given event type.
- * The connection returned by the method can be freely discarded. It's meant - * to be used later to disconnect the listener if required. - * - * The listener is as a callable object that can be moved and the type of - * which is _compatible_ with `void(Event &, Derived &)`. - * - * @note - * Whenever an event is emitted, the emitter provides the listener with a - * reference to the derived class. Listeners don't have to capture those - * instances for later uses. - * - * @tparam Event Type of event to which to connect the listener. - * @param instance The listener to register. - * @return Connection object that can be used to disconnect the listener. - */ - template - connection on(listener instance) { - return assure()->on(std::move(instance)); - } - - /** - * @brief Registers a short-lived listener with the event emitter. - * - * This method can be used to register a listener designed to be invoked - * only once for the given event type.
- * The connection returned by the method can be freely discarded. It's meant - * to be used later to disconnect the listener if required. - * - * The listener is as a callable object that can be moved and the type of - * which is _compatible_ with `void(Event &, Derived &)`. - * - * @note - * Whenever an event is emitted, the emitter provides the listener with a - * reference to the derived class. Listeners don't have to capture those - * instances for later uses. - * - * @tparam Event Type of event to which to connect the listener. - * @param instance The listener to register. - * @return Connection object that can be used to disconnect the listener. - */ - template - connection once(listener instance) { - return assure()->once(std::move(instance)); - } - - /** - * @brief Disconnects a listener from the event emitter. - * - * Do not use twice the same connection to disconnect a listener, it results - * in undefined behavior. Once used, discard the connection object. - * - * @tparam Event Type of event of the connection. - * @param conn A valid connection. - */ - template - void erase(connection conn) { - assure()->erase(std::move(conn)); - } - - /** - * @brief Disconnects all the listeners for the given event type. - * - * All the connections previously returned for the given event are - * invalidated. Using them results in undefined behavior. - * - * @tparam Event Type of event to reset. - */ - template - void clear() { - assure()->clear(); - } - - /** - * @brief Disconnects all the listeners. - * - * All the connections previously returned are invalidated. Using them - * results in undefined behavior. - */ - void clear() ENTT_NOEXCEPT { - for(auto &&cpool: pools) { - if(cpool) { - cpool->clear(); - } - } - } - - /** - * @brief Checks if there are listeners registered for the specific event. - * @tparam Event Type of event to test. - * @return True if there are no listeners registered, false otherwise. - */ - template - [[nodiscard]] bool empty() const { - const auto *cpool = assure(); - return !cpool || cpool->empty(); - } - - /** - * @brief Checks if there are listeners registered with the event emitter. - * @return True if there are no listeners registered, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return std::all_of(pools.cbegin(), pools.cend(), [](auto &&cpool) { - return !cpool || cpool->empty(); - }); - } - -private: - std::vector> pools{}; -}; - - -} - - -#endif - -// #include "signal/sigh.hpp" -#ifndef ENTT_SIGNAL_SIGH_HPP -#define ENTT_SIGNAL_SIGH_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "delegate.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - -/** - * @brief Sink class. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - */ -template -class sink; - - -/** - * @brief Unmanaged signal handler. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - */ -template -class sigh; - - -/** - * @brief Unmanaged signal handler. - * - * It works directly with references to classes and pointers to member functions - * as well as pointers to free functions. Users of this class are in charge of - * disconnecting instances before deleting them. - * - * This class serves mainly two purposes: - * - * * Creating signals to use later to notify a bunch of listeners. - * * Collecting results from a set of functions like in a voting system. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class sigh { - /*! @brief A sink is allowed to modify a signal. */ - friend class sink; - -public: - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Sink type. */ - using sink_type = sink; - - /** - * @brief Instance type when it comes to connecting member functions. - * @tparam Class Type of class to which the member function belongs. - */ - template - using instance_type = Class *; - - /** - * @brief Number of listeners connected to the signal. - * @return Number of listeners currently connected. - */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return calls.size(); - } - - /** - * @brief Returns false if at least a listener is connected to the signal. - * @return True if the signal has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return calls.empty(); - } - - /** - * @brief Triggers a signal. - * - * All the listeners are notified. Order isn't guaranteed. - * - * @param args Arguments to use to invoke listeners. - */ - void publish(Args... args) const { - for(auto &&call: std::as_const(calls)) { - call(args...); - } - } - - /** - * @brief Collects return values from the listeners. - * - * The collector must expose a call operator with the following properties: - * - * * The return type is either `void` or such that it's convertible to - * `bool`. In the second case, a true value will stop the iteration. - * * The list of parameters is empty if `Ret` is `void`, otherwise it - * contains a single element such that `Ret` is convertible to it. - * - * @tparam Func Type of collector to use, if any. - * @param func A valid function object. - * @param args Arguments to use to invoke listeners. - */ - template - void collect(Func func, Args... args) const { - for(auto &&call: calls) { - if constexpr(std::is_void_v) { - if constexpr(std::is_invocable_r_v) { - call(args...); - if(func()) { break; } - } else { - call(args...); - func(); - } - } else { - if constexpr(std::is_invocable_r_v) { - if(func(call(args...))) { break; } - } else { - func(call(args...)); - } - } - } - } - -private: - std::vector> calls; -}; - - -/** - * @brief Connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it. - */ -class connection { - /*! @brief A sink is allowed to create connection objects. */ - template - friend class sink; - - connection(delegate fn, void *ref) - : disconnect{fn}, signal{ref} - {} - -public: - /*! @brief Default constructor. */ - connection() = default; - - /** - * @brief Checks whether a connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(disconnect); - } - - /*! @brief Breaks the connection. */ - void release() { - if(disconnect) { - disconnect(signal); - disconnect.reset(); - } - } - -private: - delegate disconnect; - void *signal{}; -}; - - -/** - * @brief Scoped connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it.
- * A scoped connection automatically breaks the link between the two objects - * when it goes out of scope. - */ -struct scoped_connection { - /*! @brief Default constructor. */ - scoped_connection() = default; - - /** - * @brief Constructs a scoped connection from a basic connection. - * @param other A valid connection object. - */ - scoped_connection(const connection &other) - : conn{other} - {} - - /*! @brief Default copy constructor, deleted on purpose. */ - scoped_connection(const scoped_connection &) = delete; - - /*! @brief Automatically breaks the link on destruction. */ - ~scoped_connection() { - conn.release(); - } - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This scoped connection. - */ - scoped_connection & operator=(const scoped_connection &) = delete; - - /** - * @brief Acquires a connection. - * @param other The connection object to acquire. - * @return This scoped connection. - */ - scoped_connection & operator=(connection other) { - conn = std::move(other); - return *this; - } - - /** - * @brief Checks whether a scoped connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { - return static_cast(conn); - } - - /*! @brief Breaks the connection. */ - void release() { - conn.release(); - } - -private: - connection conn; -}; - - -/** - * @brief Sink class. - * - * A sink is used to connect listeners to signals and to disconnect them.
- * The function type for a listener is the one of the signal to which it - * belongs. - * - * The clear separation between a signal and a sink permits to store the former - * as private data member without exposing the publish functionality to the - * users of the class. - * - * @warning - * Lifetime of a sink must not overcome that of the signal to which it refers. - * In any other case, attempting to use a sink results in undefined behavior. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class sink { - using signal_type = sigh; - using difference_type = typename std::iterator_traits::difference_type; - - template - static void release(Type value_or_instance, void *signal) { - sink{*static_cast(signal)}.disconnect(value_or_instance); - } - - template - static void release(void *signal) { - sink{*static_cast(signal)}.disconnect(); - } - -public: - /** - * @brief Constructs a sink that is allowed to modify a given signal. - * @param ref A valid reference to a signal object. - */ - sink(sigh &ref) ENTT_NOEXCEPT - : offset{}, - signal{&ref} - {} - - /** - * @brief Returns false if at least a listener is connected to the sink. - * @return True if the sink has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return signal->calls.empty(); - } - - /** - * @brief Returns a sink that connects before a given free function or an - * unbound member. - * @tparam Function A valid free function pointer. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before() { - delegate call{}; - call.template connect(); - - const auto &calls = signal->calls; - const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); - - sink other{*this}; - other.offset = std::distance(it, calls.cend()); - return other; - } - - /** - * @brief Returns a sink that connects before a free function with payload - * or a bound member. - * @tparam Candidate Member or free function to look for. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type &&value_or_instance) { - delegate call{}; - call.template connect(value_or_instance); - - const auto &calls = signal->calls; - const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); - - sink other{*this}; - other.offset = std::distance(it, calls.cend()); - return other; - } - - /** - * @brief Returns a sink that connects before a given instance or specific - * payload. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type &value_or_instance) { - return before(&value_or_instance); - } - - /** - * @brief Returns a sink that connects before a given instance or specific - * payload. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - * @return A properly initialized sink object. - */ - template - [[nodiscard]] sink before(Type *value_or_instance) { - sink other{*this}; - - if(value_or_instance) { - const auto &calls = signal->calls; - const auto it = std::find_if(calls.cbegin(), calls.cend(), [value_or_instance](const auto &delegate) { - return delegate.instance() == value_or_instance; - }); - - other.offset = std::distance(it, calls.cend()); - } - - return other; - } - - /** - * @brief Returns a sink that connects before anything else. - * @return A properly initialized sink object. - */ - [[nodiscard]] sink before() { - sink other{*this}; - other.offset = signal->calls.size(); - return other; - } - - /** - * @brief Connects a free function or an unbound member to a signal. - * - * The signal handler performs checks to avoid multiple connections for the - * same function. - * - * @tparam Candidate Function or member to connect to the signal. - * @return A properly initialized connection object. - */ - template - connection connect() { - disconnect(); - - delegate call{}; - call.template connect(); - signal->calls.insert(signal->calls.end() - offset, std::move(call)); - - delegate conn{}; - conn.template connect<&release>(); - return { std::move(conn), signal }; - } - - /** - * @brief Connects a free function with payload or a bound member to a - * signal. - * - * The signal isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the signal. On the other side, the signal handler performs - * checks to avoid multiple connections for the same function.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the signal itself. - * - * @tparam Candidate Function or member to connect to the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @return A properly initialized connection object. - */ - template - connection connect(Type &&value_or_instance) { - disconnect(value_or_instance); - - delegate call{}; - call.template connect(value_or_instance); - signal->calls.insert(signal->calls.end() - offset, std::move(call)); - - delegate conn{}; - conn.template connect<&release>(value_or_instance); - return { std::move(conn), signal }; - } - - /** - * @brief Disconnects a free function or an unbound member from a signal. - * @tparam Candidate Function or member to disconnect from the signal. - */ - template - void disconnect() { - auto &calls = signal->calls; - delegate call{}; - call.template connect(); - calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); - } - - /** - * @brief Disconnects a free function with payload or a bound member from a - * signal. - * @tparam Candidate Function or member to disconnect from the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &&value_or_instance) { - auto &calls = signal->calls; - delegate call{}; - call.template connect(value_or_instance); - calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &value_or_instance) { - disconnect(&value_or_instance); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type *value_or_instance) { - if(value_or_instance) { - auto &calls = signal->calls; - calls.erase(std::remove_if(calls.begin(), calls.end(), [value_or_instance](const auto &delegate) { - return delegate.instance() == value_or_instance; - }), calls.end()); - } - } - - /*! @brief Disconnects all the listeners from a signal. */ - void disconnect() { - signal->calls.clear(); - } - -private: - difference_type offset; - signal_type *signal; -}; - - -/** - * @brief Deduction guide. - * - * It allows to deduce the function type of a sink directly from the signal it - * refers to. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -sink(sigh &) --> sink; - - -} - - -#endif - diff --git a/premake5.lua b/premake5.lua index 834d9165..dad728f4 100644 --- a/premake5.lua +++ b/premake5.lua @@ -171,7 +171,8 @@ project "Nuake" "%{prj.name}/dependencies/msdf-atlas-gen/msdfgen", "%{prj.name}/dependencies/msdf-atlas-gen/msdfgen/include", "%{prj.name}/dependencies/freetype/include", - "%{prj.name}/../Nuake/dependencies/tracy/public/tracy", + "%{prj.name}/dependencies/tracy/public/tracy", + "%{prj.name}/dependencies/entt/src", } @@ -263,6 +264,7 @@ project "NuakeRuntime" "%{prj.name}/../Nuake/dependencies/recastnavigation/Recast/Include", "%{prj.name}/../Nuake/dependencies/tracy/public/tracy", + "%{prj.name}/../Nuake/dependencies/entt/src", } libdirs @@ -313,7 +315,7 @@ project "NuakeRuntime" '{COPYFILE} "%{wks.location}/Nuake/dependencies/Coral/Coral.Managed/Coral.Managed.runtimeconfig.json" "%{wks.location}/%{prj.name}"' } - filter { "system:windows", "action:vs*"} + filter { "system:windows", "action:vs*" } flags { "MultiProcessorCompile", @@ -393,7 +395,10 @@ project "Editor" { "%{prj.name}/Editor.cpp", "%{prj.name}/src/**.cpp", - "%{prj.name}/src/**.h" + "%{prj.name}/src/**.h", + + -- This isn't ideal, but it works...needs a proper way of doing this, but that's for another time + "Nuake/dependencies/entt/natvis/entt/*.natvis" } includedirs @@ -420,6 +425,7 @@ project "Editor" "%{prj.name}/../Nuake/dependencies/msdf-atlas-gen/msdfgen/include", "%{prj.name}/../Nuake/dependencies/freetype/include", "%{prj.name}/../Nuake/dependencies/tracy/public/tracy", + "%{prj.name}/../Nuake/dependencies/entt/src", } From bf6fb0f8b6a096c9c4f9469b750ac06321c3dcff Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:33:09 +0100 Subject: [PATCH 02/29] Fix for entt update --- Nuake/src/Scene/Scene.cpp | 8 ++++---- Nuake/src/Scene/Scene.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 2ae9bc3a..a48f3e6b 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -469,7 +469,6 @@ namespace Nuake } entity.Destroy(); - m_Registry.shrink_to_fit(); } bool Scene::EntityExists(const std::string& name) @@ -638,11 +637,12 @@ namespace Nuake // This will turn the deserialized entity ids into actual Entities. // This has to be done after the whole scene has been deserialized - // to make sure we can fetch the id in the scene. Otherwise, we could - m_Registry.each([this](auto e) { + // to make sure we can fetch the id in the scene. Otherwise, we could + for (const entt::entity& e : m_Registry.view()) + { auto entity = Entity{ e, this }; entity.PostDeserialize(); - }); + }; return true; } diff --git a/Nuake/src/Scene/Scene.h b/Nuake/src/Scene/Scene.h index 47cd63cf..aa3e6ff7 100644 --- a/Nuake/src/Scene/Scene.h +++ b/Nuake/src/Scene/Scene.h @@ -2,7 +2,7 @@ #include "src/Core/Core.h" #include "src/Core/Maths.h" -#include "entt/entt.hpp" +#include #include "src/Rendering/Camera.h" #include "Lighting/Environment.h" From 7d66a19ab23706546e7550f23c19d69cef6d3307 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:37:08 +0100 Subject: [PATCH 03/29] Architecture rework for components to accomodate for reflection --- Nuake/Engine.cpp | 5 ++ Nuake/src/Core/Object/ClassDB.cpp | 5 ++ Nuake/src/Core/Object/ClassDB.h | 14 ++++ Nuake/src/Core/Object/Object.h | 70 +++++++++++++++++-- Nuake/src/Core/RegisterCoreTypes.cpp | 47 +++++++++++++ Nuake/src/Core/RegisterCoreTypes.h | 11 +++ Nuake/src/Scene/Components.h | 2 +- .../Scene/Components/AudioEmitterComponent.h | 5 +- .../src/Scene/Components/BSPBrushComponent.h | 5 +- Nuake/src/Scene/Components/BoneComponent.h | 6 +- Nuake/src/Scene/Components/BoxCollider.h | 45 ++++++++---- Nuake/src/Scene/Components/CameraComponent.h | 4 +- .../Components/CapsuleColliderComponent.h | 5 +- .../Components/CharacterControllerComponent.h | 5 +- Nuake/src/Scene/Components/Component.cpp | 15 ++++ Nuake/src/Scene/Components/Component.h | 20 ++++++ .../Components/CylinderColliderComponent.h | 5 +- Nuake/src/Scene/Components/LightComponent.h | 6 +- Nuake/src/Scene/Components/MeshCollider.h | 8 ++- Nuake/src/Scene/Components/ModelComponent.h | 5 +- .../Scene/Components/NavMeshVolumeComponent.h | 5 +- .../src/Scene/Components/NetScriptComponent.h | 5 +- .../Components/ParticleEmitterComponent.h | 5 +- Nuake/src/Scene/Components/QuakeMap.h | 10 +-- .../src/Scene/Components/RigidbodyComponent.h | 7 +- .../Scene/Components/SkinnedModelComponent.h | 8 +-- Nuake/src/Scene/Components/SphereCollider.h | 8 ++- Nuake/src/Scene/Components/SpriteComponent.h | 5 +- Nuake/src/Scene/Components/UIComponent.h | 50 ++++++------- ...{BaseComponent.h => VisibilityComponent.h} | 0 Nuake/src/Scene/Entities/Entity.h | 1 - 31 files changed, 302 insertions(+), 90 deletions(-) create mode 100644 Nuake/src/Core/Object/ClassDB.cpp create mode 100644 Nuake/src/Core/Object/ClassDB.h create mode 100644 Nuake/src/Core/RegisterCoreTypes.cpp create mode 100644 Nuake/src/Core/RegisterCoreTypes.h create mode 100644 Nuake/src/Scene/Components/Component.cpp create mode 100644 Nuake/src/Scene/Components/Component.h rename Nuake/src/Scene/Components/{BaseComponent.h => VisibilityComponent.h} (100%) diff --git a/Nuake/Engine.cpp b/Nuake/Engine.cpp index b0be2537..6aa24c16 100644 --- a/Nuake/Engine.cpp +++ b/Nuake/Engine.cpp @@ -13,6 +13,7 @@ #include "src/Scripting/ScriptingEngine.h" #include "src/Scripting/ScriptingEngineNet.h" #include "src/Threading/JobSystem.h" +#include "src/Core/RegisterCoreTypes.h" #include "src/Modules/Modules.h" #include @@ -20,6 +21,8 @@ #include #include + + namespace Nuake { Ref Engine::currentProject; @@ -48,6 +51,8 @@ namespace Nuake Renderer2D::Init(); Logger::Log("Engine initialized"); + RegisterCoreTypes::RegisterCoreComponents(); + Modules::StartupModules(); } diff --git a/Nuake/src/Core/Object/ClassDB.cpp b/Nuake/src/Core/Object/ClassDB.cpp new file mode 100644 index 00000000..0aefb9d7 --- /dev/null +++ b/Nuake/src/Core/Object/ClassDB.cpp @@ -0,0 +1,5 @@ +#include "ClassDB.h" + +namespace Nuake +{ +} diff --git a/Nuake/src/Core/Object/ClassDB.h b/Nuake/src/Core/Object/ClassDB.h new file mode 100644 index 00000000..dde82bfa --- /dev/null +++ b/Nuake/src/Core/Object/ClassDB.h @@ -0,0 +1,14 @@ +#pragma once + +namespace Nuake +{ + class ClassDB + { + public: + template + static void RegisterComponent(T klass) + { + T::InternalInitializeClass(); + } + }; +} diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index 8c065dc6..127d8d92 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -1,16 +1,46 @@ #pragma once #include +#include -#define NK_HASHED_FN_NAME_IMPL(name) inline static constexpr entt::hashed_string name = entt::hashed_string(#name); +#define NK_HASHED_STATIC_STR(name) inline static constexpr entt::hashed_string name = entt::hashed_string(#name); namespace Nuake { struct HashedFnName { - NK_HASHED_FN_NAME_IMPL(GetComponentName) - NK_HASHED_FN_NAME_IMPL(AddToEntity) + NK_HASHED_STATIC_STR(GetComponentName) + NK_HASHED_STATIC_STR(AddToEntity) }; + + struct HashedName + { + NK_HASHED_STATIC_STR(DisplayName) + }; + + enum class ComponentTypeTrait : uint16_t + { + None = 0, + InspectorExposed = 1 << 0, + + + }; + + template + constexpr std::underlying_type_t ToUnderlying(Enum e) + { + return static_cast>(e); + } + + inline ComponentTypeTrait operator|(ComponentTypeTrait lhs, ComponentTypeTrait rhs) + { + return static_cast(ToUnderlying(lhs) | ToUnderlying(rhs)); + } + + inline ComponentTypeTrait operator&(ComponentTypeTrait lhs, ComponentTypeTrait rhs) + { + return static_cast(ToUnderlying(lhs) & ToUnderlying(rhs)); + } } #define NUAKECOMPONENT(klass, componentName) \ @@ -32,7 +62,33 @@ public: enttRegistry->emplace_or_replace(entity); \ } \ \ - inline static auto ComponentFactory = entt::meta() \ - .type(entt::hashed_string(#klass)) \ - .func<&klass::ComponentName>(HashedFnName::GetComponentName) \ - .func<&klass::AddToEntity>(HashedFnName::AddToEntity); + \ + static void (*GetInitializeComponentClass())() \ + { \ + return &klass::InitializeComponentClass; \ + } \ + \ + inline static auto ComponentFactory = entt::meta(); \ + static void InternalInitializeClass() \ + { \ + static bool initialized = false; \ + if (initialized) \ + return; \ + \ + ComponentFactory.type(entt::hashed_string(#klass)) \ + .traits(ComponentTypeTrait::InspectorExposed); \ + ComponentFactory.func<&klass::ComponentName>(HashedFnName::GetComponentName); \ + ComponentFactory.func<&klass::AddToEntity>(HashedFnName::AddToEntity); \ + \ + if (klass::GetInitializeComponentClass() != Component::GetInitializeComponentClass()) \ + { \ + GetInitializeComponentClass()(); \ + } \ + \ + initialized = true; \ + } + +#define BINDCOMPONENTFIELD(field, displayName) \ + ComponentFactory \ + .data<&field>(entt::hashed_string(#field)) \ + .prop(HashedName::DisplayName, displayName) \ No newline at end of file diff --git a/Nuake/src/Core/RegisterCoreTypes.cpp b/Nuake/src/Core/RegisterCoreTypes.cpp new file mode 100644 index 00000000..7e820e98 --- /dev/null +++ b/Nuake/src/Core/RegisterCoreTypes.cpp @@ -0,0 +1,47 @@ +#include "RegisterCoreTypes.h" + +#include "src/Scene/Components/AudioEmitterComponent.h" +#include "src/Scene/Components/BoneComponent.h" +#include "src/Scene/Components/BoxCollider.h" +#include "src/Scene/Components/CameraComponent.h" +#include "src/Scene/Components/CapsuleColliderComponent.h" +#include "src/Scene/Components/CharacterControllerComponent.h" +#include "src/Scene/Components/CylinderColliderComponent.h" +#include "src/Scene/Components/MeshCollider.h" +#include "src/Scene/Components/ModelComponent.h" +#include "src/Scene/Components/NavMeshVolumeComponent.h" +#include "src/Scene/Components/NetScriptComponent.h" +#include "src/Scene/Components/ParticleEmitterComponent.h" +#include "src/Scene/Components/QuakeMap.h" +#include "src/Scene/Components/RigidbodyComponent.h" +#include "src/Scene/Components/SkinnedModelComponent.h" +#include "src/Scene/Components/SphereCollider.h" +#include "src/Scene/Components/SpriteComponent.h" +#include "src/Scene/Components/UIComponent.h" + +namespace Nuake +{ + void RegisterCoreTypes::RegisterCoreComponents() + { + UIComponent::InternalInitializeClass(); + SpriteComponent::InternalInitializeClass(); + SphereColliderComponent::InternalInitializeClass(); + SkinnedModelComponent::InternalInitializeClass(); + RigidBodyComponent::InternalInitializeClass(); + QuakeMapComponent::InternalInitializeClass(); + ParticleEmitterComponent::InternalInitializeClass(); + NetScriptComponent::InternalInitializeClass(); + NavMeshVolumeComponent::InternalInitializeClass(); + ModelComponent::InternalInitializeClass(); + MeshColliderComponent::InternalInitializeClass(); + LightComponent::InternalInitializeClass(); + CylinderColliderComponent::InternalInitializeClass(); + CharacterControllerComponent::InternalInitializeClass(); + CapsuleColliderComponent::InternalInitializeClass(); + CameraComponent::InternalInitializeClass(); + BoxColliderComponent::InternalInitializeClass(); + BoneComponent::InternalInitializeClass(); + AudioEmitterComponent::InternalInitializeClass(); + } +} + diff --git a/Nuake/src/Core/RegisterCoreTypes.h b/Nuake/src/Core/RegisterCoreTypes.h new file mode 100644 index 00000000..c7a8b686 --- /dev/null +++ b/Nuake/src/Core/RegisterCoreTypes.h @@ -0,0 +1,11 @@ +#pragma once + +namespace Nuake +{ + class RegisterCoreTypes + { + public: + static void RegisterCoreComponents(); + }; +} + diff --git a/Nuake/src/Scene/Components.h b/Nuake/src/Scene/Components.h index c99682ca..37ad6487 100644 --- a/Nuake/src/Scene/Components.h +++ b/Nuake/src/Scene/Components.h @@ -1,7 +1,7 @@ #pragma once #include "Components/AudioEmitterComponent.h" -#include "Components/BaseComponent.h" +#include "Components/VisibilityComponent.h" #include "Components/BoneComponent.h" #include "Components/BoxCollider.h" #include "Components/BSPBrushComponent.h" diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.h b/Nuake/src/Scene/Components/AudioEmitterComponent.h index bebfd6fb..7f5d69e8 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.h +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.h @@ -1,12 +1,13 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Core/Core.h" #include "src/Resource/Serializable.h" namespace Nuake { - class AudioEmitterComponent + class AudioEmitterComponent : public Component { NUAKECOMPONENT(AudioEmitterComponent, "Audio Emitter") diff --git a/Nuake/src/Scene/Components/BSPBrushComponent.h b/Nuake/src/Scene/Components/BSPBrushComponent.h index b4ba41cc..4e33a5c1 100644 --- a/Nuake/src/Scene/Components/BSPBrushComponent.h +++ b/Nuake/src/Scene/Components/BSPBrushComponent.h @@ -1,4 +1,7 @@ #pragma once + +#include "Component.h" + #include "src/Core/Core.h" #include "src/Core/Maths.h" @@ -7,7 +10,7 @@ #include "src/Physics/Rigibody.h" namespace Nuake { - class BSPBrushComponent + class BSPBrushComponent : public Component { public: //std::vector> Meshes; diff --git a/Nuake/src/Scene/Components/BoneComponent.h b/Nuake/src/Scene/Components/BoneComponent.h index f1c9a8b8..6688ee92 100644 --- a/Nuake/src/Scene/Components/BoneComponent.h +++ b/Nuake/src/Scene/Components/BoneComponent.h @@ -1,13 +1,13 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Core/Core.h" #include "src/Resource/Serializable.h" - namespace Nuake { - class BoneComponent + class BoneComponent : public Component { NUAKECOMPONENT(BoneComponent, "Bone") diff --git a/Nuake/src/Scene/Components/BoxCollider.h b/Nuake/src/Scene/Components/BoxCollider.h index 80c84d60..be5f4cdc 100644 --- a/Nuake/src/Scene/Components/BoxCollider.h +++ b/Nuake/src/Scene/Components/BoxCollider.h @@ -1,22 +1,41 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Physics/PhysicsShapes.h" #include "src/Core/Core.h" -namespace Nuake { +namespace Nuake +{ + class BoxColliderComponent : public Component + { + NUAKECOMPONENT(BoxColliderComponent, "Box Collider") - class BoxColliderComponent - { - NUAKECOMPONENT(BoxColliderComponent, "Box Collider") + static void InitializeComponentClass() + { + BINDCOMPONENTFIELD(BoxColliderComponent::IsTrigger, "Is Trigger"); - public: - Ref Box; - Vector3 Size = Vector3(0.5f, 0.5f, 0.5f); - bool IsTrigger = false; + ComponentFactory + .data<&BoxColliderComponent::SetSize, &BoxColliderComponent::GetSize>(entt::hashed_string("size")) + .prop(HashedName::DisplayName, "Size"); + } - json Serialize(); - bool Deserialize(const json& j); - }; + public: + Ref Box; + Vector3 Size = Vector3(0.5f, 0.5f, 0.5f); + bool IsTrigger = true; + + void SetSize(const Vector3& newSize) + { + Size = newSize; + } + + Vector3 GetSize() + { + return Size; + } + + json Serialize(); + bool Deserialize(const json& j); + }; } - \ No newline at end of file diff --git a/Nuake/src/Scene/Components/CameraComponent.h b/Nuake/src/Scene/Components/CameraComponent.h index b62b7cf8..f4f1cf2d 100644 --- a/Nuake/src/Scene/Components/CameraComponent.h +++ b/Nuake/src/Scene/Components/CameraComponent.h @@ -1,6 +1,6 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" #include "TransformComponent.h" #include "src/Core/Core.h" @@ -10,7 +10,7 @@ namespace Nuake { - class CameraComponent + class CameraComponent : public Component { NUAKECOMPONENT(CameraComponent, "Camera") diff --git a/Nuake/src/Scene/Components/CapsuleColliderComponent.h b/Nuake/src/Scene/Components/CapsuleColliderComponent.h index a0114945..ee146789 100644 --- a/Nuake/src/Scene/Components/CapsuleColliderComponent.h +++ b/Nuake/src/Scene/Components/CapsuleColliderComponent.h @@ -1,12 +1,13 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Physics/PhysicsShapes.h" #include "src/Core/Core.h" namespace Nuake { - class CapsuleColliderComponent + class CapsuleColliderComponent : public Component { NUAKECOMPONENT(CapsuleColliderComponent, "Capsule Collider") diff --git a/Nuake/src/Scene/Components/CharacterControllerComponent.h b/Nuake/src/Scene/Components/CharacterControllerComponent.h index 7d39bec1..9060cf09 100644 --- a/Nuake/src/Scene/Components/CharacterControllerComponent.h +++ b/Nuake/src/Scene/Components/CharacterControllerComponent.h @@ -1,11 +1,12 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Physics/CharacterController.h" namespace Nuake { - class CharacterControllerComponent + class CharacterControllerComponent : public Component { NUAKECOMPONENT(CharacterControllerComponent, "Character Controller") diff --git a/Nuake/src/Scene/Components/Component.cpp b/Nuake/src/Scene/Components/Component.cpp new file mode 100644 index 00000000..f8870d84 --- /dev/null +++ b/Nuake/src/Scene/Components/Component.cpp @@ -0,0 +1,15 @@ +#include "Component.h" + +using namespace Nuake; + +std::string Component::GetName(const entt::meta_type& componentMeta) +{ + // TODO: [WiggleWizard] Needs some error handling + if (entt::meta_func func = componentMeta.func(HashedFnName::GetComponentName)) + { + entt::meta_any ret = func.invoke(componentMeta); + return ret.cast(); + } + + return "Unknown Component"; +} diff --git a/Nuake/src/Scene/Components/Component.h b/Nuake/src/Scene/Components/Component.h new file mode 100644 index 00000000..5bfe9f06 --- /dev/null +++ b/Nuake/src/Scene/Components/Component.h @@ -0,0 +1,20 @@ +#pragma once + +#include "src/Core/Object/Object.h" + +namespace Nuake +{ + class Component + { + protected: + static void InitializeComponentClass() {} + + static void (* GetInitializeComponentClass(void))() + { + return &Component::InitializeComponentClass; + } + + public: + static std::string GetName(const entt::meta_type& componentMeta); + }; +} diff --git a/Nuake/src/Scene/Components/CylinderColliderComponent.h b/Nuake/src/Scene/Components/CylinderColliderComponent.h index 3aa31b29..fefa5c27 100644 --- a/Nuake/src/Scene/Components/CylinderColliderComponent.h +++ b/Nuake/src/Scene/Components/CylinderColliderComponent.h @@ -1,12 +1,13 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Physics/PhysicsShapes.h" #include "src/Core/Core.h" namespace Nuake { - class CylinderColliderComponent + class CylinderColliderComponent : public Component { NUAKECOMPONENT(CylinderColliderComponent, "Cylinder Collider") diff --git a/Nuake/src/Scene/Components/LightComponent.h b/Nuake/src/Scene/Components/LightComponent.h index 95204b52..a7d9e8a4 100644 --- a/Nuake/src/Scene/Components/LightComponent.h +++ b/Nuake/src/Scene/Components/LightComponent.h @@ -1,13 +1,13 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" #include #include #include "TransformComponent.h" #include "../Rendering/Camera.h" #include "src/Rendering/Buffers/Framebuffer.h" -#include "BaseComponent.h" +#include "VisibilityComponent.h" #include "../Resource/Serializable.h" #include @@ -20,7 +20,7 @@ namespace Nuake }; const int CSM_AMOUNT = 4; - class LightComponent + class LightComponent : public Component { NUAKECOMPONENT(LightComponent, "Light") diff --git a/Nuake/src/Scene/Components/MeshCollider.h b/Nuake/src/Scene/Components/MeshCollider.h index 8c2c32ec..d032cd33 100644 --- a/Nuake/src/Scene/Components/MeshCollider.h +++ b/Nuake/src/Scene/Components/MeshCollider.h @@ -1,11 +1,13 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Physics/PhysicsShapes.h" #include "src/Core/Core.h" -namespace Nuake { - class MeshColliderComponent +namespace Nuake +{ + class MeshColliderComponent : public Component { NUAKECOMPONENT(MeshColliderComponent, "Mesh Collider") diff --git a/Nuake/src/Scene/Components/ModelComponent.h b/Nuake/src/Scene/Components/ModelComponent.h index d130b677..ac27cfce 100644 --- a/Nuake/src/Scene/Components/ModelComponent.h +++ b/Nuake/src/Scene/Components/ModelComponent.h @@ -1,6 +1,7 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Core/String.h" #include "src/Resource/Model.h" #include "src/Resource/ResourceLoader.h" @@ -12,7 +13,7 @@ namespace Nuake { - struct ModelComponent + struct ModelComponent : public Component { NUAKECOMPONENT(ModelComponent, "Model") diff --git a/Nuake/src/Scene/Components/NavMeshVolumeComponent.h b/Nuake/src/Scene/Components/NavMeshVolumeComponent.h index 0b551ca4..a14f9ade 100644 --- a/Nuake/src/Scene/Components/NavMeshVolumeComponent.h +++ b/Nuake/src/Scene/Components/NavMeshVolumeComponent.h @@ -1,13 +1,14 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "../Entities/Entity.h" #include "Engine.h" #include namespace Nuake { - struct NavMeshVolumeComponent + struct NavMeshVolumeComponent : public Component { NUAKECOMPONENT(NavMeshVolumeComponent, "Nav Mesh Volume") diff --git a/Nuake/src/Scene/Components/NetScriptComponent.h b/Nuake/src/Scene/Components/NetScriptComponent.h index 8cd6bcfe..e3373cb4 100644 --- a/Nuake/src/Scene/Components/NetScriptComponent.h +++ b/Nuake/src/Scene/Components/NetScriptComponent.h @@ -1,6 +1,7 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Core/Core.h" #include "src/Core/Maths.h" #include "src/FileSystem/FileSystem.h" @@ -34,7 +35,7 @@ namespace Nuake { NetScriptExposedVarType Type; }; - class NetScriptComponent + class NetScriptComponent : public Component { NUAKECOMPONENT(NetScriptComponent, "Net Script") diff --git a/Nuake/src/Scene/Components/ParticleEmitterComponent.h b/Nuake/src/Scene/Components/ParticleEmitterComponent.h index fb309038..755294aa 100644 --- a/Nuake/src/Scene/Components/ParticleEmitterComponent.h +++ b/Nuake/src/Scene/Components/ParticleEmitterComponent.h @@ -1,6 +1,7 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Core/Core.h" #include "src/Core/Maths.h" #include "src/Resource/Serializable.h" @@ -10,7 +11,7 @@ namespace Nuake { - class ParticleEmitterComponent + class ParticleEmitterComponent : public Component { NUAKECOMPONENT(ParticleEmitterComponent, "Particle Emitter") diff --git a/Nuake/src/Scene/Components/QuakeMap.h b/Nuake/src/Scene/Components/QuakeMap.h index 9d9169b0..e777febf 100644 --- a/Nuake/src/Scene/Components/QuakeMap.h +++ b/Nuake/src/Scene/Components/QuakeMap.h @@ -1,17 +1,19 @@ #pragma once -#include -#include -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Rendering/Mesh/Mesh.h" #include "src/Resource/Serializable.h" #include "src/Scene/Systems/QuakeMapBuilder.h" #include "src/Scene/Entities/Entity.h" #include "Engine.h" +#include +#include + namespace Nuake { - class QuakeMapComponent + class QuakeMapComponent : public Component { NUAKECOMPONENT(QuakeMapComponent, "Quake Map") diff --git a/Nuake/src/Scene/Components/RigidbodyComponent.h b/Nuake/src/Scene/Components/RigidbodyComponent.h index 06ad21f6..66a15127 100644 --- a/Nuake/src/Scene/Components/RigidbodyComponent.h +++ b/Nuake/src/Scene/Components/RigidbodyComponent.h @@ -1,8 +1,9 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "TransformComponent.h" -#include "BaseComponent.h" +#include "VisibilityComponent.h" #include "src/Core/Core.h" namespace Nuake { @@ -11,7 +12,7 @@ namespace Nuake { class RigidBody; }; - class RigidBodyComponent + class RigidBodyComponent : public Component { NUAKECOMPONENT(RigidBodyComponent, "Rigid Body") diff --git a/Nuake/src/Scene/Components/SkinnedModelComponent.h b/Nuake/src/Scene/Components/SkinnedModelComponent.h index b33c9a07..14461f96 100644 --- a/Nuake/src/Scene/Components/SkinnedModelComponent.h +++ b/Nuake/src/Scene/Components/SkinnedModelComponent.h @@ -1,16 +1,16 @@ #pragma once -#include -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Resource/Serializable.h" #include "src/Resource/SkinnedModel.h" #include - +#include namespace Nuake { - struct SkinnedModelComponent + class SkinnedModelComponent : public Component { NUAKECOMPONENT(SkinnedModelComponent, "Skinned Model") diff --git a/Nuake/src/Scene/Components/SphereCollider.h b/Nuake/src/Scene/Components/SphereCollider.h index bd79f3d6..6ffdabfa 100644 --- a/Nuake/src/Scene/Components/SphereCollider.h +++ b/Nuake/src/Scene/Components/SphereCollider.h @@ -1,11 +1,13 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Physics/PhysicsShapes.h" #include "src/Core/Core.h" -namespace Nuake { - class SphereColliderComponent +namespace Nuake +{ + class SphereColliderComponent : public Component { NUAKECOMPONENT(SphereColliderComponent, "Sphere Component") diff --git a/Nuake/src/Scene/Components/SpriteComponent.h b/Nuake/src/Scene/Components/SpriteComponent.h index f5b06c19..f2e3f1fe 100644 --- a/Nuake/src/Scene/Components/SpriteComponent.h +++ b/Nuake/src/Scene/Components/SpriteComponent.h @@ -1,6 +1,7 @@ #pragma once -#include "src/Core/Object/Object.h" +#include "Component.h" + #include "src/Core/Core.h" #include "src/Resource/Serializable.h" #include "src/Rendering/Textures/Texture.h" @@ -8,7 +9,7 @@ namespace Nuake { - class SpriteComponent + class SpriteComponent : public Component { NUAKECOMPONENT(SpriteComponent, "Sprite") diff --git a/Nuake/src/Scene/Components/UIComponent.h b/Nuake/src/Scene/Components/UIComponent.h index 12245ec6..e5b9debf 100644 --- a/Nuake/src/Scene/Components/UIComponent.h +++ b/Nuake/src/Scene/Components/UIComponent.h @@ -1,33 +1,35 @@ #pragma once -#include "src/Core/Object/Object.h" + +#include "Component.h" +#include "src/Core/Logger.h" + #include "src/Resource/UUID.h" #include "src/Resource/Serializable.h" namespace Nuake { - struct UIComponent - { - NUAKECOMPONENT(UIComponent, "UI Component"); + struct UIComponent : public Component + { + NUAKECOMPONENT(UIComponent, "UI") - UUID UIResource = UUID(0); - std::string CSharpUIController; - std::string UIFilePath; - bool IsWorldSpace; - // TODO: Z-Ordering + public: + UUID UIResource = UUID(0); + std::string CSharpUIController; + std::string UIFilePath; + bool IsWorldSpace; + // TODO: Z-Ordering - json Serialize() - { - BEGIN_SERIALIZE(); - SERIALIZE_VAL(UIFilePath); - SERIALIZE_VAL(IsWorldSpace); - END_SERIALIZE(); - } + json Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_VAL(UIFilePath); + END_SERIALIZE(); + } - bool Deserialize(const json& j) - { - DESERIALIZE_VAL(UIFilePath); - DESERIALIZE_VAL(IsWorldSpace); - return true; - } - }; -} \ No newline at end of file + bool Deserialize(const json& j) + { + DESERIALIZE_VAL(UIFilePath); + return true; + } + }; +} diff --git a/Nuake/src/Scene/Components/BaseComponent.h b/Nuake/src/Scene/Components/VisibilityComponent.h similarity index 100% rename from Nuake/src/Scene/Components/BaseComponent.h rename to Nuake/src/Scene/Components/VisibilityComponent.h diff --git a/Nuake/src/Scene/Entities/Entity.h b/Nuake/src/Scene/Entities/Entity.h index 2abff3dc..b64d3137 100644 --- a/Nuake/src/Scene/Entities/Entity.h +++ b/Nuake/src/Scene/Entities/Entity.h @@ -4,7 +4,6 @@ #include "src/Core/Logger.h" #include "../Scene.h" -#include "../Components/BaseComponent.h" #include "../Resource/Serializable.h" #include "../Components/NameComponent.h" From 56e12c2647771d0d4cedaedc6e45e04277301b54 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:37:28 +0100 Subject: [PATCH 04/29] DrawVec3 helper now returns true if changed --- Nuake/src/Scene/Entities/ImGuiHelper.h | 31 +++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/Nuake/src/Scene/Entities/ImGuiHelper.h b/Nuake/src/Scene/Entities/ImGuiHelper.h index dde80b31..716f7530 100644 --- a/Nuake/src/Scene/Entities/ImGuiHelper.h +++ b/Nuake/src/Scene/Entities/ImGuiHelper.h @@ -8,8 +8,10 @@ class ImGuiHelper { public: - static void DrawVec3(const std::string label, glm::vec3* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f) + static bool DrawVec3(const std::string label, glm::vec3* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f) { + bool changed = false; + ImGuiIO& io = ImGui::GetIO(); auto boldFont = io.Fonts->Fonts[0]; @@ -26,13 +28,19 @@ public: ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f }); ImGui::PushFont(boldFont); if (ImGui::Button("###X", buttonSize)) + { values->x = resetValue; + changed = true; + } ImGui::PopFont(); ImGui::PopStyleColor(3); ImGui::SameLine(); ImGui::PushItemWidth(availWidth); - ImGui::DragFloat("##X", &values->x, rate, min, 0.0f, "%.2f"); + if (ImGui::DragFloat("##X", &values->x, rate, min, 0.0f, "%.2f")) + { + changed = true; + } ImGui::PopItemWidth(); ImGui::SameLine(); @@ -41,12 +49,18 @@ public: ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f }); ImGui::PushFont(boldFont); if (ImGui::Button("Y", buttonSize)) + { values->y = resetValue; + changed = true; + } ImGui::PopFont(); ImGui::PopStyleColor(3); ImGui::SameLine(); ImGui::PushItemWidth(availWidth); - ImGui::DragFloat("##Y", &values->y, rate, 0.0f, 0.0f, "%.2f"); + if (ImGui::DragFloat("##Y", &values->y, rate, 0.0f, 0.0f, "%.2f")) + { + changed = true; + } ImGui::PopItemWidth(); ImGui::SameLine(); @@ -55,19 +69,26 @@ public: ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f }); ImGui::PushFont(boldFont); if (ImGui::Button("Z", buttonSize)) + { values->z = resetValue; + changed = true; + } ImGui::PopFont(); ImGui::PopStyleColor(3); ImGui::SameLine(); ImGui::PushItemWidth(availWidth); - ImGui::DragFloat("##Z", &values->z, rate, 0.0f, 0.0f, "%.2f"); + if (ImGui::DragFloat("##Z", &values->z, rate, 0.0f, 0.0f, "%.2f")) + { + changed = true; + } ImGui::PopItemWidth(); ImGui::PopStyleVar(); ImGui::PopID(); - //ImGui::Text("Hello"); + + return changed; } static void DrawVec2(const std::string label, glm::vec2* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f) From 90a60e8d87dfca925bfe220d92c8fd98a86f1682 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:38:08 +0100 Subject: [PATCH 05/29] Initial inspector work to render using reflection --- Editor/src/Windows/EditorSelectionPanel.cpp | 167 +++++++++++++++++++- Editor/src/Windows/EditorSelectionPanel.h | 14 ++ 2 files changed, 173 insertions(+), 8 deletions(-) diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 6b581a2a..9410c9ee 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -15,6 +15,9 @@ #include +#define REGISTER_TYPE_DRAWER(forType, fn) \ + FieldTypeDrawers[entt::type_id().hash()] = std::bind(&fn, this, std::placeholders::_1, std::placeholders::_2); + using namespace Nuake; EditorSelectionPanel::EditorSelectionPanel() @@ -22,6 +25,10 @@ EditorSelectionPanel::EditorSelectionPanel() virtualScene = CreateRef(); virtualScene->SetName("Virtual Scene"); virtualScene->CreateEntity("Camera").AddComponent(); + + REGISTER_TYPE_DRAWER(bool, EditorSelectionPanel::DrawFieldTypeBool); + REGISTER_TYPE_DRAWER(float, EditorSelectionPanel::DrawFieldTypeFloat); + REGISTER_TYPE_DRAWER(Vector3, EditorSelectionPanel::DrawFieldTypeVector3); } void EditorSelectionPanel::ResolveFile(Ref file) @@ -117,6 +124,29 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) DrawAddComponentMenu(entity); + entt::registry& registry = entity.GetScene()->m_Registry; + for (auto&& [componentTypeId, storage] : registry.storage()) + { + entt::type_info componentType = storage.type(); + + entt::entity entityId = static_cast(entity.GetHandle()); + if (storage.contains(entityId)) + { + entt::meta_type type = entt::resolve(componentType); + entt::meta_any component = type.from_void(storage.value(entityId)); + + ComponentTypeTrait typeTraits = type.traits(); + // Component not exposed as an inspector panel + if ((typeTraits & ComponentTypeTrait::InspectorExposed) == ComponentTypeTrait::None) + { + continue; + } + + DrawComponent(entity, component); + } + } + + // Draw each component properties panels. mTransformPanel.Draw(entity); mLightPanel.Draw(entity); @@ -154,16 +184,12 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) if (ImGui::BeginPopup("ComponentPopup")) { - for(entt::meta_type t : entt::resolve()) + for(auto [fst, component] : entt::resolve()) { - if (entt::meta_func func = t.func(HashedFnName::GetComponentName)) + std::string componentName = Component::GetName(component); + if (ImGui::MenuItem(componentName.c_str())) { - entt::meta_any ret = func.invoke(t); - std::string className = ret.cast(); - if (ImGui::MenuItem(className.c_str())) - { - entity.AddComponent(t); - } + entity.AddComponent(component); } } @@ -511,3 +537,128 @@ void EditorSelectionPanel::DrawNetScriptPanel(Ref file) ImGui::PopTextWrapPos(); } +void EditorSelectionPanel::DrawComponent(const Nuake::Entity& entity, entt::meta_any& component) +{ + const entt::meta_type componentMeta = component.type(); + const std::string componentName = Component::GetName(componentMeta); + + UIFont* boldFont = new UIFont(Fonts::Bold); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f); + bool removed = false; + bool headerOpened = ImGui::CollapsingHeader(componentName.c_str(), ImGuiTreeNodeFlags_DefaultOpen); + + ImGui::PopStyleVar(); + if (strcmp(componentName.c_str(), "TRANSFORM") != 0 && ImGui::BeginPopupContextItem()) + { + if (ImGui::Selectable("Remove")) { removed = true; } + ImGui::EndPopup(); + } + + if(removed) + { + // entity.RemoveComponent(); + ImGui::PopStyleVar(); + delete boldFont; + } + else if (headerOpened) + { + delete boldFont; + ImGui::PopStyleVar(); + ImGui::Indent(); + + if (ImGui::BeginTable(componentName.c_str(), 3, ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.25f); + ImGui::TableSetupColumn("set", 0, 0.65f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + DrawComponentContent(component); + + ImGui::EndTable(); + } + ImGui::Unindent(); + } + else + { + ImGui::PopStyleVar(); + delete boldFont; + } + ImGui::PopStyleVar(); +} + +void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) +{ + entt::meta_type componentMeta = component.type(); + for (auto [fst, dataType] : componentMeta.data()) + { + ImGui::TableNextColumn(); + + // Search for the appropriate drawer for the type + entt::id_type dataId = dataType.type().id(); + if (FieldTypeDrawers.contains(dataId)) + { + auto drawerFn = FieldTypeDrawers[dataId]; + drawerFn(dataType, component); + } + } +} + +void EditorSelectionPanel::DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component) +{ + ImGui::Text("Hello World!!!"); +} + +void EditorSelectionPanel::DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component) +{ + auto prop = field.prop(HashedName::DisplayName); + auto propVal = prop.value(); + const char* displayName = *propVal.try_cast(); + + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + bool* boolPtr = fieldVal.try_cast(); + if (boolPtr != nullptr) + { + bool boolProxy = *boolPtr; + if (ImGui::Checkbox("##isTrigger", &boolProxy)) + { + field.set(component, boolProxy); + } + } + else + { + ImGui::Text("ERR"); + } + + ImGui::TableNextColumn(); + } +} + +void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component) +{ + auto prop = field.prop(HashedName::DisplayName); + auto propVal = prop.value(); + const char* displayName = *propVal.try_cast(); + + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + Vector3* vec3Ptr = fieldVal.try_cast(); + if (ImGuiHelper::DrawVec3("BoxSize", vec3Ptr, 0.5f, 100.0, 0.01f)) + { + field.set(component, *vec3Ptr); + } + + ImGui::TableNextColumn(); + } +} + diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 82f3fb0c..8d8bb1f2 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -38,6 +38,8 @@ namespace Nuake class EditorSelectionPanel { + using DrawFieldTypeFn = std::function; + private: TransformPanel mTransformPanel; LightPanel mLightPanel; @@ -77,10 +79,22 @@ public: void DrawFile(Ref file); void DrawResource(Nuake::Resource resource); void DrawPrefabPanel(Ref prefab); + +protected: + // List of functions to call for each type that needs to be drawn + std::unordered_map FieldTypeDrawers; + private: void ResolveFile(Ref file); void DrawMaterialPanel(Ref material); void DrawProjectPanel(Ref project); void DrawWrenScriptPanel(Ref wrenFile); void DrawNetScriptPanel(Ref file); + + void DrawComponent(const Nuake::Entity& entity, entt::meta_any& component); + void DrawComponentContent(entt::meta_any& component); + + void DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component); }; \ No newline at end of file From 68ffe1d6b488f1f60b78b60ac23e6ef0fe55e2e0 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 21:43:22 +0100 Subject: [PATCH 06/29] Basic inspector reflection working for 2 components --- Editor/src/Windows/EditorSelectionPanel.cpp | 95 ++++++++++++++----- Nuake/src/Core/Object/Object.h | 39 ++++++-- .../Scene/Components/AudioEmitterComponent.h | 22 +++++ Nuake/src/Scene/Components/BoxCollider.h | 7 +- 4 files changed, 126 insertions(+), 37 deletions(-) diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 9410c9ee..c5482feb 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -124,6 +124,8 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) DrawAddComponentMenu(entity); + mTransformPanel.Draw(entity); + entt::registry& registry = entity.GetScene()->m_Registry; for (auto&& [componentTypeId, storage] : registry.storage()) { @@ -148,27 +150,26 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) // Draw each component properties panels. - mTransformPanel.Draw(entity); - mLightPanel.Draw(entity); - mScriptPanel.Draw(entity); - mNetScriptPanel.Draw(entity); - mAudioEmitterPanel.Draw(entity); - mParticleEmitterPanel.Draw(entity); - mSpritePanel.Draw(entity); - mMeshPanel.Draw(entity); - mSkinnedModelPanel.Draw(entity); - mBonePanel.Draw(entity); - mQuakeMapPanel.Draw(entity); - mCameraPanel.Draw(entity); - mRigidbodyPanel.Draw(entity); - mBoxColliderPanel.Draw(entity); - mSphereColliderPanel.Draw(entity); - mCapsuleColliderPanel.Draw(entity); - mCylinderColliderPanel.Draw(entity); - mMeshColliderPanel.Draw(entity); - mCharacterControllerPanel.Draw(entity); - mNavMeshVolumePanel.Draw(entity); - mUiPanel.Draw(entity); + // mLightPanel.Draw(entity); + // mScriptPanel.Draw(entity); + // mNetScriptPanel.Draw(entity); + // mAudioEmitterPanel.Draw(entity); + // mParticleEmitterPanel.Draw(entity); + // mSpritePanel.Draw(entity); + // mMeshPanel.Draw(entity); + // mSkinnedModelPanel.Draw(entity); + // mBonePanel.Draw(entity); + // mQuakeMapPanel.Draw(entity); + // mCameraPanel.Draw(entity); + // mRigidbodyPanel.Draw(entity); + // mBoxColliderPanel.Draw(entity); + // mSphereColliderPanel.Draw(entity); + // mCapsuleColliderPanel.Draw(entity); + // mCylinderColliderPanel.Draw(entity); + // mMeshColliderPanel.Draw(entity); + // mCharacterControllerPanel.Draw(entity); + // mNavMeshVolumePanel.Draw(entity); + // mUiPanel.Draw(entity); using namespace Nuake; @@ -607,7 +608,43 @@ void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) void EditorSelectionPanel::DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component) { - ImGui::Text("Hello World!!!"); + float stepSize = 1.f; + if (auto prop = field.prop(HashedFieldPropName::FloatStep)) + stepSize = *prop.value().try_cast(); + + float min = 0.f; + if (auto prop = field.prop(HashedFieldPropName::FloatMin)) + min = *prop.value().try_cast(); + + float max = 0.f; + if (auto prop = field.prop(HashedFieldPropName::FloatMax)) + max = *prop.value().try_cast(); + + auto propDisplayName = field.prop(HashedName::DisplayName); + const char* displayName = *propDisplayName.value().try_cast(); + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + float* floatPtr = fieldVal.try_cast(); + if (floatPtr != nullptr) + { + float floatProxy = *floatPtr; + const std::string controlId = std::string("##") + displayName; + if (ImGui::DragFloat(controlId.c_str(), &floatProxy, stepSize, min, max)) + { + field.set(component, floatProxy); + } + } + else + { + ImGui::Text("ERR"); + } + } + + ImGui::TableNextRow(); } void EditorSelectionPanel::DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component) @@ -626,7 +663,8 @@ void EditorSelectionPanel::DrawFieldTypeBool(entt::meta_data& field, entt::meta_ if (boolPtr != nullptr) { bool boolProxy = *boolPtr; - if (ImGui::Checkbox("##isTrigger", &boolProxy)) + std::string controlId = std::string("##") + displayName; + if (ImGui::Checkbox(controlId.c_str(), &boolProxy)) { field.set(component, boolProxy); } @@ -635,9 +673,9 @@ void EditorSelectionPanel::DrawFieldTypeBool(entt::meta_data& field, entt::meta_ { ImGui::Text("ERR"); } - - ImGui::TableNextColumn(); } + + ImGui::TableNextRow(); } void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component) @@ -653,12 +691,17 @@ void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::me auto fieldVal = field.get(component); Vector3* vec3Ptr = fieldVal.try_cast(); + std::string controlId = std::string("##") + displayName; + ImGui::PushID(controlId.c_str()); + if (ImGuiHelper::DrawVec3("BoxSize", vec3Ptr, 0.5f, 100.0, 0.01f)) { field.set(component, *vec3Ptr); } - ImGui::TableNextColumn(); + ImGui::PopID(); } + + ImGui::TableNextRow(); } diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index 127d8d92..7c4a10f9 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -13,6 +13,13 @@ namespace Nuake NK_HASHED_STATIC_STR(AddToEntity) }; + struct HashedFieldPropName + { + NK_HASHED_STATIC_STR(FloatStep) + NK_HASHED_STATIC_STR(FloatMin) + NK_HASHED_STATIC_STR(FloatMax) + }; + struct HashedName { NK_HASHED_STATIC_STR(DisplayName) @@ -86,9 +93,29 @@ public: } \ \ initialized = true; \ - } - -#define BINDCOMPONENTFIELD(field, displayName) \ - ComponentFactory \ - .data<&field>(entt::hashed_string(#field)) \ - .prop(HashedName::DisplayName, displayName) \ No newline at end of file + \ + }\ +\ + template \ + static auto BindComponentField(const char* varName, const char* displayName) \ + { \ + return ComponentFactory \ + .data(entt::hashed_string(varName)) \ + .prop(HashedName::DisplayName, displayName); \ + } \ + \ + template \ + static auto BindComponentProperty(const char* varName, const char* displayName) \ + { \ + return ComponentFactory \ + .data(entt::hashed_string(varName)) \ + .prop(HashedName::DisplayName, displayName); \ + } \ + \ + static auto FloatFieldLimits(float stepSize, float min, float max) \ + { \ + return ComponentFactory \ + .prop(HashedFieldPropName::FloatStep, stepSize) \ + .prop(HashedFieldPropName::FloatMin, min) \ + .prop(HashedFieldPropName::FloatMax, max); \ + } \ No newline at end of file diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.h b/Nuake/src/Scene/Components/AudioEmitterComponent.h index 7f5d69e8..552d4fd8 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.h +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.h @@ -11,6 +11,28 @@ namespace Nuake { { NUAKECOMPONENT(AudioEmitterComponent, "Audio Emitter") + static void InitializeComponentClass() + { + BindComponentField<&AudioEmitterComponent::IsPlaying>("IsPlaying", "Is Playing"); + BindComponentField<&AudioEmitterComponent::Loop>("Loop", "Loop"); + + BindComponentField<&AudioEmitterComponent::Volume>("Volume", "Volume"); + FloatFieldLimits(0.001f, 0.0f, 2.0f); + BindComponentField<&AudioEmitterComponent::Pan>("Pan", "Pan"); + FloatFieldLimits(0.01f, -1.0f, 1.0f); + BindComponentField<&AudioEmitterComponent::PlaybackSpeed>("PlaybackSpeed", "Playback Speed"); + FloatFieldLimits(0.01f, 0.0001f, 0.f); + + BindComponentField<&AudioEmitterComponent::Spatialized>("Spatialized", "Spatialized"); + + BindComponentField<&AudioEmitterComponent::MinDistance>("MinDistance", "Min Distance"); + FloatFieldLimits(0.001f, 0.f, 0.f); + BindComponentField<&AudioEmitterComponent::MaxDistance>("MaxDistance", "Max Distance"); + FloatFieldLimits(0.001f, 0.f, 0.f); + BindComponentField<&AudioEmitterComponent::AttenuationFactor>("AttenuationFactor", "Attenuation Factor"); + FloatFieldLimits(0.001f, 0.f, 0.f); + } + public: std::string FilePath; diff --git a/Nuake/src/Scene/Components/BoxCollider.h b/Nuake/src/Scene/Components/BoxCollider.h index be5f4cdc..28057a1a 100644 --- a/Nuake/src/Scene/Components/BoxCollider.h +++ b/Nuake/src/Scene/Components/BoxCollider.h @@ -13,11 +13,8 @@ namespace Nuake static void InitializeComponentClass() { - BINDCOMPONENTFIELD(BoxColliderComponent::IsTrigger, "Is Trigger"); - - ComponentFactory - .data<&BoxColliderComponent::SetSize, &BoxColliderComponent::GetSize>(entt::hashed_string("size")) - .prop(HashedName::DisplayName, "Size"); + BindComponentField<&BoxColliderComponent::IsTrigger>("IsTrigger", "Is Trigger"); + BindComponentProperty<&BoxColliderComponent::SetSize, &BoxColliderComponent::GetSize>("Size", "Size"); } public: From 65c8ab79af3ab4652ef5cd90bfdb20f3be8c27d4 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:37:29 +0100 Subject: [PATCH 07/29] New component field type to support files Also fixed Audio System to work with this new supported component field type --- .../src/ComponentsPanel/AudioEmitterPanel.h | 129 +--------------- Editor/src/Windows/EditorSelectionPanel.cpp | 75 ++++++++++ Editor/src/Windows/EditorSelectionPanel.h | 2 + Nuake/src/Core/Object/Object.h | 140 +++++++++--------- .../Components/AudioEmitterComponent.cpp | 24 ++- .../Scene/Components/AudioEmitterComponent.h | 11 +- Nuake/src/Scene/Components/FieldTypes.h | 18 +++ Nuake/src/Scene/Systems/AudioSystem.cpp | 4 +- 8 files changed, 203 insertions(+), 200 deletions(-) create mode 100644 Nuake/src/Scene/Components/FieldTypes.h diff --git a/Editor/src/ComponentsPanel/AudioEmitterPanel.h b/Editor/src/ComponentsPanel/AudioEmitterPanel.h index df3611db..f7449ab6 100644 --- a/Editor/src/ComponentsPanel/AudioEmitterPanel.h +++ b/Editor/src/ComponentsPanel/AudioEmitterPanel.h @@ -15,133 +15,6 @@ public: void Draw(Nuake::Entity entity) override { - using namespace Nuake; - - if (!entity.HasComponent()) - return; - - auto& component = entity.GetComponent(); - BeginComponentTable(AUDIO EMITTER, AudioEmitterComponent); - { - { - ImGui::Text("Audio File"); - ImGui::TableNextColumn(); - - std::string path = component.FilePath; - ImGui::Button(component.FilePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_AudioFile")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = Nuake::FileSystem::AbsoluteToRelative(fullPath); - component.FilePath = path; - } - ImGui::EndDragDropTarget(); - } - - ImGui::TableNextColumn(); - - ComponentTableReset(component.FilePath, ""); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Playing"); - ImGui::TableNextColumn(); - - UI::ToggleButton("##Player", &component.IsPlaying); - //ImGui::Checkbox("##Playing", &component.IsPlaying); - ImGui::TableNextColumn(); - - ComponentTableReset(component.IsPlaying, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Loop"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##Loop", &component.Loop); - ImGui::TableNextColumn(); - - ComponentTableReset(component.Loop, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Volume"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##Volume", &component.Volume, 0.001f, 0.0f, 2.0f); - ImGui::TableNextColumn(); - - ComponentTableReset(component.Volume, 1.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Playback Speed"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##PlaybackSpeed", &component.PlaybackSpeed, 0.01f, 0.0001f); - ImGui::TableNextColumn(); - - ComponentTableReset(component.PlaybackSpeed, 1.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Pan"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##Pan", &component.Pan, 0.01f, -1.0f, 1.0f); - ImGui::TableNextColumn(); - - ComponentTableReset(component.Pan, 0.0f); - } - - ImGui::TableNextColumn(); - { - ImGui::Text("Spatialized"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##Spatialized", &component.Spatialized); - ImGui::TableNextColumn(); - - ComponentTableReset(component.Spatialized, false); - } - - if (component.Spatialized) - { - ImGui::TableNextColumn(); - { - ImGui::Text("Min Distance"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##minDistance", &component.MinDistance, 0.001f, 0.0f); - ImGui::TableNextColumn(); - - ComponentTableReset(component.MinDistance, 1.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Max Distance"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##maxDistance", &component.MaxDistance, 0.001f, 0.0f); - ImGui::TableNextColumn(); - - ComponentTableReset(component.MaxDistance, 10.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Attenuation Factor"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##attenuationFactor", &component.AttenuationFactor, 0.001f, 0.0f); - ImGui::TableNextColumn(); - - ComponentTableReset(component.AttenuationFactor, 1.0f); - } - } - } - EndComponentTable(); + } }; \ No newline at end of file diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index c5482feb..db2431d5 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -3,6 +3,7 @@ #include "EditorSelectionPanel.h" #include "../Misc/ImGuiTextHelper.h" #include +#include "src/Scene/Components/FieldTypes.h" #include #include @@ -15,6 +16,7 @@ #include + #define REGISTER_TYPE_DRAWER(forType, fn) \ FieldTypeDrawers[entt::type_id().hash()] = std::bind(&fn, this, std::placeholders::_1, std::placeholders::_2); @@ -29,6 +31,8 @@ EditorSelectionPanel::EditorSelectionPanel() REGISTER_TYPE_DRAWER(bool, EditorSelectionPanel::DrawFieldTypeBool); REGISTER_TYPE_DRAWER(float, EditorSelectionPanel::DrawFieldTypeFloat); REGISTER_TYPE_DRAWER(Vector3, EditorSelectionPanel::DrawFieldTypeVector3); + REGISTER_TYPE_DRAWER(std::string, EditorSelectionPanel::DrawFieldTypeString); + REGISTER_TYPE_DRAWER(ResourceFile, EditorSelectionPanel::DrawFieldTypeResourceFile); } void EditorSelectionPanel::ResolveFile(Ref file) @@ -705,3 +709,74 @@ void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::me ImGui::TableNextRow(); } +void EditorSelectionPanel::DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component) +{ + auto prop = field.prop(HashedName::DisplayName); + auto propVal = prop.value(); + const char* displayName = *propVal.try_cast(); + + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + std::string* fieldValPtr = fieldVal.try_cast(); + if (fieldValPtr != nullptr) + { + std::string fieldValProxy = *fieldValPtr; + std::string controlId = std::string("##") + displayName; + ImGui::InputText(controlId.c_str(), &fieldValProxy); + } + else + { + ImGui::Text("ERR"); + } + } + + ImGui::TableNextRow(); +} + +void EditorSelectionPanel::DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component) +{ + const char* resourceRestrictedType = nullptr; + if (auto prop = field.prop(HashedFieldPropName::ResourceFileType)) + resourceRestrictedType = *prop.value().try_cast(); + + auto propDisplayName = field.prop(HashedName::DisplayName); + const char* displayName = *propDisplayName.value().try_cast(); + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + auto fieldValPtr = fieldVal.try_cast(); + if (fieldValPtr != nullptr) + { + auto fieldValProxy = *fieldValPtr; + std::string filePath = fieldValProxy.file == nullptr ? "" : fieldValProxy.file->GetRelativePath(); + std::string controlName = filePath + std::string("##") + displayName; + ImGui::Button(controlName.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(resourceRestrictedType)) + { + const char* payloadFilePath = static_cast(payload->Data); + const std::string fullPath = std::string(payloadFilePath, 256); + const Ref file = FileSystem::GetFile(FileSystem::AbsoluteToRelative(fullPath)); + field.set(component, ResourceFile{ file }); + } + ImGui::EndDragDropTarget(); + } + } + else + { + ImGui::Text("ERR"); + } + } + + ImGui::TableNextRow(); +} + diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 8d8bb1f2..7bb92e3d 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -97,4 +97,6 @@ private: void DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component); void DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component); void DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component); }; \ No newline at end of file diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index 7c4a10f9..bdd1c782 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -18,6 +18,8 @@ namespace Nuake NK_HASHED_STATIC_STR(FloatStep) NK_HASHED_STATIC_STR(FloatMin) NK_HASHED_STATIC_STR(FloatMax) + + NK_HASHED_STATIC_STR(ResourceFileType) }; struct HashedName @@ -50,72 +52,78 @@ namespace Nuake } } -#define NUAKECOMPONENT(klass, componentName) \ -public: \ - static std::string ClassName() \ - { \ - static std::string className = #klass; \ - return className; \ - } \ - \ - static std::string ComponentName() \ - { \ - static std::string name = componentName; \ - return name; \ - } \ - \ - static void AddToEntity(entt::entity entity, entt::registry* enttRegistry) \ - { \ - enttRegistry->emplace_or_replace(entity); \ - } \ - \ - \ - static void (*GetInitializeComponentClass())() \ - { \ - return &klass::InitializeComponentClass; \ - } \ - \ - inline static auto ComponentFactory = entt::meta(); \ - static void InternalInitializeClass() \ - { \ - static bool initialized = false; \ - if (initialized) \ - return; \ - \ - ComponentFactory.type(entt::hashed_string(#klass)) \ - .traits(ComponentTypeTrait::InspectorExposed); \ - ComponentFactory.func<&klass::ComponentName>(HashedFnName::GetComponentName); \ - ComponentFactory.func<&klass::AddToEntity>(HashedFnName::AddToEntity); \ - \ - if (klass::GetInitializeComponentClass() != Component::GetInitializeComponentClass()) \ - { \ - GetInitializeComponentClass()(); \ - } \ - \ - initialized = true; \ - \ - }\ -\ - template \ - static auto BindComponentField(const char* varName, const char* displayName) \ - { \ - return ComponentFactory \ - .data(entt::hashed_string(varName)) \ - .prop(HashedName::DisplayName, displayName); \ - } \ +#define NUAKECOMPONENT(klass, componentName) \ +public: \ + static std::string ClassName() \ + { \ + static std::string className = #klass; \ + return className; \ + } \ + \ + static std::string ComponentName() \ + { \ + static std::string name = componentName; \ + return name; \ + } \ + \ + static void AddToEntity(entt::entity entity, entt::registry* enttRegistry) \ + { \ + enttRegistry->emplace_or_replace(entity); \ + } \ + \ + \ + static void (*GetInitializeComponentClass())() \ + { \ + return &klass::InitializeComponentClass; \ + } \ + \ + inline static auto ComponentFactory = entt::meta(); \ + static void InternalInitializeClass() \ + { \ + static bool initialized = false; \ + if (initialized) \ + return; \ + \ + ComponentFactory.type(entt::hashed_string(#klass)) \ + .traits(ComponentTypeTrait::InspectorExposed); \ + ComponentFactory.func<&klass::ComponentName>(HashedFnName::GetComponentName); \ + ComponentFactory.func<&klass::AddToEntity>(HashedFnName::AddToEntity); \ + \ + if (klass::GetInitializeComponentClass() != Component::GetInitializeComponentClass()) \ + { \ + GetInitializeComponentClass()(); \ + } \ + \ + initialized = true; \ + \ + } \ + \ + template \ + static auto BindComponentField(const char* varName, const char* displayName) \ + { \ + return ComponentFactory \ + .data(entt::hashed_string(varName)) \ + .prop(HashedName::DisplayName, displayName); \ + } \ + \ + template \ + static auto BindComponentProperty(const char* varName, const char* displayName) \ + { \ + return ComponentFactory \ + .data(entt::hashed_string(varName)) \ + .prop(HashedName::DisplayName, displayName); \ + } \ + \ + static auto FloatFieldLimits(float stepSize, float min, float max) \ + { \ + return ComponentFactory \ + .prop(HashedFieldPropName::FloatStep, stepSize) \ + .prop(HashedFieldPropName::FloatMin, min) \ + .prop(HashedFieldPropName::FloatMax, max); \ + } \ \ - template \ - static auto BindComponentProperty(const char* varName, const char* displayName) \ + static auto ResourceFileRestriction(const char* fileType) \ { \ return ComponentFactory \ - .data(entt::hashed_string(varName)) \ - .prop(HashedName::DisplayName, displayName); \ - } \ - \ - static auto FloatFieldLimits(float stepSize, float min, float max) \ - { \ - return ComponentFactory \ - .prop(HashedFieldPropName::FloatStep, stepSize) \ - .prop(HashedFieldPropName::FloatMin, min) \ - .prop(HashedFieldPropName::FloatMax, max); \ - } \ No newline at end of file + .prop(HashedFieldPropName::ResourceFileType, fileType); \ + } diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp index 35b75249..be7d8ae0 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp @@ -1,11 +1,20 @@ #include "AudioEmitterComponent.h" +#include "src/FileSystem/FileSystem.h" + namespace Nuake { json AudioEmitterComponent::Serialize() { BEGIN_SERIALIZE(); - SERIALIZE_VAL(FilePath); + + bool validFile = FilePath.file != nullptr && FilePath.file->Exist(); + j["validFile"] = validFile; + if (validFile) + { + j["file"] = FilePath.file->GetRelativePath(); + } + SERIALIZE_VAL(IsPlaying); SERIALIZE_VAL(Volume); SERIALIZE_VAL(Pan); @@ -20,7 +29,16 @@ namespace Nuake { bool AudioEmitterComponent::Deserialize(const json& j) { - DESERIALIZE_VAL(FilePath); + if (j.contains("validFile")) + { + bool validFile = j["validFile"]; + if (validFile) + { + std::string filePath = j["file"]; + FilePath.file = FileSystem::GetFile(filePath); + } + } + DESERIALIZE_VAL(Volume); DESERIALIZE_VAL(IsPlaying); DESERIALIZE_VAL(Pan); @@ -32,4 +50,4 @@ namespace Nuake { DESERIALIZE_VAL(Loop); return true; } -} \ No newline at end of file +} diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.h b/Nuake/src/Scene/Components/AudioEmitterComponent.h index 552d4fd8..e30bb20c 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.h +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.h @@ -1,8 +1,11 @@ #pragma once #include "Component.h" +#include "FieldTypes.h" #include "src/Core/Core.h" +#include "src/FileSystem/File.h" +#include "src/Resource/Resource.h" #include "src/Resource/Serializable.h" namespace Nuake { @@ -13,6 +16,11 @@ namespace Nuake { static void InitializeComponentClass() { + BindComponentField<&AudioEmitterComponent::File>("FilePath", "File Path"); + + BindComponentField<&AudioEmitterComponent::FilePath>("FilePath", "File Path"); + ResourceFileRestriction("_AudioFile"); + BindComponentField<&AudioEmitterComponent::IsPlaying>("IsPlaying", "Is Playing"); BindComponentField<&AudioEmitterComponent::Loop>("Loop", "Loop"); @@ -34,7 +42,8 @@ namespace Nuake { } public: - std::string FilePath; + Ref File; + ResourceFile FilePath; bool IsPlaying = false; bool Loop = false; diff --git a/Nuake/src/Scene/Components/FieldTypes.h b/Nuake/src/Scene/Components/FieldTypes.h new file mode 100644 index 00000000..e46ba0c2 --- /dev/null +++ b/Nuake/src/Scene/Components/FieldTypes.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "src/Core/Core.h" + +namespace Nuake +{ + class File; + + struct ResourceFile + { + ResourceFile() {} + ResourceFile(const Ref& inFile) : file(inFile) {} + + Ref file = nullptr; + }; +} diff --git a/Nuake/src/Scene/Systems/AudioSystem.cpp b/Nuake/src/Scene/Systems/AudioSystem.cpp index e761e6f1..9b715eef 100644 --- a/Nuake/src/Scene/Systems/AudioSystem.cpp +++ b/Nuake/src/Scene/Systems/AudioSystem.cpp @@ -44,14 +44,14 @@ namespace Nuake { auto [transformComponent, audioEmitterComponent] = view.get(e); - if (audioEmitterComponent.FilePath.empty()) + if (audioEmitterComponent.FilePath.file == nullptr || !audioEmitterComponent.FilePath.file->Exist()) { // Doesn't have a file continue; } const bool isPlaying = audioEmitterComponent.IsPlaying; - const std::string absoluteFilePath = FileSystem::RelativeToAbsolute(audioEmitterComponent.FilePath); + const std::string absoluteFilePath = audioEmitterComponent.FilePath.file->GetAbsolutePath(); const bool isVoiceActive = audioManager.IsVoiceActive(absoluteFilePath); AudioRequest audioRequest; From 82771d43da99d52a277c5c7ce742535e31c82cc5 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Thu, 12 Sep 2024 23:40:21 +0100 Subject: [PATCH 08/29] Removed old rubbish from audio emitter component --- Nuake/src/Scene/Components/AudioEmitterComponent.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.h b/Nuake/src/Scene/Components/AudioEmitterComponent.h index e30bb20c..a57863cb 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.h +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.h @@ -16,8 +16,6 @@ namespace Nuake { static void InitializeComponentClass() { - BindComponentField<&AudioEmitterComponent::File>("FilePath", "File Path"); - BindComponentField<&AudioEmitterComponent::FilePath>("FilePath", "File Path"); ResourceFileRestriction("_AudioFile"); @@ -42,7 +40,6 @@ namespace Nuake { } public: - Ref File; ResourceFile FilePath; bool IsPlaying = false; From 9e94006d2bcfa83d6ad9d760b82a88253e4f0647 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Fri, 13 Sep 2024 13:22:05 +0100 Subject: [PATCH 09/29] Added generic ability to (de)serialize ResourceFiles, a templated function to allow easier setting of entt traits and renamed float limits function --- Nuake/src/Core/Object/Object.h | 21 +++++++++++++++++-- Nuake/src/Resource/Serializable.h | 19 ++++++++++++++++- .../Components/AudioEmitterComponent.cpp | 20 ++---------------- .../Scene/Components/AudioEmitterComponent.h | 13 ++++++------ Nuake/src/Scene/Components/UIComponent.h | 19 +++++++++++++---- 5 files changed, 60 insertions(+), 32 deletions(-) diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index bdd1c782..4b23c8c2 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -30,9 +30,17 @@ namespace Nuake enum class ComponentTypeTrait : uint16_t { None = 0, + // Exposes the component to be added via the inspector InspectorExposed = 1 << 0, + }; - + enum class ComponentFieldTrait : uint16_t + { + None = 0, + // Stops field from showing up in the editor inspector + Internal = 1 << 0, + // Marks the field as temporary (ie, do not serialize) + Transient = 1 << 1, }; template @@ -114,7 +122,7 @@ public: .prop(HashedName::DisplayName, displayName); \ } \ \ - static auto FloatFieldLimits(float stepSize, float min, float max) \ + static auto FieldFloatLimits(float stepSize, float min, float max) \ { \ return ComponentFactory \ .prop(HashedFieldPropName::FloatStep, stepSize) \ @@ -126,4 +134,13 @@ public: { \ return ComponentFactory \ .prop(HashedFieldPropName::ResourceFileType, fileType); \ + } \ + \ + template \ + static auto SetFlags(Enums... enums) \ + { \ + static_assert((std::is_enum_v && ...), "All arguments must be of enum class type"); \ + return ComponentFactory.traits((static_cast(enums) | ...)); \ } + + diff --git a/Nuake/src/Resource/Serializable.h b/Nuake/src/Resource/Serializable.h index 54a79b81..f85a9ce2 100644 --- a/Nuake/src/Resource/Serializable.h +++ b/Nuake/src/Resource/Serializable.h @@ -6,6 +6,13 @@ using json = nlohmann::json; #define BEGIN_SERIALIZE() json j; #define SERIALIZE_VAL_LBL(lbl, v) j[lbl] = v; #define SERIALIZE_VAL(v) j[#v] = this->v; +#define SERIALIZE_RES_FILE(v) \ + bool validFile = this->v.file != nullptr && this->v.file->Exist(); \ + j["validFile"#v] = validFile; \ + if (validFile) \ + { \ + j["file"#v] = this->v.file->GetRelativePath(); \ + } #define SERIALIZE_VEC2(v) \ j[#v]["x"] = v.x; \ @@ -23,7 +30,17 @@ using json = nlohmann::json; if(j.contains(#p)) \ { \ p = j[#p]; \ -} +} + +#define DESERIALIZE_RES_FILE(v) \ + if (j.contains("validFile"#v)) \ + { \ + if (bool validFile = j["validFile"#v]) \ + { \ + const std::string filePath = j["file"#v]; \ + (v).file = FileSystem::GetFile(filePath); \ + } \ + } #define DESERIALIZE_VEC4(v, p) \ p = Vector4(v["x"], v["y"], v["z"], v["w"]); diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp index be7d8ae0..3034a057 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp @@ -7,14 +7,7 @@ namespace Nuake { json AudioEmitterComponent::Serialize() { BEGIN_SERIALIZE(); - - bool validFile = FilePath.file != nullptr && FilePath.file->Exist(); - j["validFile"] = validFile; - if (validFile) - { - j["file"] = FilePath.file->GetRelativePath(); - } - + SERIALIZE_RES_FILE(FilePath); SERIALIZE_VAL(IsPlaying); SERIALIZE_VAL(Volume); SERIALIZE_VAL(Pan); @@ -29,16 +22,7 @@ namespace Nuake { bool AudioEmitterComponent::Deserialize(const json& j) { - if (j.contains("validFile")) - { - bool validFile = j["validFile"]; - if (validFile) - { - std::string filePath = j["file"]; - FilePath.file = FileSystem::GetFile(filePath); - } - } - + DESERIALIZE_RES_FILE(FilePath); DESERIALIZE_VAL(Volume); DESERIALIZE_VAL(IsPlaying); DESERIALIZE_VAL(Pan); diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.h b/Nuake/src/Scene/Components/AudioEmitterComponent.h index a57863cb..fedced6c 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.h +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.h @@ -4,7 +4,6 @@ #include "FieldTypes.h" #include "src/Core/Core.h" -#include "src/FileSystem/File.h" #include "src/Resource/Resource.h" #include "src/Resource/Serializable.h" @@ -23,20 +22,20 @@ namespace Nuake { BindComponentField<&AudioEmitterComponent::Loop>("Loop", "Loop"); BindComponentField<&AudioEmitterComponent::Volume>("Volume", "Volume"); - FloatFieldLimits(0.001f, 0.0f, 2.0f); + FieldFloatLimits(0.001f, 0.0f, 2.0f); BindComponentField<&AudioEmitterComponent::Pan>("Pan", "Pan"); - FloatFieldLimits(0.01f, -1.0f, 1.0f); + FieldFloatLimits(0.01f, -1.0f, 1.0f); BindComponentField<&AudioEmitterComponent::PlaybackSpeed>("PlaybackSpeed", "Playback Speed"); - FloatFieldLimits(0.01f, 0.0001f, 0.f); + FieldFloatLimits(0.01f, 0.0001f, 0.f); BindComponentField<&AudioEmitterComponent::Spatialized>("Spatialized", "Spatialized"); BindComponentField<&AudioEmitterComponent::MinDistance>("MinDistance", "Min Distance"); - FloatFieldLimits(0.001f, 0.f, 0.f); + FieldFloatLimits(0.001f, 0.f, 0.f); BindComponentField<&AudioEmitterComponent::MaxDistance>("MaxDistance", "Max Distance"); - FloatFieldLimits(0.001f, 0.f, 0.f); + FieldFloatLimits(0.001f, 0.f, 0.f); BindComponentField<&AudioEmitterComponent::AttenuationFactor>("AttenuationFactor", "Attenuation Factor"); - FloatFieldLimits(0.001f, 0.f, 0.f); + FieldFloatLimits(0.001f, 0.f, 0.f); } public: diff --git a/Nuake/src/Scene/Components/UIComponent.h b/Nuake/src/Scene/Components/UIComponent.h index e5b9debf..13955b58 100644 --- a/Nuake/src/Scene/Components/UIComponent.h +++ b/Nuake/src/Scene/Components/UIComponent.h @@ -1,7 +1,10 @@ #pragma once #include "Component.h" +#include "FieldTypes.h" #include "src/Core/Logger.h" +#include "src/FileSystem/File.h" +#include "src/FileSystem/FileSystem.h" #include "src/Resource/UUID.h" #include "src/Resource/Serializable.h" @@ -11,24 +14,32 @@ namespace Nuake struct UIComponent : public Component { NUAKECOMPONENT(UIComponent, "UI") + + static void InitializeComponentClass() + { + BindComponentField<&UIComponent::UIResource>("UIResource", "UIResource"); + SetFlags(ComponentFieldTrait::Internal, ComponentFieldTrait::Transient); + + BindComponentField<&UIComponent::UIFilePath>("UIFilePath", "File Path"); + BindComponentField<&UIComponent::IsWorldSpace>("IsWorldspace", "Is Worldspace"); + } public: UUID UIResource = UUID(0); - std::string CSharpUIController; - std::string UIFilePath; + ResourceFile UIFilePath; bool IsWorldSpace; // TODO: Z-Ordering json Serialize() { BEGIN_SERIALIZE(); - SERIALIZE_VAL(UIFilePath); + SERIALIZE_RES_FILE(UIFilePath); END_SERIALIZE(); } bool Deserialize(const json& j) { - DESERIALIZE_VAL(UIFilePath); + DESERIALIZE_RES_FILE(UIFilePath); return true; } }; From 59505b066422ea6b84d1ee08f1eaa478e153eb55 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Fri, 13 Sep 2024 21:54:54 +0100 Subject: [PATCH 10/29] Fix for audio emitter component not compiling --- Nuake/src/Scene/Components/AudioEmitterComponent.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp index 3034a057..234a4475 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp @@ -1,5 +1,6 @@ #include "AudioEmitterComponent.h" +#include "src/FileSystem/File.h" #include "src/FileSystem/FileSystem.h" namespace Nuake { From aed98dd6488846e08f12d9008fabcb2bdb1f55ba Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Fri, 13 Sep 2024 23:24:34 +0100 Subject: [PATCH 11/29] UI system now working well with the new component changes, fixed trait compile issues, fixed inspector rendering issues --- Editor/src/ComponentsPanel/UIPanel.h | 84 ++++++++++----------- Editor/src/Windows/EditorSelectionPanel.cpp | 25 +++--- Nuake/src/Core/Object/Object.h | 27 ++++++- Nuake/src/Resource/ResourceLoader.cpp | 11 +++ Nuake/src/Resource/ResourceLoader.h | 2 + Nuake/src/Scene/Components/UIComponent.h | 4 +- Nuake/src/Scene/Systems/AudioSystem.cpp | 3 +- Nuake/src/Scene/Systems/UISystem.cpp | 8 +- 8 files changed, 100 insertions(+), 64 deletions(-) diff --git a/Editor/src/ComponentsPanel/UIPanel.h b/Editor/src/ComponentsPanel/UIPanel.h index 70251dac..0f4b48fc 100644 --- a/Editor/src/ComponentsPanel/UIPanel.h +++ b/Editor/src/ComponentsPanel/UIPanel.h @@ -15,47 +15,47 @@ public: void Draw(Nuake::Entity entity) override { - using namespace Nuake; - - if (!entity.HasComponent()) - return; - - auto& component = entity.GetComponent(); - BeginComponentTable(UI EMITTER, UIComponent); - { - { - ImGui::Text("HTML File"); - ImGui::TableNextColumn(); - - std::string path = component.UIFilePath; - ImGui::Button(component.UIFilePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_UIFile")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = Nuake::FileSystem::AbsoluteToRelative(fullPath); - component.UIFilePath = path; - } - ImGui::EndDragDropTarget(); - } - - ImGui::TableNextColumn(); - - ComponentTableReset(component.UIFilePath, ""); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Worldspace"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##WorldSpace", &component.IsWorldSpace); - ImGui::TableNextColumn(); - - ComponentTableReset(component.IsWorldSpace, false); - } - } - EndComponentTable(); + // using namespace Nuake; + // + // if (!entity.HasComponent()) + // return; + // + // auto& component = entity.GetComponent(); + // BeginComponentTable(UI EMITTER, UIComponent); + // { + // { + // ImGui::Text("HTML File"); + // ImGui::TableNextColumn(); + // + // std::string path = component.UIFilePath; + // ImGui::Button(component.UIFilePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + // if (ImGui::BeginDragDropTarget()) + // { + // if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_UIFile")) + // { + // char* file = (char*)payload->Data; + // std::string fullPath = std::string(file, 256); + // path = Nuake::FileSystem::AbsoluteToRelative(fullPath); + // component.UIFilePath = path; + // } + // ImGui::EndDragDropTarget(); + // } + // + // ImGui::TableNextColumn(); + // + // ComponentTableReset(component.UIFilePath, ""); + // } + // ImGui::TableNextColumn(); + // { + // ImGui::Text("Worldspace"); + // ImGui::TableNextColumn(); + // + // ImGui::Checkbox("##WorldSpace", &component.IsWorldSpace); + // ImGui::TableNextColumn(); + // + // ComponentTableReset(component.IsWorldSpace, false); + // } + // } + // EndComponentTable(); } }; \ No newline at end of file diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index db2431d5..a741ba1a 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -598,8 +598,15 @@ void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) entt::meta_type componentMeta = component.type(); for (auto [fst, dataType] : componentMeta.data()) { + const ComponentFieldTrait fieldTraits = dataType.traits(); + // Field marked as internal and thus not exposed to the inspector + if ((fieldTraits & ComponentFieldTrait::Internal) == ComponentFieldTrait::Internal) + { + continue; + } + ImGui::TableNextColumn(); - + // Search for the appropriate drawer for the type entt::id_type dataId = dataType.type().id(); if (FieldTypeDrawers.contains(dataId)) @@ -607,6 +614,12 @@ void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) auto drawerFn = FieldTypeDrawers[dataId]; drawerFn(dataType, component); } + else + { + ImGui::Text("ERR"); + } + + ImGui::TableNextRow(); } } @@ -647,8 +660,6 @@ void EditorSelectionPanel::DrawFieldTypeFloat(entt::meta_data& field, entt::meta ImGui::Text("ERR"); } } - - ImGui::TableNextRow(); } void EditorSelectionPanel::DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component) @@ -678,8 +689,6 @@ void EditorSelectionPanel::DrawFieldTypeBool(entt::meta_data& field, entt::meta_ ImGui::Text("ERR"); } } - - ImGui::TableNextRow(); } void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component) @@ -705,8 +714,6 @@ void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::me ImGui::PopID(); } - - ImGui::TableNextRow(); } void EditorSelectionPanel::DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component) @@ -733,8 +740,6 @@ void EditorSelectionPanel::DrawFieldTypeString(entt::meta_data& field, entt::met ImGui::Text("ERR"); } } - - ImGui::TableNextRow(); } void EditorSelectionPanel::DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component) @@ -776,7 +781,5 @@ void EditorSelectionPanel::DrawFieldTypeResourceFile(entt::meta_data& field, ent ImGui::Text("ERR"); } } - - ImGui::TableNextRow(); } diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index 4b23c8c2..72f9d793 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -5,6 +5,17 @@ #define NK_HASHED_STATIC_STR(name) inline static constexpr entt::hashed_string name = entt::hashed_string(#name); +#define NK_ENUM_BITWISE_IMPL(enumClassName) \ + inline enumClassName operator|(enumClassName lhs, enumClassName rhs) \ + { \ + return static_cast(ToUnderlying(lhs) | ToUnderlying(rhs)); \ + } \ + \ + inline enumClassName operator&(enumClassName lhs, enumClassName rhs) \ + { \ + return static_cast(ToUnderlying(lhs) & ToUnderlying(rhs)); \ + } + namespace Nuake { struct HashedFnName @@ -18,7 +29,7 @@ namespace Nuake NK_HASHED_STATIC_STR(FloatStep) NK_HASHED_STATIC_STR(FloatMin) NK_HASHED_STATIC_STR(FloatMax) - + NK_HASHED_STATIC_STR(ResourceFileType) }; @@ -58,6 +69,16 @@ namespace Nuake { return static_cast(ToUnderlying(lhs) & ToUnderlying(rhs)); } + + inline ComponentFieldTrait operator|(ComponentFieldTrait lhs, ComponentFieldTrait rhs) + { + return static_cast(ToUnderlying(lhs) | ToUnderlying(rhs)); + } + + inline ComponentFieldTrait operator&(ComponentFieldTrait lhs, ComponentFieldTrait rhs) + { + return static_cast(ToUnderlying(lhs) & ToUnderlying(rhs)); + } } #define NUAKECOMPONENT(klass, componentName) \ @@ -140,7 +161,5 @@ public: static auto SetFlags(Enums... enums) \ { \ static_assert((std::is_enum_v && ...), "All arguments must be of enum class type"); \ - return ComponentFactory.traits((static_cast(enums) | ...)); \ + return ComponentFactory.traits((enums | ...)); \ } - - diff --git a/Nuake/src/Resource/ResourceLoader.cpp b/Nuake/src/Resource/ResourceLoader.cpp index fbb25949..22f062d7 100644 --- a/Nuake/src/Resource/ResourceLoader.cpp +++ b/Nuake/src/Resource/ResourceLoader.cpp @@ -1,6 +1,7 @@ #include "ResourceLoader.h" #include "src/Core/Logger.h" #include "src/Core/String.h" +#include "src/FileSystem/File.h" #include "src/Resource/Resource.h" #include "src/Resource/ResourceManager.h" #include "src/Rendering/Textures/Material.h" @@ -101,6 +102,16 @@ Ref ResourceLoader::LoadUI(const std::string& path) return uiResource; } +Ref ResourceLoader::LoadUI(const Ref& file) +{ + if (file == nullptr || !file->Exist()) + { + return nullptr; + } + + return LoadUI(file->GetRelativePath()); +} + UUID ResourceLoader::ReadUUID(json j) { if (j.contains("UUID")) diff --git a/Nuake/src/Resource/ResourceLoader.h b/Nuake/src/Resource/ResourceLoader.h index 4e916a7b..378cd6de 100644 --- a/Nuake/src/Resource/ResourceLoader.h +++ b/Nuake/src/Resource/ResourceLoader.h @@ -8,6 +8,7 @@ namespace Nuake class Material; class Model; class UIResource; + class File; class ResourceLoader { @@ -23,6 +24,7 @@ namespace Nuake static Ref LoadMaterial(const std::string& path); static Ref LoadModel(const std::string& path); static Ref LoadUI(const std::string& path); + static Ref LoadUI(const Ref& file); private: static UUID ReadUUID(json j); diff --git a/Nuake/src/Scene/Components/UIComponent.h b/Nuake/src/Scene/Components/UIComponent.h index 13955b58..55188105 100644 --- a/Nuake/src/Scene/Components/UIComponent.h +++ b/Nuake/src/Scene/Components/UIComponent.h @@ -19,7 +19,7 @@ namespace Nuake { BindComponentField<&UIComponent::UIResource>("UIResource", "UIResource"); SetFlags(ComponentFieldTrait::Internal, ComponentFieldTrait::Transient); - + BindComponentField<&UIComponent::UIFilePath>("UIFilePath", "File Path"); BindComponentField<&UIComponent::IsWorldSpace>("IsWorldspace", "Is Worldspace"); } @@ -34,12 +34,14 @@ namespace Nuake { BEGIN_SERIALIZE(); SERIALIZE_RES_FILE(UIFilePath); + SERIALIZE_VAL(IsWorldSpace); END_SERIALIZE(); } bool Deserialize(const json& j) { DESERIALIZE_RES_FILE(UIFilePath); + DESERIALIZE_VAL(IsWorldSpace); return true; } }; diff --git a/Nuake/src/Scene/Systems/AudioSystem.cpp b/Nuake/src/Scene/Systems/AudioSystem.cpp index 9b715eef..96bfb8dd 100644 --- a/Nuake/src/Scene/Systems/AudioSystem.cpp +++ b/Nuake/src/Scene/Systems/AudioSystem.cpp @@ -4,12 +4,11 @@ #include "src/Scene/Scene.h" #include "src/Scene/Entities/Entity.h" #include "src/Scene/Components/AudioEmitterComponent.h" - +#include "src/FileSystem/File.h" #include "src/Audio/AudioManager.h" #include - namespace Nuake { AudioSystem::AudioSystem(Scene* scene) diff --git a/Nuake/src/Scene/Systems/UISystem.cpp b/Nuake/src/Scene/Systems/UISystem.cpp index 537f2505..99dd7fbb 100644 --- a/Nuake/src/Scene/Systems/UISystem.cpp +++ b/Nuake/src/Scene/Systems/UISystem.cpp @@ -28,15 +28,15 @@ namespace Nuake for (auto e : uiView) { auto& uiViewComponent = uiView.get(e); - const std::string& filePath = uiViewComponent.UIFilePath; + Ref file = uiViewComponent.UIFilePath.file; if (uiViewComponent.UIResource == 0) { - if (filePath.empty() || !FileSystem::FileExists(filePath)) + if (file == nullptr || !file->Exist()) { continue; } - Ref uiResource = ResourceLoader::LoadUI(filePath); + Ref uiResource = ResourceLoader::LoadUI(file); uiViewComponent.UIResource = uiResource->ID; uis[uiViewComponent.UIResource] = uiResource; @@ -44,7 +44,7 @@ namespace Nuake } else { - if (FileSystem::FileExists(filePath)) + if (file != nullptr && file->Exist()) { auto ui = ResourceManager::GetResource(uiViewComponent.UIResource); bool sourceHasChanged = false; From dabd9c01a619be92b66d20f119f7757d17273b44 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Fri, 13 Sep 2024 23:54:43 +0100 Subject: [PATCH 12/29] Removed trigger zone component --- Nuake/src/Scene/Components/TriggerZone.h | 26 --------------------- Nuake/src/Scene/Systems/PhysicsSystem.cpp | 1 - Nuake/src/Scene/Systems/QuakeMapBuilder.cpp | 1 - Nuake/src/Scripting/Modules/SceneModule.h | 5 ---- 4 files changed, 33 deletions(-) delete mode 100644 Nuake/src/Scene/Components/TriggerZone.h diff --git a/Nuake/src/Scene/Components/TriggerZone.h b/Nuake/src/Scene/Components/TriggerZone.h deleted file mode 100644 index 8c07debb..00000000 --- a/Nuake/src/Scene/Components/TriggerZone.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -namespace Nuake -{ - class TriggerZone - { - public: - std::string target = ""; - - std::vector Targets; - bool Enabled = true; - - TriggerZone() - { - Targets = std::vector(); - } - - std::vector GetTargets() - { - return Targets; - } - - }; -} diff --git a/Nuake/src/Scene/Systems/PhysicsSystem.cpp b/Nuake/src/Scene/Systems/PhysicsSystem.cpp index 6de93c66..fe3fb0c3 100644 --- a/Nuake/src/Scene/Systems/PhysicsSystem.cpp +++ b/Nuake/src/Scene/Systems/PhysicsSystem.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include namespace Nuake diff --git a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp index 1d49ac55..cb1ad4f7 100644 --- a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp +++ b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp @@ -22,7 +22,6 @@ extern "C" { #include "src/Scene/Components/TransformComponent.h" #include "src/Scene/Components/LightComponent.h" #include "src/Scene/Components/NameComponent.h" -#include "src/Scene/Components/TriggerZone.h" #include "src/Resource/FGD/FGDClass.h" #include "src/Scene/Components/WrenScriptComponent.h" #include "src/Scene/Components/PrefabComponent.h" diff --git a/Nuake/src/Scripting/Modules/SceneModule.h b/Nuake/src/Scripting/Modules/SceneModule.h index 704997ac..b10d176b 100644 --- a/Nuake/src/Scripting/Modules/SceneModule.h +++ b/Nuake/src/Scripting/Modules/SceneModule.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -406,8 +405,6 @@ namespace Nuake double handle = wrenGetSlotDouble(vm, 1); Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get()); - TriggerZone trigger = ent.GetComponent(); - int count = 0; wrenSetSlotDouble(vm, 0, count); @@ -418,8 +415,6 @@ namespace Nuake double handle = wrenGetSlotDouble(vm, 1); Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get()); - TriggerZone trigger = ent.GetComponent(); - std::vector entities = {}; wrenEnsureSlots(vm, static_cast(entities.size())); From 5d0eb4a59736fcddba410885c4875071e6577b3d Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Fri, 13 Sep 2024 23:56:01 +0100 Subject: [PATCH 13/29] Sprite component reflected --- Editor/src/ComponentsPanel/SpritePanel.h | 71 +------------------ .../src/Scene/Components/SpriteComponent.cpp | 22 +++--- Nuake/src/Scene/Components/SpriteComponent.h | 11 ++- 3 files changed, 23 insertions(+), 81 deletions(-) diff --git a/Editor/src/ComponentsPanel/SpritePanel.h b/Editor/src/ComponentsPanel/SpritePanel.h index b21c58e0..bc03e632 100644 --- a/Editor/src/ComponentsPanel/SpritePanel.h +++ b/Editor/src/ComponentsPanel/SpritePanel.h @@ -15,75 +15,6 @@ public: void Draw(Nuake::Entity entity) override { - if (!entity.HasComponent()) - { - return; - } - - auto& component = entity.GetComponent(); - BeginComponentTable(SPRITE, Nuake::SpriteComponent); - { - { - ImGui::Text("Sprite"); - ImGui::TableNextColumn(); - - std::string path = component.SpritePath; - ImGui::Button(path.empty() ? "Drag image" : component.SpritePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Image")) - { - char* file = (char*)payload->Data; - - std::string fullPath = std::string(file, 512); - path = Nuake::FileSystem::AbsoluteToRelative(std::move(fullPath)); - component.SpritePath = path; - - component.LoadSprite(); - } - ImGui::EndDragDropTarget(); - } - - ImGui::TableNextColumn(); - ComponentTableReset(component.LockYRotation, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Billboard"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##billboard", &component.Billboard); - ImGui::TableNextColumn(); - - ComponentTableReset(component.Billboard, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Lock Y rotation"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##lockYRotation", &component.LockYRotation); - ImGui::TableNextColumn(); - - ComponentTableReset(component.LockYRotation, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Position Based"); - if (ImGui::BeginItemTooltip()) - { - ImGui::Text("Orientation is based on the position of the camera or the orientation of the camera."); - ImGui::EndTooltip(); - } - - ImGui::TableNextColumn(); - - ImGui::Checkbox("##positionbased", &component.PositionFacing); - ImGui::TableNextColumn(); - - ComponentTableReset(component.LockYRotation, false); - } - } - EndComponentTable(); + } }; \ No newline at end of file diff --git a/Nuake/src/Scene/Components/SpriteComponent.cpp b/Nuake/src/Scene/Components/SpriteComponent.cpp index c2892e6c..369e0a92 100644 --- a/Nuake/src/Scene/Components/SpriteComponent.cpp +++ b/Nuake/src/Scene/Components/SpriteComponent.cpp @@ -1,5 +1,6 @@ #include "SpriteComponent.h" +#include "src/FileSystem/File.h" #include "src/FileSystem/FileSystem.h" #include "src/Rendering/Textures/TextureManager.h" #include "src/Rendering/Textures/MaterialManager.h" @@ -10,8 +11,7 @@ namespace Nuake { SpriteComponent::SpriteComponent() : Billboard(false), - LockYRotation(false), - SpritePath("") + LockYRotation(false) { } @@ -32,7 +32,13 @@ namespace Nuake SpriteMesh = CreateRef(); SpriteMesh->AddSurface(quadVertices, { 0, 1, 2, 3, 4, 5 }); - Ref material = MaterialManager::Get()->GetMaterial(FileSystem::Root + SpritePath); + std::string absPath = ""; + if (SpritePath.file != nullptr && SpritePath.file->Exist()) + { + absPath = SpritePath.file->GetAbsolutePath(); + } + + Ref material = MaterialManager::Get()->GetMaterial(absPath); bool hasNormal = material->HasNormal(); SpriteMesh->SetMaterial(material); @@ -44,7 +50,7 @@ namespace Nuake BEGIN_SERIALIZE(); SERIALIZE_VAL(Billboard); SERIALIZE_VAL(LockYRotation); - SERIALIZE_VAL(SpritePath); + SERIALIZE_RES_FILE(SpritePath); SERIALIZE_VAL(PositionFacing); END_SERIALIZE(); } @@ -61,17 +67,13 @@ namespace Nuake LockYRotation = j["LockYRotation"]; } + DESERIALIZE_RES_FILE(SpritePath); + if (j.contains("PositionFacing")) { PositionFacing = j["PositionFacing"]; } - if (j.contains("SpritePath")) - { - SpritePath = j["SpritePath"]; - LoadSprite(); - } - return true; } } \ No newline at end of file diff --git a/Nuake/src/Scene/Components/SpriteComponent.h b/Nuake/src/Scene/Components/SpriteComponent.h index f2e3f1fe..ab2bacf2 100644 --- a/Nuake/src/Scene/Components/SpriteComponent.h +++ b/Nuake/src/Scene/Components/SpriteComponent.h @@ -1,6 +1,7 @@ #pragma once #include "Component.h" +#include "FieldTypes.h" #include "src/Core/Core.h" #include "src/Resource/Serializable.h" @@ -13,12 +14,20 @@ namespace Nuake { NUAKECOMPONENT(SpriteComponent, "Sprite") + static void InitializeComponentClass() + { + BindComponentField<&SpriteComponent::Billboard>("Billboard", "Billboard"); + BindComponentField<&SpriteComponent::LockYRotation>("LockYRotation", "Lock Y Rotation"); + BindComponentField<&SpriteComponent::PositionFacing>("PositionFacing", "Position Facing"); + BindComponentField<&SpriteComponent::SpritePath>("SpritePath", "Sprite Path"); + } + public: bool Billboard; bool LockYRotation; bool PositionFacing; - std::string SpritePath; + ResourceFile SpritePath; Ref SpriteMesh; SpriteComponent(); From d62f241a163089769735b49221d05c6e95cb4ea7 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Fri, 13 Sep 2024 23:59:56 +0100 Subject: [PATCH 14/29] Sphere collider reflection --- Nuake/src/Scene/Components/SphereCollider.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Nuake/src/Scene/Components/SphereCollider.h b/Nuake/src/Scene/Components/SphereCollider.h index 6ffdabfa..7ad00e94 100644 --- a/Nuake/src/Scene/Components/SphereCollider.h +++ b/Nuake/src/Scene/Components/SphereCollider.h @@ -11,12 +11,28 @@ namespace Nuake { NUAKECOMPONENT(SphereColliderComponent, "Sphere Component") + static void InitializeComponentClass() + { + BindComponentField<&SphereColliderComponent::IsTrigger>("IsTrigger", "Is Trigger"); + BindComponentProperty<&SphereColliderComponent::SetRadius, &SphereColliderComponent::GetRadius>("Radius", "Radius"); + } + public: Ref Sphere; float Radius = 0.5f; bool IsTrigger = false; + void SetRadius(const float newRadius) + { + Radius = newRadius; + } + + float GetRadius() + { + return Radius; + } + json Serialize() { BEGIN_SERIALIZE(); From 1e570e17fd9c8536a63344486ff6d7a079d3d44a Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sat, 14 Sep 2024 09:40:20 +0100 Subject: [PATCH 15/29] Made component field type `ResourceFile` easier to work with --- Nuake/src/Scene/Components/FieldTypes.cpp | 18 ++++++++++++++++++ Nuake/src/Scene/Components/FieldTypes.h | 3 +++ 2 files changed, 21 insertions(+) create mode 100644 Nuake/src/Scene/Components/FieldTypes.cpp diff --git a/Nuake/src/Scene/Components/FieldTypes.cpp b/Nuake/src/Scene/Components/FieldTypes.cpp new file mode 100644 index 00000000..10d5f91d --- /dev/null +++ b/Nuake/src/Scene/Components/FieldTypes.cpp @@ -0,0 +1,18 @@ +#include "FieldTypes.h" + +#include "src/FileSystem/File.h" + +bool Nuake::ResourceFile::Exist() +{ + return file != nullptr && file->Exist(); +} + +std::string Nuake::ResourceFile::GetRelativePath() +{ + if (Exist()) + { + return file->GetRelativePath(); + } + + return ""; +} diff --git a/Nuake/src/Scene/Components/FieldTypes.h b/Nuake/src/Scene/Components/FieldTypes.h index e46ba0c2..da5acaa7 100644 --- a/Nuake/src/Scene/Components/FieldTypes.h +++ b/Nuake/src/Scene/Components/FieldTypes.h @@ -12,6 +12,9 @@ namespace Nuake { ResourceFile() {} ResourceFile(const Ref& inFile) : file(inFile) {} + + bool Exist(); + std::string GetRelativePath(); Ref file = nullptr; }; From d8d904b6ba9dab37acc693b7e49106e18c3f69fb Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:46:46 +0100 Subject: [PATCH 16/29] New reflection type `DynamicItemList` --- Editor/src/Windows/EditorSelectionPanel.cpp | 55 +++++++++++++++++++++ Editor/src/Windows/EditorSelectionPanel.h | 1 + Nuake/src/Scene/Components/FieldTypes.h | 8 ++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index a741ba1a..e7381279 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -33,6 +33,7 @@ EditorSelectionPanel::EditorSelectionPanel() REGISTER_TYPE_DRAWER(Vector3, EditorSelectionPanel::DrawFieldTypeVector3); REGISTER_TYPE_DRAWER(std::string, EditorSelectionPanel::DrawFieldTypeString); REGISTER_TYPE_DRAWER(ResourceFile, EditorSelectionPanel::DrawFieldTypeResourceFile); + REGISTER_TYPE_DRAWER(DynamicItemList, EditorSelectionPanel::DrawFieldTypeDynamicItemList); } void EditorSelectionPanel::ResolveFile(Ref file) @@ -783,3 +784,57 @@ void EditorSelectionPanel::DrawFieldTypeResourceFile(entt::meta_data& field, ent } } +void EditorSelectionPanel::DrawFieldTypeDynamicItemList(entt::meta_data& field, entt::meta_any& component) +{ + auto propDisplayName = field.prop(HashedName::DisplayName); + const char* displayName = *propDisplayName.value().try_cast(); + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + auto fieldValPtr = fieldVal.try_cast(); + if (fieldValPtr == nullptr) + { + ImGui::Text("ERR"); + } + + const auto& items = fieldValPtr->items; + const int index = fieldValPtr->index; + + // Check first to see if we are within the bounds + std::string selectedStr = ""; + if (index >= 0 || index < items.size()) + { + selectedStr = items[index]; + } + + std::string controlName = std::string("##") + displayName; + if (ImGui::BeginCombo(controlName.c_str(), selectedStr.c_str())) + { + for (int i = 0; i < items.size(); i++) + { + bool isSelected = (index == i); + std::string name = items[i]; + + if (name.empty()) + { + name = "Empty"; + } + + if (ImGui::Selectable(name.c_str(), isSelected)) + { + field.set(component, i); + } + + if (isSelected) + { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + } +} + diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 7bb92e3d..acc7b2a8 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -99,4 +99,5 @@ private: void DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component); void DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component); void DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeDynamicItemList(entt::meta_data& field, entt::meta_any& component); }; \ No newline at end of file diff --git a/Nuake/src/Scene/Components/FieldTypes.h b/Nuake/src/Scene/Components/FieldTypes.h index da5acaa7..0d5e0c70 100644 --- a/Nuake/src/Scene/Components/FieldTypes.h +++ b/Nuake/src/Scene/Components/FieldTypes.h @@ -10,7 +10,7 @@ namespace Nuake struct ResourceFile { - ResourceFile() {} + ResourceFile() = default; ResourceFile(const Ref& inFile) : file(inFile) {} bool Exist(); @@ -18,4 +18,10 @@ namespace Nuake Ref file = nullptr; }; + + struct DynamicItemList + { + std::vector items; + int index = -1; + }; } From 6149907576775fce6311317be92f5e27debb2c80 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:47:01 +0100 Subject: [PATCH 17/29] Skinned Model Component now reflected --- .../src/ComponentsPanel/SkinnedModelPanel.h | 288 +++++++++--------- .../Components/SkinnedModelComponent.cpp | 86 +++++- .../Scene/Components/SkinnedModelComponent.h | 53 ++-- Nuake/src/Scene/Systems/AnimationSystem.cpp | 11 +- 4 files changed, 260 insertions(+), 178 deletions(-) diff --git a/Editor/src/ComponentsPanel/SkinnedModelPanel.h b/Editor/src/ComponentsPanel/SkinnedModelPanel.h index 9083d2cd..482c2cbc 100644 --- a/Editor/src/ComponentsPanel/SkinnedModelPanel.h +++ b/Editor/src/ComponentsPanel/SkinnedModelPanel.h @@ -24,149 +24,149 @@ public: void Draw(Nuake::Entity entity) override { - using namespace Nuake; - if (!entity.HasComponent()) - return; - - SkinnedModelComponent& component = entity.GetComponent(); - BeginComponentTable(SKINNED MESH, SkinnedModelComponent); - { - ImGui::Text("Model"); - ImGui::TableNextColumn(); - - std::string label = "None"; - - const bool isModelNone = component.ModelResource == nullptr; - if (!isModelNone) - { - label = std::to_string(component.ModelResource->ID); - } - - if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) - { - } - - if (m_Expanded) - { - m_ModelInspector->Draw(); - } - - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath); - - if (Nuake::String::EndsWith(fullPath, ".model")) - { - - } - else - { - m_QueuedModelPath = fullPath; - ImGui::OpenPopup("Create Skeleton"); - } - } - ImGui::EndDragDropTarget(); - } - - if (ImGui::BeginPopupModal("Create Skeleton", NULL, ImGuiWindowFlags_AlwaysAutoResize)) - { - ImGui::SetItemDefaultFocus(); - ImGui::Text("Would you like to create the skeleton structure in the scene tree?"); - ImGui::Separator(); - - if (ImGui::Button("OK", ImVec2(120, 0))) - { - component.ModelPath = m_QueuedModelPath; - component.LoadModel(); - - Scene* scene = entity.GetScene(); - scene->CreateSkeleton(entity); - - ImGui::CloseCurrentPopup(); - } - - ImGui::SetItemDefaultFocus(); - ImGui::SameLine(); - - if (ImGui::Button("Cancel", ImVec2(120, 0))) - { - ImGui::CloseCurrentPopup(); - } - - ImGui::EndPopup(); - } - - ImGui::TableNextColumn(); - ComponentTableReset(component.ModelPath, ""); - - if (component.ModelResource) - { - auto& model = component.ModelResource; - ImGui::TableNextColumn(); - - { - ImGui::Text("Playing"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##playing", &model->IsPlaying); - - ImGui::TableNextColumn(); - ComponentTableReset(model->IsPlaying, true); - ImGui::TableNextColumn(); - } - - if(model->GetCurrentAnimation()) - { - ImGui::Text("Animation"); - ImGui::TableNextColumn(); - - uint32_t animIndex = model->GetCurrentAnimationIndex(); - uint32_t oldAnimIndex = animIndex; - auto animations = model->GetAnimations(); - if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str())) - { - for (uint32_t n = 0; n < model->GetAnimationsCount(); n++) - { - bool is_selected = (animIndex == n); - std::string animName = animations[n]->GetName(); - - if (animName.empty()) - { - animName = "Empty"; - } - - if (ImGui::Selectable(animName.c_str(), is_selected)) - { - animIndex = n; - } - - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - - if (animIndex != oldAnimIndex) - { - model->PlayAnimation(animIndex); - } - - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetAnimId"; - if (ImGui::Button(resetLabel.c_str())) - { - model->PlayAnimation(0); - } - ImGui::PopStyleColor(); - } - } - - } - EndComponentTable(); + // using namespace Nuake; + // if (!entity.HasComponent()) + // return; + // + // SkinnedModelComponent& component = entity.GetComponent(); + // BeginComponentTable(SKINNED MESH, SkinnedModelComponent); + // { + // ImGui::Text("Model"); + // ImGui::TableNextColumn(); + // + // std::string label = "None"; + // + // const bool isModelNone = component.ModelResource == nullptr; + // if (!isModelNone) + // { + // label = std::to_string(component.ModelResource->ID); + // } + // + // if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) + // { + // } + // + // if (m_Expanded) + // { + // m_ModelInspector->Draw(); + // } + // + // if (ImGui::BeginDragDropTarget()) + // { + // if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) + // { + // char* file = (char*)payload->Data; + // std::string fullPath = std::string(file, 256); + // fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath); + // + // if (Nuake::String::EndsWith(fullPath, ".model")) + // { + // + // } + // else + // { + // m_QueuedModelPath = fullPath; + // ImGui::OpenPopup("Create Skeleton"); + // } + // } + // ImGui::EndDragDropTarget(); + // } + // + // if (ImGui::BeginPopupModal("Create Skeleton", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + // { + // ImGui::SetItemDefaultFocus(); + // ImGui::Text("Would you like to create the skeleton structure in the scene tree?"); + // ImGui::Separator(); + // + // if (ImGui::Button("OK", ImVec2(120, 0))) + // { + // component.ModelPath = m_QueuedModelPath; + // component.LoadModel(); + // + // Scene* scene = entity.GetScene(); + // scene->CreateSkeleton(entity); + // + // ImGui::CloseCurrentPopup(); + // } + // + // ImGui::SetItemDefaultFocus(); + // ImGui::SameLine(); + // + // if (ImGui::Button("Cancel", ImVec2(120, 0))) + // { + // ImGui::CloseCurrentPopup(); + // } + // + // ImGui::EndPopup(); + // } + // + // ImGui::TableNextColumn(); + // ComponentTableReset(component.ModelPath, ""); + // + // if (component.ModelResource) + // { + // auto& model = component.ModelResource; + // ImGui::TableNextColumn(); + // + // { + // ImGui::Text("Playing"); + // ImGui::TableNextColumn(); + // + // ImGui::Checkbox("##playing", &model->IsPlaying); + // + // ImGui::TableNextColumn(); + // ComponentTableReset(model->IsPlaying, true); + // ImGui::TableNextColumn(); + // } + // + // if(model->GetCurrentAnimation()) + // { + // ImGui::Text("Animation"); + // ImGui::TableNextColumn(); + // + // uint32_t animIndex = model->GetCurrentAnimationIndex(); + // uint32_t oldAnimIndex = animIndex; + // auto animations = model->GetAnimations(); + // if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str())) + // { + // for (uint32_t n = 0; n < model->GetAnimationsCount(); n++) + // { + // bool is_selected = (animIndex == n); + // std::string animName = animations[n]->GetName(); + // + // if (animName.empty()) + // { + // animName = "Empty"; + // } + // + // if (ImGui::Selectable(animName.c_str(), is_selected)) + // { + // animIndex = n; + // } + // + // if (is_selected) + // ImGui::SetItemDefaultFocus(); + // } + // ImGui::EndCombo(); + // } + // + // if (animIndex != oldAnimIndex) + // { + // model->PlayAnimation(animIndex); + // } + // + // ImGui::TableNextColumn(); + // ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + // std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetAnimId"; + // if (ImGui::Button(resetLabel.c_str())) + // { + // model->PlayAnimation(0); + // } + // ImGui::PopStyleColor(); + // } + // } + // + // } + // EndComponentTable(); } }; \ No newline at end of file diff --git a/Nuake/src/Scene/Components/SkinnedModelComponent.cpp b/Nuake/src/Scene/Components/SkinnedModelComponent.cpp index 0dcee3f3..717ca80c 100644 --- a/Nuake/src/Scene/Components/SkinnedModelComponent.cpp +++ b/Nuake/src/Scene/Components/SkinnedModelComponent.cpp @@ -1,16 +1,92 @@ #include "SkinnedModelComponent.h" #include "src/Resource/ModelLoader.h" +#include "src/Scene/Entities/Entity.h" namespace Nuake { - SkinnedModelComponent::SkinnedModelComponent() + void SkinnedModelComponent::LoadModel(entt::entity e, Scene* scene) { + ModelLoader loader = ModelLoader(); + this->ModelResource = loader.LoadSkinnedModel(ModelPath.GetRelativePath()); + Entity entity = Entity{ e, scene }; + scene->CreateSkeleton(entity); + + RegenerateAnimationList(); } - void SkinnedModelComponent::LoadModel() + void SkinnedModelComponent::SetPlaying(bool play) { - auto loader = ModelLoader(); - this->ModelResource = loader.LoadSkinnedModel(ModelPath); + if (ModelResource == nullptr) + return; + ModelResource->IsPlaying = play; } -} \ No newline at end of file + + bool SkinnedModelComponent::GetIsPlaying() const + { + if (ModelResource == nullptr) + return false; + return ModelResource->IsPlaying; + } + + void SkinnedModelComponent::SetAnimationList(int i) + { + animationList.index = i; + + // If the model is valid then play the animation + if (ModelResource != nullptr) + { + ModelResource->PlayAnimation(animationList.index); + } + } + + void SkinnedModelComponent::RegenerateAnimationList() + { + if (ModelResource == nullptr) + { + return; + } + + // Regenerate the animation list + std::vector> animations = ModelResource->GetAnimations(); + for (uint32_t i = 0; i < animations.size(); i++) + { + Ref& animation = animations[i]; + if (animation == nullptr) + { + continue; + } + + animationList.items.push_back(animation->GetName()); + } + } + + json SkinnedModelComponent::Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_RES_FILE(ModelPath); + + if (ModelResource) + { + SERIALIZE_OBJECT(ModelResource); + } + END_SERIALIZE(); + } + + bool SkinnedModelComponent::Deserialize(const json& j) + { + DESERIALIZE_RES_FILE(ModelPath); + + ModelResource = CreateRef(); + + if (j.contains("ModelResource")) + { + auto& res = j["ModelResource"]; + ModelResource->Deserialize(res); + } + + RegenerateAnimationList(); + + return true; + } +} diff --git a/Nuake/src/Scene/Components/SkinnedModelComponent.h b/Nuake/src/Scene/Components/SkinnedModelComponent.h index 14461f96..36444a81 100644 --- a/Nuake/src/Scene/Components/SkinnedModelComponent.h +++ b/Nuake/src/Scene/Components/SkinnedModelComponent.h @@ -1,7 +1,10 @@ #pragma once #include "Component.h" +#include "FieldTypes.h" +#include "src/FileSystem/File.h" +#include "src/FileSystem/FileSystem.h" #include "src/Resource/Serializable.h" #include "src/Resource/SkinnedModel.h" @@ -10,44 +13,38 @@ namespace Nuake { + class Scene; + class SkinnedModelComponent : public Component { NUAKECOMPONENT(SkinnedModelComponent, "Skinned Model") + static void InitializeComponentClass() + { + BindComponentField<&SkinnedModelComponent::ModelPath>("ModelPath", "Model Path"); + BindComponentProperty<&SkinnedModelComponent::SetPlaying, &SkinnedModelComponent::GetIsPlaying>("Playing", "Playing"); + SetFlags(ComponentFieldTrait::Transient); + + BindComponentProperty<&SkinnedModelComponent::SetAnimationList, &SkinnedModelComponent::GetAnimationList>("Animation", "Animation"); + SetFlags(ComponentFieldTrait::Transient); + } + Ref ModelResource; - std::string ModelPath; + ResourceFile ModelPath; + DynamicItemList animationList; - SkinnedModelComponent(); + void LoadModel(entt::entity e, Scene* scene); - void LoadModel(); + void SetPlaying(bool play); + bool GetIsPlaying() const; - std::string directory; + DynamicItemList& GetAnimationList() { return animationList; } + void SetAnimationList(int i); - json Serialize() - { - BEGIN_SERIALIZE(); - SERIALIZE_VAL(ModelPath); + void RegenerateAnimationList(); - if (ModelResource) - { - SERIALIZE_OBJECT(ModelResource); - } - END_SERIALIZE(); - } + json Serialize(); - bool Deserialize(const json& j) - { - ModelPath = j["ModelPath"]; - - ModelResource = CreateRef(); - - if (j.contains("ModelResource")) - { - auto& res = j["ModelResource"]; - ModelResource->Deserialize(res); - } - - return true; - } + bool Deserialize(const json& j); }; } diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index 61c1508a..8118684b 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -31,7 +31,16 @@ namespace Nuake { auto [transformComponent, skinnedComponent] = view.get(e); - auto& model = skinnedComponent.ModelResource; + Ref model = skinnedComponent.ModelResource; + + // Load the model if it's not already loaded + // TODO: [WiggleWizard] Needs some sort of flag to infer that we've tried loading it once already, so + // we don't try loading the model every frame if it's invalid. + if (skinnedComponent.ModelPath.Exist() && skinnedComponent.ModelResource == nullptr) + { + skinnedComponent.LoadModel(e, m_Scene); + } + if (!model) { continue; From 1d5f578e86b6ad166391493c3734be4f5f2042c7 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:53:23 +0100 Subject: [PATCH 18/29] Rigidbody Component reflection --- .../src/Scene/Components/RigidbodyComponent.h | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/Nuake/src/Scene/Components/RigidbodyComponent.h b/Nuake/src/Scene/Components/RigidbodyComponent.h index 66a15127..a7804f03 100644 --- a/Nuake/src/Scene/Components/RigidbodyComponent.h +++ b/Nuake/src/Scene/Components/RigidbodyComponent.h @@ -16,6 +16,14 @@ namespace Nuake { { NUAKECOMPONENT(RigidBodyComponent, "Rigid Body") + static void InitializeComponentClass() + { + BindComponentField<&RigidBodyComponent::Mass>("Mass", "Mass"); + BindComponentField<&RigidBodyComponent::LockX>("LockX", "Lock X"); + BindComponentField<&RigidBodyComponent::LockY>("LockY", "Lock Y"); + BindComponentField<&RigidBodyComponent::LockZ>("LockZ", "Lock Z"); + } + public: float Mass; bool LockX = false; @@ -39,7 +47,7 @@ namespace Nuake { json Serialize() { BEGIN_SERIALIZE(); - SERIALIZE_VAL_LBL("Mass", Mass); + SERIALIZE_VAL(Mass); SERIALIZE_VAL(LockX); SERIALIZE_VAL(LockY); SERIALIZE_VAL(LockZ); @@ -48,22 +56,10 @@ namespace Nuake { bool Deserialize(const json& j) { - Mass = j["Mass"]; - - if (j.contains("LockX")) - { - LockX = j["LockX"]; - } - - if (j.contains("LockY")) - { - LockY = j["LockY"]; - } - - if (j.contains("LockZ")) - { - LockZ = j["LockZ"]; - } + DESERIALIZE_VAL(Mass); + DESERIALIZE_VAL(LockX); + DESERIALIZE_VAL(LockY); + DESERIALIZE_VAL(LockZ); return true; } From 2b06fe32defcd722b1fadea47f04992836686fa9 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sat, 14 Sep 2024 22:15:45 +0100 Subject: [PATCH 19/29] Small refactor of trait reflection --- Nuake/src/Core/Object/Object.h | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index 72f9d793..c8594ed4 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -60,25 +60,8 @@ namespace Nuake return static_cast>(e); } - inline ComponentTypeTrait operator|(ComponentTypeTrait lhs, ComponentTypeTrait rhs) - { - return static_cast(ToUnderlying(lhs) | ToUnderlying(rhs)); - } - - inline ComponentTypeTrait operator&(ComponentTypeTrait lhs, ComponentTypeTrait rhs) - { - return static_cast(ToUnderlying(lhs) & ToUnderlying(rhs)); - } - - inline ComponentFieldTrait operator|(ComponentFieldTrait lhs, ComponentFieldTrait rhs) - { - return static_cast(ToUnderlying(lhs) | ToUnderlying(rhs)); - } - - inline ComponentFieldTrait operator&(ComponentFieldTrait lhs, ComponentFieldTrait rhs) - { - return static_cast(ToUnderlying(lhs) & ToUnderlying(rhs)); - } + NK_ENUM_BITWISE_IMPL(ComponentTypeTrait); + NK_ENUM_BITWISE_IMPL(ComponentFieldTrait); } #define NUAKECOMPONENT(klass, componentName) \ From 0dcd383dbbe8e516acd6669ac589729942091340 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sun, 15 Sep 2024 00:10:59 +0100 Subject: [PATCH 20/29] Added the ability to add actions (buttons) to the inspector through reflection --- Editor/src/Windows/EditorSelectionPanel.cpp | 29 +++++++++++++++++++++ Nuake/src/Core/Object/Object.h | 18 +++++++++++++ Nuake/src/Scene/Components/FieldTypes.cpp | 10 +++++++ Nuake/src/Scene/Components/FieldTypes.h | 1 + 4 files changed, 58 insertions(+) diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index e7381279..17ba5726 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -597,6 +597,8 @@ void EditorSelectionPanel::DrawComponent(const Nuake::Entity& entity, entt::meta void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) { entt::meta_type componentMeta = component.type(); + + // Draw component bound data for (auto [fst, dataType] : componentMeta.data()) { const ComponentFieldTrait fieldTraits = dataType.traits(); @@ -622,6 +624,33 @@ void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) ImGui::TableNextRow(); } + + // Draw any actions bound to the component + for (auto [fst, funcMeta] : componentMeta.func()) + { + ImGui::TableSetColumnIndex(0); + + const ComponentFuncTrait funcTraits = funcMeta.traits(); + if ((funcTraits & ComponentFuncTrait::Action) == ComponentFuncTrait::Action) + { + ImGui::TableNextColumn(); + + std::string funcDisplayName = ""; + auto prop = funcMeta.prop(HashedName::DisplayName).value(); + if (prop) + { + funcDisplayName = std::string(*prop.try_cast()); + } + + std::string buttonName = funcDisplayName; + if (UI::SecondaryButton(buttonName.c_str())) + { + entt::meta_any result = funcMeta.invoke(component); + } + + ImGui::TableNextRow(); + } + } } void EditorSelectionPanel::DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component) diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index c8594ed4..2cad7125 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -22,6 +22,7 @@ namespace Nuake { NK_HASHED_STATIC_STR(GetComponentName) NK_HASHED_STATIC_STR(AddToEntity) + NK_HASHED_STATIC_STR(ActionName) }; struct HashedFieldPropName @@ -45,6 +46,13 @@ namespace Nuake InspectorExposed = 1 << 0, }; + enum class ComponentFuncTrait : uint16_t + { + None = 0, + // Exposes the component to be added via the inspector + Action = 1 << 0, + }; + enum class ComponentFieldTrait : uint16_t { None = 0, @@ -61,6 +69,7 @@ namespace Nuake } NK_ENUM_BITWISE_IMPL(ComponentTypeTrait); + NK_ENUM_BITWISE_IMPL(ComponentFuncTrait); NK_ENUM_BITWISE_IMPL(ComponentFieldTrait); } @@ -145,4 +154,13 @@ public: { \ static_assert((std::is_enum_v && ...), "All arguments must be of enum class type"); \ return ComponentFactory.traits((enums | ...)); \ + } \ + \ + template \ + static void BindAction(const char* funcName, const char* actionName) \ + { \ + ComponentFactory \ + .func(entt::hashed_string(funcName)) \ + .prop(HashedName::DisplayName, actionName); \ + SetFlags(ComponentFuncTrait::Action); \ } diff --git a/Nuake/src/Scene/Components/FieldTypes.cpp b/Nuake/src/Scene/Components/FieldTypes.cpp index 10d5f91d..c9ff4278 100644 --- a/Nuake/src/Scene/Components/FieldTypes.cpp +++ b/Nuake/src/Scene/Components/FieldTypes.cpp @@ -16,3 +16,13 @@ std::string Nuake::ResourceFile::GetRelativePath() return ""; } + +std::string Nuake::ResourceFile::GetAbsolutePath() +{ + if (Exist()) + { + return file->GetAbsolutePath(); + } + + return ""; +} diff --git a/Nuake/src/Scene/Components/FieldTypes.h b/Nuake/src/Scene/Components/FieldTypes.h index 0d5e0c70..5d4174e6 100644 --- a/Nuake/src/Scene/Components/FieldTypes.h +++ b/Nuake/src/Scene/Components/FieldTypes.h @@ -15,6 +15,7 @@ namespace Nuake bool Exist(); std::string GetRelativePath(); + std::string GetAbsolutePath(); Ref file = nullptr; }; From 7846a667a2ed4e9ddc5a31f0ca5217c0e1881780 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sun, 15 Sep 2024 00:11:12 +0100 Subject: [PATCH 21/29] Quake Map Component reflected --- Editor/src/ComponentsPanel/QuakeMapPanel.h | 124 ++++++++++---------- Nuake/src/Scene/Components/QuakeMap.h | 30 ++++- Nuake/src/Scene/Scene.cpp | 4 +- Nuake/src/Scene/Systems/QuakeMapBuilder.cpp | 2 +- 4 files changed, 89 insertions(+), 71 deletions(-) diff --git a/Editor/src/ComponentsPanel/QuakeMapPanel.h b/Editor/src/ComponentsPanel/QuakeMapPanel.h index f326b4ff..56546b70 100644 --- a/Editor/src/ComponentsPanel/QuakeMapPanel.h +++ b/Editor/src/ComponentsPanel/QuakeMapPanel.h @@ -13,67 +13,67 @@ public: void Draw(Nuake::Entity entity) override { - using namespace Nuake; - - if (!entity.HasComponent()) - return; - - Nuake::QuakeMapComponent& component = entity.GetComponent(); - BeginComponentTable(QUAKEMAP, Nuake::QuakeMapComponent); - { - { - ImGui::Text("Map"); - ImGui::TableNextColumn(); - - std::string path = component.Path; - ImGui::Button(component.Path.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - path = Nuake::FileSystem::AbsoluteToRelative(fullPath); - - component.Path = path; - } - ImGui::EndDragDropTarget(); - } - - ImGui::TableNextColumn(); - - ComponentTableReset(component.Path, ""); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Collision"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##Collison", &component.HasCollisions); - ImGui::TableNextColumn(); - ComponentTableReset(component.HasCollisions, true); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Auto Rebuild"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##AutoRebuild", &component.AutoRebuild); - ImGui::TableNextColumn(); - ComponentTableReset(component.AutoRebuild, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Build"); - ImGui::TableNextColumn(); - - if (UI::SecondaryButton("Build Geometry")) - { - Nuake::QuakeMapBuilder builder; - builder.BuildQuakeMap(entity, component.HasCollisions); - } - } - } - EndComponentTable(); + // using namespace Nuake; + // + // if (!entity.HasComponent()) + // return; + // + // Nuake::QuakeMapComponent& component = entity.GetComponent(); + // BeginComponentTable(QUAKEMAP, Nuake::QuakeMapComponent); + // { + // { + // ImGui::Text("Map"); + // ImGui::TableNextColumn(); + // + // std::string path = component.Path; + // ImGui::Button(component.Path.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + // if (ImGui::BeginDragDropTarget()) + // { + // if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map")) + // { + // char* file = (char*)payload->Data; + // std::string fullPath = std::string(file, 256); + // path = Nuake::FileSystem::AbsoluteToRelative(fullPath); + // + // component.Path = path; + // } + // ImGui::EndDragDropTarget(); + // } + // + // ImGui::TableNextColumn(); + // + // ComponentTableReset(component.Path, ""); + // } + // ImGui::TableNextColumn(); + // { + // ImGui::Text("Collision"); + // ImGui::TableNextColumn(); + // + // ImGui::Checkbox("##Collison", &component.HasCollisions); + // ImGui::TableNextColumn(); + // ComponentTableReset(component.HasCollisions, true); + // } + // ImGui::TableNextColumn(); + // { + // ImGui::Text("Auto Rebuild"); + // ImGui::TableNextColumn(); + // + // ImGui::Checkbox("##AutoRebuild", &component.AutoRebuild); + // ImGui::TableNextColumn(); + // ComponentTableReset(component.AutoRebuild, false); + // } + // ImGui::TableNextColumn(); + // { + // ImGui::Text("Build"); + // ImGui::TableNextColumn(); + // + // if (UI::SecondaryButton("Build Geometry")) + // { + // Nuake::QuakeMapBuilder builder; + // builder.BuildQuakeMap(entity, component.HasCollisions); + // } + // } + // } + // EndComponentTable(); } }; \ No newline at end of file diff --git a/Nuake/src/Scene/Components/QuakeMap.h b/Nuake/src/Scene/Components/QuakeMap.h index e777febf..f99c4d3b 100644 --- a/Nuake/src/Scene/Components/QuakeMap.h +++ b/Nuake/src/Scene/Components/QuakeMap.h @@ -1,7 +1,9 @@ #pragma once #include "Component.h" +#include "FieldTypes.h" +#include "src/FileSystem/File.h" #include "src/Rendering/Mesh/Mesh.h" #include "src/Resource/Serializable.h" #include "src/Scene/Systems/QuakeMapBuilder.h" @@ -11,27 +13,39 @@ #include #include + namespace Nuake { class QuakeMapComponent : public Component { NUAKECOMPONENT(QuakeMapComponent, "Quake Map") + static void InitializeComponentClass() + { + BindComponentField<&QuakeMapComponent::HasCollisions>("HasCollisions", "Has Collisions"); + BindComponentField<&QuakeMapComponent::Path>("Path", "Path"); + BindComponentField<&QuakeMapComponent::AutoRebuild>("AutoRebuild", "Auto Rebuild"); + + BindAction<&QuakeMapComponent::ActionRebuild>("Rebuild", "Rebuild"); + } + public: + bool HasCollisions = false; + ResourceFile Path; + bool AutoRebuild = false; + float ScaleFactor = 1.f; + std::vector> m_Meshes; std::vector m_Brushes; std::vector m_SerializedBrushIDs; - std::string Path; - float ScaleFactor = 1.0f; - bool HasCollisions = false; - bool AutoRebuild = false; + void ActionRebuild(); json Serialize() { BEGIN_SERIALIZE(); SERIALIZE_VAL(HasCollisions); - SERIALIZE_VAL(Path); + SERIALIZE_RES_FILE(Path); SERIALIZE_VAL(AutoRebuild); for (uint32_t i = 0; i < std::size(m_Brushes); i++) @@ -64,7 +78,7 @@ namespace Nuake { } } - this->Path = j["Path"]; + DESERIALIZE_RES_FILE(Path); this->HasCollisions = j["HasCollisions"]; return true; } @@ -81,4 +95,8 @@ namespace Nuake { m_SerializedBrushIDs.clear(); } }; + + inline void QuakeMapComponent::ActionRebuild() + { + } } diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index a48f3e6b..f7b73998 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -273,9 +273,9 @@ namespace Nuake for (const auto& e : view) { auto& map = view.get(e); - if (map.AutoRebuild && !map.Path.empty() && FileSystem::FileExists(map.Path)) + if (map.AutoRebuild && map.Path.Exist()) { - if (auto file = FileSystem::GetFile(map.Path); file->Exist() && file->GetHasBeenModified()) + if (auto file = FileSystem::GetFile(map.Path.GetRelativePath()); file->Exist() && file->GetHasBeenModified()) { file->SetHasBeenModified(false); diff --git a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp index cb1ad4f7..67b9be85 100644 --- a/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp +++ b/Nuake/src/Scene/Systems/QuakeMapBuilder.cpp @@ -67,7 +67,7 @@ namespace Nuake { m_Scene->DestroyEntity(e); } - map_parser_load((FileSystem::Root + quakeMapC.Path).c_str()); + map_parser_load(quakeMapC.Path.GetAbsolutePath().c_str()); geo_generator_run(); DefaultMaterial = MaterialManager::Get()->GetMaterial("default"); From 269533eb03233115de5f0ff850aadae34949b01b Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sun, 15 Sep 2024 21:28:22 +0100 Subject: [PATCH 22/29] Particle Emitter Component reflected --- .../ComponentsPanel/ParticleEmitterPanel.h | 132 ------------------ Editor/src/Windows/EditorSelectionPanel.cpp | 16 ++- Nuake/src/Rendering/SceneRenderer.cpp | 17 ++- Nuake/src/Scene/Components/Component.h | 1 + Nuake/src/Scene/Components/FieldTypes.h | 1 + .../Components/ParticleEmitterComponent.cpp | 19 +-- .../Components/ParticleEmitterComponent.h | 23 +++ 7 files changed, 59 insertions(+), 150 deletions(-) diff --git a/Editor/src/ComponentsPanel/ParticleEmitterPanel.h b/Editor/src/ComponentsPanel/ParticleEmitterPanel.h index d45495de..02bbfc47 100644 --- a/Editor/src/ComponentsPanel/ParticleEmitterPanel.h +++ b/Editor/src/ComponentsPanel/ParticleEmitterPanel.h @@ -18,138 +18,6 @@ public: void Draw(Nuake::Entity entity) override { - if (!entity.HasComponent()) - return; - - auto& component = entity.GetComponent(); - BeginComponentTable(PARTICLE EMITTER, Nuake::ParticleEmitterComponent); - { - { - ImGui::Text("Particle Material"); - ImGui::TableNextColumn(); - - std::string label = "Empty"; - if (component.ParticleMaterial && !component.ParticleMaterial->Path.empty()) - { - label = component.ParticleMaterial->Path; - } - - if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) - { - - } - - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Material")) - { - char* file = (char*)payload->Data; - std::string fullPath = std::string(file, 256); - - fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath); - - Ref material = Nuake::ResourceLoader::LoadMaterial(fullPath); - component.ParticleMaterial = material; - } - ImGui::EndDragDropTarget(); - } - - //std::string childId = "materialEditorParticle"; - //ImGui::BeginChild(childId.c_str(), ImVec2(0, 0), false); - //{ - // MaterialEditor editor; - // editor.Draw(component.ParticleMaterial); - //} - //ImGui::EndChild(); - - ImGui::TableNextColumn(); - //ComponentTableReset(component.ParticleColor, Nuake::Vector4(1, 1, 1, 1)); - } - - ImGui::TableNextColumn(); - { - ImGui::Text("Amount"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##ParticleAmount", &component.Amount, 0.1f, 0.0f, 500.0f); - ImGui::TableNextColumn(); - ComponentTableReset(component.Amount, 10.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Particle Scale"); - ImGui::TableNextColumn(); - - ImGuiHelper::DrawVec3("##particleSize", &component.ParticleScale); - - ImGui::TableNextColumn(); - ComponentTableReset(component.ParticleScale, Nuake::Vector3(0.1, 0.1, 0.1)); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Particle Scale Random"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##particleSizeRandom", &component.ScaleRandomness, 0.01f, 0.0f); - - ImGui::TableNextColumn(); - ComponentTableReset(component.ScaleRandomness, 0.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Global Space"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##globalSpace", &component.GlobalSpace); - - ImGui::TableNextColumn(); - ComponentTableReset(component.GlobalSpace, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Rate"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##ParticleRate", &component.Rate, 0.1f, 0.0f, 10.0f); - ImGui::TableNextColumn(); - ComponentTableReset(component.Rate, 0.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Life"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##ParticleLife", &component.Life, 0.1f, 0.0f, 100.0f); - ImGui::TableNextColumn(); - ComponentTableReset(component.Life, 5.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Gravity"); - ImGui::TableNextColumn(); - - ImGuiHelper::DrawVec3("Gravity", &component.Gravity); - ImGui::TableNextColumn(); - ComponentTableReset(component.Gravity, Nuake::Vector3(0, -1, 0)); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Gravity Random"); - ImGui::TableNextColumn(); - ImGui::DragFloat("##GravityRandom", &component.GravityRandom, 0.01f, 0.0f, 1.0f); - ImGui::TableNextColumn(); - ComponentTableReset(component.GravityRandom, 0.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Radius"); - ImGui::TableNextColumn(); - ImGui::DragFloat("##ParticleRadius", &component.Radius, 0.01f, 0.0f, 10.0f); - ImGui::TableNextColumn(); - ComponentTableReset(component.Radius, 1.0f); - } - } - EndComponentTable(); } }; \ No newline at end of file diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 17ba5726..2f6a7525 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -16,6 +16,8 @@ #include +#include "Tracy.hpp" + #define REGISTER_TYPE_DRAWER(forType, fn) \ FieldTypeDrawers[entt::type_id().hash()] = std::bind(&fn, this, std::placeholders::_1, std::placeholders::_2); @@ -122,6 +124,8 @@ void EditorSelectionPanel::DrawNone() void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) { + ZoneScoped; + if (!entity.IsValid()) { return; @@ -545,6 +549,8 @@ void EditorSelectionPanel::DrawNetScriptPanel(Ref file) void EditorSelectionPanel::DrawComponent(const Nuake::Entity& entity, entt::meta_any& component) { + ZoneScoped; + const entt::meta_type componentMeta = component.type(); const std::string componentName = Component::GetName(componentMeta); @@ -580,6 +586,8 @@ void EditorSelectionPanel::DrawComponent(const Nuake::Entity& entity, entt::meta ImGui::TableSetupColumn("set", 0, 0.65f); ImGui::TableSetupColumn("reset", 0, 0.1f); + ImGui::TableNextRow(); + DrawComponentContent(component); ImGui::EndTable(); @@ -596,6 +604,8 @@ void EditorSelectionPanel::DrawComponent(const Nuake::Entity& entity, entt::meta void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) { + ZoneScoped; + entt::meta_type componentMeta = component.type(); // Draw component bound data @@ -608,7 +618,7 @@ void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) continue; } - ImGui::TableNextColumn(); + ImGui::TableSetColumnIndex(0); // Search for the appropriate drawer for the type entt::id_type dataId = dataType.type().id(); @@ -628,12 +638,10 @@ void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component) // Draw any actions bound to the component for (auto [fst, funcMeta] : componentMeta.func()) { - ImGui::TableSetColumnIndex(0); - const ComponentFuncTrait funcTraits = funcMeta.traits(); if ((funcTraits & ComponentFuncTrait::Action) == ComponentFuncTrait::Action) { - ImGui::TableNextColumn(); + ImGui::TableSetColumnIndex(0); std::string funcDisplayName = ""; auto prop = funcMeta.prop(HashedName::DisplayName).value(); diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index ff7b2162d..773af6cb 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -917,9 +917,24 @@ namespace Nuake { auto [transform, emitterComponent, visibility] = particleEmitterView.get(e); - if (!visibility.Visible || !emitterComponent.ParticleMaterial) + if (!visibility.Visible) continue; + if (emitterComponent.resFile.dirty) + { + emitterComponent.resFile.dirty = false; + if (emitterComponent.resFile.Exist()) + { + Ref material = Nuake::ResourceLoader::LoadMaterial(emitterComponent.resFile.GetRelativePath()); + emitterComponent.ParticleMaterial = material; + } + } + + if (emitterComponent.ParticleMaterial == nullptr) + { + continue; + } + Renderer::QuadMesh->SetMaterial(emitterComponent.ParticleMaterial); Vector3 oldColor = Renderer::QuadMesh->GetMaterial()->data.m_AlbedoColor; diff --git a/Nuake/src/Scene/Components/Component.h b/Nuake/src/Scene/Components/Component.h index 5bfe9f06..1a07dc6d 100644 --- a/Nuake/src/Scene/Components/Component.h +++ b/Nuake/src/Scene/Components/Component.h @@ -1,6 +1,7 @@ #pragma once #include "src/Core/Object/Object.h" +#include "FieldTypes.h" namespace Nuake { diff --git a/Nuake/src/Scene/Components/FieldTypes.h b/Nuake/src/Scene/Components/FieldTypes.h index 5d4174e6..3f321904 100644 --- a/Nuake/src/Scene/Components/FieldTypes.h +++ b/Nuake/src/Scene/Components/FieldTypes.h @@ -18,6 +18,7 @@ namespace Nuake std::string GetAbsolutePath(); Ref file = nullptr; + bool dirty = true; }; struct DynamicItemList diff --git a/Nuake/src/Scene/Components/ParticleEmitterComponent.cpp b/Nuake/src/Scene/Components/ParticleEmitterComponent.cpp index 80297e15..3c74162e 100644 --- a/Nuake/src/Scene/Components/ParticleEmitterComponent.cpp +++ b/Nuake/src/Scene/Components/ParticleEmitterComponent.cpp @@ -1,11 +1,14 @@ #include "src/Scene/Components/ParticleEmitterComponent.h" +#include "src/FileSystem/File.h" #include #include + namespace Nuake { json ParticleEmitterComponent::Serialize() { BEGIN_SERIALIZE(); + SERIALIZE_RES_FILE(resFile); SERIALIZE_VEC3(ParticleScale); SERIALIZE_VAL(Amount); SERIALIZE_VAL(Life); @@ -14,10 +17,6 @@ namespace Nuake SERIALIZE_VAL(GravityRandom); SERIALIZE_VAL(Radius); SERIALIZE_VAL(GlobalSpace); - if (ParticleMaterial) - { - SERIALIZE_OBJECT(ParticleMaterial); - } SERIALIZE_VAL(LifeRandomness); SERIALIZE_VAL(ScaleRandomness); END_SERIALIZE(); @@ -51,16 +50,10 @@ namespace Nuake { DESERIALIZE_VAL(GlobalSpace); } - if (j.contains("ParticleMaterial")) - { - if (j["ParticleMaterial"].contains("Path")) - { - Ref newMaterial = ResourceLoader::LoadMaterial(j["ParticleMaterial"]["Path"]); - ParticleMaterial = newMaterial; - } - } GravityRandom = j["GravityRandom"]; Radius = j["Radius"]; + + DESERIALIZE_RES_FILE(resFile); return true; } -} \ No newline at end of file +} diff --git a/Nuake/src/Scene/Components/ParticleEmitterComponent.h b/Nuake/src/Scene/Components/ParticleEmitterComponent.h index 755294aa..f6dc6846 100644 --- a/Nuake/src/Scene/Components/ParticleEmitterComponent.h +++ b/Nuake/src/Scene/Components/ParticleEmitterComponent.h @@ -15,10 +15,33 @@ namespace Nuake { NUAKECOMPONENT(ParticleEmitterComponent, "Particle Emitter") + static void InitializeComponentClass() + { + BindComponentField<&ParticleEmitterComponent::resFile>("Particle", "Particle"); + BindComponentField<&ParticleEmitterComponent::Amount>("Amount", "Amount"); + FieldFloatLimits(0.1f, 0.0f, 500.0f); + BindComponentField<&ParticleEmitterComponent::LifeRandomness>("LifeRandomness", "Life Randomness"); + FieldFloatLimits(0.1f, 0.f, 9999.f); + BindComponentField<&ParticleEmitterComponent::Life>("Life", "Life"); + FieldFloatLimits(0.1f, 0.0f, 100.0f); + BindComponentField<&ParticleEmitterComponent::Rate>("Rate", "Rate"); + FieldFloatLimits(0.1f, 0.0f, 10.0f); + BindComponentField<&ParticleEmitterComponent::ScaleRandomness>("ScaleRandomness", "Scale Randomness"); + FieldFloatLimits(0.01f, 0.0f, 0.f); + BindComponentField<&ParticleEmitterComponent::ParticleScale>("ParticleScale", "Particle Scale"); + BindComponentField<&ParticleEmitterComponent::GlobalSpace>("GlobalSpace", "Global Space"); + BindComponentField<&ParticleEmitterComponent::Gravity>("Gravity", "Gravity"); + BindComponentField<&ParticleEmitterComponent::GravityRandom>("GravityRandom", "Gravity Random"); + FieldFloatLimits(0.01f, 0.0f, 1.0f); + BindComponentField<&ParticleEmitterComponent::Radius>("Radius", "Radius"); + FieldFloatLimits(0.01f, 0.0f, 10.0f); + } + public: ParticleEmitterComponent() = default; ~ParticleEmitterComponent() = default; + ResourceFile resFile; Ref ParticleMaterial = CreateRef(); float Amount; From baac971deb86b9f843d979aa12a855ad39b13eb8 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sun, 15 Sep 2024 23:06:06 +0100 Subject: [PATCH 23/29] A little bit of cleanup --- .../src/ComponentsPanel/AudioEmitterPanel.h | 20 -- .../ComponentsPanel/ParticleEmitterPanel.h | 23 --- Editor/src/ComponentsPanel/QuakeMapPanel.h | 79 -------- Editor/src/ComponentsPanel/RigidbodyPanel.h | 62 ------- .../src/ComponentsPanel/SkinnedModelPanel.h | 172 ------------------ .../src/ComponentsPanel/SphereColliderPanel.h | 40 ---- Editor/src/ComponentsPanel/SpritePanel.h | 20 -- Editor/src/ComponentsPanel/UIPanel.h | 61 ------- Editor/src/Windows/EditorSelectionPanel.cpp | 32 ++-- Editor/src/Windows/EditorSelectionPanel.h | 15 -- 10 files changed, 16 insertions(+), 508 deletions(-) delete mode 100644 Editor/src/ComponentsPanel/AudioEmitterPanel.h delete mode 100644 Editor/src/ComponentsPanel/ParticleEmitterPanel.h delete mode 100644 Editor/src/ComponentsPanel/QuakeMapPanel.h delete mode 100644 Editor/src/ComponentsPanel/RigidbodyPanel.h delete mode 100644 Editor/src/ComponentsPanel/SkinnedModelPanel.h delete mode 100644 Editor/src/ComponentsPanel/SphereColliderPanel.h delete mode 100644 Editor/src/ComponentsPanel/SpritePanel.h delete mode 100644 Editor/src/ComponentsPanel/UIPanel.h diff --git a/Editor/src/ComponentsPanel/AudioEmitterPanel.h b/Editor/src/ComponentsPanel/AudioEmitterPanel.h deleted file mode 100644 index f7449ab6..00000000 --- a/Editor/src/ComponentsPanel/AudioEmitterPanel.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "ComponentPanel.h" - -#include "src/FileSystem/FileSystem.h" -#include -#include -#include - - -class AudioEmitterPanel : ComponentPanel -{ -public: - AudioEmitterPanel() = default; - ~AudioEmitterPanel() = default; - - void Draw(Nuake::Entity entity) override - { - - } -}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/ParticleEmitterPanel.h b/Editor/src/ComponentsPanel/ParticleEmitterPanel.h deleted file mode 100644 index 02bbfc47..00000000 --- a/Editor/src/ComponentsPanel/ParticleEmitterPanel.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "ComponentPanel.h" - -#include "src/FileSystem/FileSystem.h" -#include -#include -#include -#include "MaterialEditor.h" -#include -#include - -class ParticleEmitterPanel : ComponentPanel -{ -public: - Scope _modelInspector; - - ParticleEmitterPanel() {} - - void Draw(Nuake::Entity entity) override - { - - } -}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/QuakeMapPanel.h b/Editor/src/ComponentsPanel/QuakeMapPanel.h deleted file mode 100644 index 56546b70..00000000 --- a/Editor/src/ComponentsPanel/QuakeMapPanel.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include "ComponentPanel.h" -#include -#include "src/Scene/Systems/QuakeMapBuilder.h" -#include "src/FileSystem/FileSystem.h" -#include -#include - -class QuakeMapPanel : ComponentPanel { - -public: - QuakeMapPanel() {} - - void Draw(Nuake::Entity entity) override - { - // using namespace Nuake; - // - // if (!entity.HasComponent()) - // return; - // - // Nuake::QuakeMapComponent& component = entity.GetComponent(); - // BeginComponentTable(QUAKEMAP, Nuake::QuakeMapComponent); - // { - // { - // ImGui::Text("Map"); - // ImGui::TableNextColumn(); - // - // std::string path = component.Path; - // ImGui::Button(component.Path.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); - // if (ImGui::BeginDragDropTarget()) - // { - // if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map")) - // { - // char* file = (char*)payload->Data; - // std::string fullPath = std::string(file, 256); - // path = Nuake::FileSystem::AbsoluteToRelative(fullPath); - // - // component.Path = path; - // } - // ImGui::EndDragDropTarget(); - // } - // - // ImGui::TableNextColumn(); - // - // ComponentTableReset(component.Path, ""); - // } - // ImGui::TableNextColumn(); - // { - // ImGui::Text("Collision"); - // ImGui::TableNextColumn(); - // - // ImGui::Checkbox("##Collison", &component.HasCollisions); - // ImGui::TableNextColumn(); - // ComponentTableReset(component.HasCollisions, true); - // } - // ImGui::TableNextColumn(); - // { - // ImGui::Text("Auto Rebuild"); - // ImGui::TableNextColumn(); - // - // ImGui::Checkbox("##AutoRebuild", &component.AutoRebuild); - // ImGui::TableNextColumn(); - // ComponentTableReset(component.AutoRebuild, false); - // } - // ImGui::TableNextColumn(); - // { - // ImGui::Text("Build"); - // ImGui::TableNextColumn(); - // - // if (UI::SecondaryButton("Build Geometry")) - // { - // Nuake::QuakeMapBuilder builder; - // builder.BuildQuakeMap(entity, component.HasCollisions); - // } - // } - // } - // EndComponentTable(); - } -}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/RigidbodyPanel.h b/Editor/src/ComponentsPanel/RigidbodyPanel.h deleted file mode 100644 index 89a10b30..00000000 --- a/Editor/src/ComponentsPanel/RigidbodyPanel.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include "ComponentPanel.h" -#include -#include "src/FileSystem/FileSystem.h" - -class RigidbodyPanel : ComponentPanel { - -public: - RigidbodyPanel() {} - - void Draw(Nuake::Entity entity) override - { - if (!entity.HasComponent()) - return; - - auto& component = entity.GetComponent(); - BeginComponentTable(RIGIDBODY, Nuake::RigidBodyComponent); - { - { - ImGui::Text("Mass"); - ImGui::TableNextColumn(); - - ImGui::DragFloat("##Mass", &component.Mass, 0.01f, 0.1f); - component.Mass = std::max(component.Mass, 0.0f); - ImGui::TableNextColumn(); - ComponentTableReset(component.Mass, 0.0f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Lock X axis"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##lockx", &component.LockX); - - ImGui::TableNextColumn(); - ComponentTableReset(component.LockX, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Lock Y axis"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##locky", &component.LockY); - - ImGui::TableNextColumn(); - ComponentTableReset(component.LockY, false); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Lock Z axis"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##lockz", &component.LockZ); - - ImGui::TableNextColumn(); - ComponentTableReset(component.LockZ, false); - } - ImGui::TableNextColumn(); - } - EndComponentTable(); - } -}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/SkinnedModelPanel.h b/Editor/src/ComponentsPanel/SkinnedModelPanel.h deleted file mode 100644 index 482c2cbc..00000000 --- a/Editor/src/ComponentsPanel/SkinnedModelPanel.h +++ /dev/null @@ -1,172 +0,0 @@ -#pragma once -#include -#include "ComponentPanel.h" -#include "ModelResourceInspector.h" - -#include -#include - -#include -#include - -class SkinnedModelPanel : ComponentPanel -{ -private: - Scope m_ModelInspector; - bool m_Expanded = false; - std::string m_QueuedModelPath; - -public: - SkinnedModelPanel() - { - CreateScope(); - } - - void Draw(Nuake::Entity entity) override - { - // using namespace Nuake; - // if (!entity.HasComponent()) - // return; - // - // SkinnedModelComponent& component = entity.GetComponent(); - // BeginComponentTable(SKINNED MESH, SkinnedModelComponent); - // { - // ImGui::Text("Model"); - // ImGui::TableNextColumn(); - // - // std::string label = "None"; - // - // const bool isModelNone = component.ModelResource == nullptr; - // if (!isModelNone) - // { - // label = std::to_string(component.ModelResource->ID); - // } - // - // if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0))) - // { - // } - // - // if (m_Expanded) - // { - // m_ModelInspector->Draw(); - // } - // - // if (ImGui::BeginDragDropTarget()) - // { - // if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model")) - // { - // char* file = (char*)payload->Data; - // std::string fullPath = std::string(file, 256); - // fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath); - // - // if (Nuake::String::EndsWith(fullPath, ".model")) - // { - // - // } - // else - // { - // m_QueuedModelPath = fullPath; - // ImGui::OpenPopup("Create Skeleton"); - // } - // } - // ImGui::EndDragDropTarget(); - // } - // - // if (ImGui::BeginPopupModal("Create Skeleton", NULL, ImGuiWindowFlags_AlwaysAutoResize)) - // { - // ImGui::SetItemDefaultFocus(); - // ImGui::Text("Would you like to create the skeleton structure in the scene tree?"); - // ImGui::Separator(); - // - // if (ImGui::Button("OK", ImVec2(120, 0))) - // { - // component.ModelPath = m_QueuedModelPath; - // component.LoadModel(); - // - // Scene* scene = entity.GetScene(); - // scene->CreateSkeleton(entity); - // - // ImGui::CloseCurrentPopup(); - // } - // - // ImGui::SetItemDefaultFocus(); - // ImGui::SameLine(); - // - // if (ImGui::Button("Cancel", ImVec2(120, 0))) - // { - // ImGui::CloseCurrentPopup(); - // } - // - // ImGui::EndPopup(); - // } - // - // ImGui::TableNextColumn(); - // ComponentTableReset(component.ModelPath, ""); - // - // if (component.ModelResource) - // { - // auto& model = component.ModelResource; - // ImGui::TableNextColumn(); - // - // { - // ImGui::Text("Playing"); - // ImGui::TableNextColumn(); - // - // ImGui::Checkbox("##playing", &model->IsPlaying); - // - // ImGui::TableNextColumn(); - // ComponentTableReset(model->IsPlaying, true); - // ImGui::TableNextColumn(); - // } - // - // if(model->GetCurrentAnimation()) - // { - // ImGui::Text("Animation"); - // ImGui::TableNextColumn(); - // - // uint32_t animIndex = model->GetCurrentAnimationIndex(); - // uint32_t oldAnimIndex = animIndex; - // auto animations = model->GetAnimations(); - // if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str())) - // { - // for (uint32_t n = 0; n < model->GetAnimationsCount(); n++) - // { - // bool is_selected = (animIndex == n); - // std::string animName = animations[n]->GetName(); - // - // if (animName.empty()) - // { - // animName = "Empty"; - // } - // - // if (ImGui::Selectable(animName.c_str(), is_selected)) - // { - // animIndex = n; - // } - // - // if (is_selected) - // ImGui::SetItemDefaultFocus(); - // } - // ImGui::EndCombo(); - // } - // - // if (animIndex != oldAnimIndex) - // { - // model->PlayAnimation(animIndex); - // } - // - // ImGui::TableNextColumn(); - // ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); - // std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetAnimId"; - // if (ImGui::Button(resetLabel.c_str())) - // { - // model->PlayAnimation(0); - // } - // ImGui::PopStyleColor(); - // } - // } - // - // } - // EndComponentTable(); - } -}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/SphereColliderPanel.h b/Editor/src/ComponentsPanel/SphereColliderPanel.h deleted file mode 100644 index 6374df31..00000000 --- a/Editor/src/ComponentsPanel/SphereColliderPanel.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include "ComponentPanel.h" -#include -#include "src/FileSystem/FileSystem.h" -#include - -class SphereColliderPanel : ComponentPanel { -public: - SphereColliderPanel() {} - - void Draw(Nuake::Entity entity) override - { - if (!entity.HasComponent()) - return; - - auto& component = entity.GetComponent(); - BeginComponentTable(SPHERE COLLIDER, Nuake::SphereColliderComponent); - { - { - ImGui::Text("Size"); - ImGui::TableNextColumn(); - ImGui::DragFloat("##Radius", &component.Radius, 0.01f, 0.001f); - - component.Radius = std::max(component.Radius, 0.001f); - ImGui::TableNextColumn(); - ComponentTableReset(component.Radius, 0.5f); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Is Trigger"); - ImGui::TableNextColumn(); - - ImGui::Checkbox("##isTrigger", &component.IsTrigger); - ImGui::TableNextColumn(); - ComponentTableReset(component.IsTrigger, false); - } - } - EndComponentTable(); - } -}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/SpritePanel.h b/Editor/src/ComponentsPanel/SpritePanel.h deleted file mode 100644 index bc03e632..00000000 --- a/Editor/src/ComponentsPanel/SpritePanel.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "ComponentPanel.h" - -#include "src/FileSystem/FileSystem.h" -#include -#include -#include - - -class SpritePanel : ComponentPanel -{ -public: - SpritePanel() = default; - ~SpritePanel() = default; - - void Draw(Nuake::Entity entity) override - { - - } -}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/UIPanel.h b/Editor/src/ComponentsPanel/UIPanel.h deleted file mode 100644 index 0f4b48fc..00000000 --- a/Editor/src/ComponentsPanel/UIPanel.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once -#include "ComponentPanel.h" - -#include "src/FileSystem/FileSystem.h" -#include -#include -#include - - -class UIPanel : ComponentPanel -{ -public: - UIPanel() = default; - ~UIPanel() = default; - - void Draw(Nuake::Entity entity) override - { - // using namespace Nuake; - // - // if (!entity.HasComponent()) - // return; - // - // auto& component = entity.GetComponent(); - // BeginComponentTable(UI EMITTER, UIComponent); - // { - // { - // ImGui::Text("HTML File"); - // ImGui::TableNextColumn(); - // - // std::string path = component.UIFilePath; - // ImGui::Button(component.UIFilePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); - // if (ImGui::BeginDragDropTarget()) - // { - // if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_UIFile")) - // { - // char* file = (char*)payload->Data; - // std::string fullPath = std::string(file, 256); - // path = Nuake::FileSystem::AbsoluteToRelative(fullPath); - // component.UIFilePath = path; - // } - // ImGui::EndDragDropTarget(); - // } - // - // ImGui::TableNextColumn(); - // - // ComponentTableReset(component.UIFilePath, ""); - // } - // ImGui::TableNextColumn(); - // { - // ImGui::Text("Worldspace"); - // ImGui::TableNextColumn(); - // - // ImGui::Checkbox("##WorldSpace", &component.IsWorldSpace); - // ImGui::TableNextColumn(); - // - // ComponentTableReset(component.IsWorldSpace, false); - // } - // } - // EndComponentTable(); - } -}; \ No newline at end of file diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 2f6a7525..0e66433d 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -159,25 +159,25 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) // Draw each component properties panels. - // mLightPanel.Draw(entity); - // mScriptPanel.Draw(entity); - // mNetScriptPanel.Draw(entity); + mLightPanel.Draw(entity); + mScriptPanel.Draw(entity); + mNetScriptPanel.Draw(entity); // mAudioEmitterPanel.Draw(entity); // mParticleEmitterPanel.Draw(entity); - // mSpritePanel.Draw(entity); - // mMeshPanel.Draw(entity); + // mSpritePanel.Draw(entity); + mMeshPanel.Draw(entity); // mSkinnedModelPanel.Draw(entity); - // mBonePanel.Draw(entity); - // mQuakeMapPanel.Draw(entity); - // mCameraPanel.Draw(entity); - // mRigidbodyPanel.Draw(entity); - // mBoxColliderPanel.Draw(entity); - // mSphereColliderPanel.Draw(entity); - // mCapsuleColliderPanel.Draw(entity); - // mCylinderColliderPanel.Draw(entity); - // mMeshColliderPanel.Draw(entity); - // mCharacterControllerPanel.Draw(entity); - // mNavMeshVolumePanel.Draw(entity); + mBonePanel.Draw(entity); + // mQuakeMapPanel.Draw(entity); + mCameraPanel.Draw(entity); + // mRigidbodyPanel.Draw(entity); + mBoxColliderPanel.Draw(entity); + // mSphereColliderPanel.Draw(entity); + mCapsuleColliderPanel.Draw(entity); + mCylinderColliderPanel.Draw(entity); + mMeshColliderPanel.Draw(entity); + mCharacterControllerPanel.Draw(entity); + mNavMeshVolumePanel.Draw(entity); // mUiPanel.Draw(entity); using namespace Nuake; diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index acc7b2a8..8788ff56 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -9,23 +9,16 @@ #include "../ComponentsPanel/LightPanel.h" #include "../ComponentsPanel/ScriptPanel.h" #include "../ComponentsPanel/MeshPanel.h" -#include "../ComponentsPanel/QuakeMapPanel.h" #include "../ComponentsPanel/CameraPanel.h" -#include "../ComponentsPanel/RigidbodyPanel.h" #include "../ComponentsPanel/BoxColliderPanel.h" #include "../ComponentsPanel/CapsuleColliderPanel.h" #include "../ComponentsPanel/CylinderColliderPanel.h" #include "../ComponentsPanel/SphereColliderPanel.h" #include "../ComponentsPanel/MeshColliderPanel.h" #include "../ComponentsPanel/CharacterControllerPanel.h" -#include "../ComponentsPanel/SpritePanel.h" -#include "../ComponentsPanel/ParticleEmitterPanel.h" -#include "../ComponentsPanel/SkinnedModelPanel.h" #include "../ComponentsPanel/BonePanel.h" -#include "../ComponentsPanel/AudioEmitterPanel.h" #include "../ComponentsPanel/NetScriptPanel.h" #include "../ComponentsPanel/NavMeshVolumePanel.h" -#include "../ComponentsPanel/UIPanel.h" #include #include @@ -46,22 +39,14 @@ private: ScriptPanel mScriptPanel; NetScriptPanel mNetScriptPanel; MeshPanel mMeshPanel; - SkinnedModelPanel mSkinnedModelPanel; - QuakeMapPanel mQuakeMapPanel; CameraPanel mCameraPanel; - RigidbodyPanel mRigidbodyPanel; BoxColliderPanel mBoxColliderPanel; - SphereColliderPanel mSphereColliderPanel; MeshColliderPanel mMeshColliderPanel; CapsuleColliderPanel mCapsuleColliderPanel; CylinderColliderPanel mCylinderColliderPanel; - SpritePanel mSpritePanel; CharacterControllerPanel mCharacterControllerPanel; - ParticleEmitterPanel mParticleEmitterPanel; BonePanel mBonePanel; - AudioEmitterPanel mAudioEmitterPanel; NavMeshVolumePanel mNavMeshVolumePanel; - UIPanel mUiPanel; Ref currentFile; Ref selectedResource; From b23d418f237ac1300e2420ed307269600c8842cb Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Sun, 15 Sep 2024 23:14:23 +0100 Subject: [PATCH 24/29] Compile issues fixed --- Editor/src/ComponentsPanel/NavMeshVolumePanel.h | 4 +++- Editor/src/Misc/GizmoDrawer.cpp | 2 +- Editor/src/Windows/EditorSelectionPanel.cpp | 1 + Editor/src/Windows/EditorSelectionPanel.h | 1 - 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Editor/src/ComponentsPanel/NavMeshVolumePanel.h b/Editor/src/ComponentsPanel/NavMeshVolumePanel.h index 9fe7fae7..b6c8e878 100644 --- a/Editor/src/ComponentsPanel/NavMeshVolumePanel.h +++ b/Editor/src/ComponentsPanel/NavMeshVolumePanel.h @@ -3,6 +3,8 @@ #include #include +#include "src/AI/NavManager.h" +#include "src/Scene/Components/QuakeMap.h" #include #include @@ -384,4 +386,4 @@ public: } EndComponentTable(); } -}; \ No newline at end of file +}; diff --git a/Editor/src/Misc/GizmoDrawer.cpp b/Editor/src/Misc/GizmoDrawer.cpp index e8aaadea..8571bdd1 100644 --- a/Editor/src/Misc/GizmoDrawer.cpp +++ b/Editor/src/Misc/GizmoDrawer.cpp @@ -8,6 +8,7 @@ #include #include #include +#include "src/Scene/Components/RigidbodyComponent.h" #include #include @@ -26,7 +27,6 @@ #include #include - GizmoDrawer::GizmoDrawer(EditorInterface* editor) { m_LineShader = Nuake::ShaderManager::GetShader("Resources/Shaders/line.shader"); diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 0e66433d..c4f35310 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -4,6 +4,7 @@ #include "../Misc/ImGuiTextHelper.h" #include #include "src/Scene/Components/FieldTypes.h" +#include "../ComponentsPanel/MaterialEditor.h" #include #include diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 8788ff56..3594f801 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -13,7 +13,6 @@ #include "../ComponentsPanel/BoxColliderPanel.h" #include "../ComponentsPanel/CapsuleColliderPanel.h" #include "../ComponentsPanel/CylinderColliderPanel.h" -#include "../ComponentsPanel/SphereColliderPanel.h" #include "../ComponentsPanel/MeshColliderPanel.h" #include "../ComponentsPanel/CharacterControllerPanel.h" #include "../ComponentsPanel/BonePanel.h" From 52776186d3f88b3a9716fab754fb35763da7cdde Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Mon, 16 Sep 2024 00:17:28 +0100 Subject: [PATCH 25/29] Added the ability to remove components --- Editor/src/Windows/EditorSelectionPanel.cpp | 5 +- Editor/src/Windows/EditorSelectionPanel.h | 2 +- Nuake/src/Core/Object/Object.h | 183 ++++++++++---------- Nuake/src/Scene/Entities/Entity.h | 26 +++ 4 files changed, 125 insertions(+), 91 deletions(-) diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index c4f35310..be5abe21 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -548,7 +548,7 @@ void EditorSelectionPanel::DrawNetScriptPanel(Ref file) ImGui::PopTextWrapPos(); } -void EditorSelectionPanel::DrawComponent(const Nuake::Entity& entity, entt::meta_any& component) +void EditorSelectionPanel::DrawComponent(Nuake::Entity& entity, entt::meta_any& component) { ZoneScoped; @@ -571,7 +571,8 @@ void EditorSelectionPanel::DrawComponent(const Nuake::Entity& entity, entt::meta if(removed) { - // entity.RemoveComponent(); + auto componentType = component.type(); + entity.RemoveComponent(componentType); ImGui::PopStyleVar(); delete boldFont; } diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 3594f801..6d8ba30a 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -75,7 +75,7 @@ private: void DrawWrenScriptPanel(Ref wrenFile); void DrawNetScriptPanel(Ref file); - void DrawComponent(const Nuake::Entity& entity, entt::meta_any& component); + void DrawComponent(Nuake::Entity& entity, entt::meta_any& component); void DrawComponentContent(entt::meta_any& component); void DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component); diff --git a/Nuake/src/Core/Object/Object.h b/Nuake/src/Core/Object/Object.h index 2cad7125..a135717a 100644 --- a/Nuake/src/Core/Object/Object.h +++ b/Nuake/src/Core/Object/Object.h @@ -22,6 +22,7 @@ namespace Nuake { NK_HASHED_STATIC_STR(GetComponentName) NK_HASHED_STATIC_STR(AddToEntity) + NK_HASHED_STATIC_STR(RemoveFromEntity) NK_HASHED_STATIC_STR(ActionName) }; @@ -75,92 +76,98 @@ namespace Nuake #define NUAKECOMPONENT(klass, componentName) \ public: \ - static std::string ClassName() \ - { \ - static std::string className = #klass; \ - return className; \ - } \ - \ - static std::string ComponentName() \ - { \ - static std::string name = componentName; \ - return name; \ - } \ - \ - static void AddToEntity(entt::entity entity, entt::registry* enttRegistry) \ - { \ - enttRegistry->emplace_or_replace(entity); \ - } \ - \ - \ - static void (*GetInitializeComponentClass())() \ - { \ - return &klass::InitializeComponentClass; \ - } \ - \ - inline static auto ComponentFactory = entt::meta(); \ - static void InternalInitializeClass() \ - { \ - static bool initialized = false; \ - if (initialized) \ - return; \ - \ - ComponentFactory.type(entt::hashed_string(#klass)) \ - .traits(ComponentTypeTrait::InspectorExposed); \ - ComponentFactory.func<&klass::ComponentName>(HashedFnName::GetComponentName); \ - ComponentFactory.func<&klass::AddToEntity>(HashedFnName::AddToEntity); \ - \ - if (klass::GetInitializeComponentClass() != Component::GetInitializeComponentClass()) \ - { \ - GetInitializeComponentClass()(); \ - } \ - \ - initialized = true; \ - \ - } \ - \ - template \ - static auto BindComponentField(const char* varName, const char* displayName) \ - { \ - return ComponentFactory \ - .data(entt::hashed_string(varName)) \ - .prop(HashedName::DisplayName, displayName); \ - } \ - \ - template \ - static auto BindComponentProperty(const char* varName, const char* displayName) \ - { \ - return ComponentFactory \ - .data(entt::hashed_string(varName)) \ - .prop(HashedName::DisplayName, displayName); \ - } \ - \ - static auto FieldFloatLimits(float stepSize, float min, float max) \ - { \ - return ComponentFactory \ - .prop(HashedFieldPropName::FloatStep, stepSize) \ - .prop(HashedFieldPropName::FloatMin, min) \ - .prop(HashedFieldPropName::FloatMax, max); \ - } \ - \ - static auto ResourceFileRestriction(const char* fileType) \ - { \ - return ComponentFactory \ - .prop(HashedFieldPropName::ResourceFileType, fileType); \ - } \ - \ - template \ - static auto SetFlags(Enums... enums) \ - { \ - static_assert((std::is_enum_v && ...), "All arguments must be of enum class type"); \ - return ComponentFactory.traits((enums | ...)); \ - } \ - \ - template \ - static void BindAction(const char* funcName, const char* actionName) \ - { \ - ComponentFactory \ - .func(entt::hashed_string(funcName)) \ - .prop(HashedName::DisplayName, actionName); \ - SetFlags(ComponentFuncTrait::Action); \ + static std::string ClassName() \ + { \ + static std::string className = #klass; \ + return className; \ + } \ + \ + static std::string ComponentName() \ + { \ + static std::string name = componentName; \ + return name; \ + } \ + \ + static void AddToEntity(entt::entity entity, entt::registry* enttRegistry) \ + { \ + enttRegistry->emplace_or_replace(entity); \ + } \ + \ + static void RemoveFromEntity(entt::entity entity, entt::registry* enttRegistry) \ + { \ + enttRegistry->erase(entity); \ + } \ + \ + \ + static void (*GetInitializeComponentClass())() \ + { \ + return &klass::InitializeComponentClass; \ + } \ + \ + inline static auto ComponentFactory = entt::meta(); \ + static void InternalInitializeClass() \ + { \ + static bool initialized = false; \ + if (initialized) \ + return; \ + \ + ComponentFactory.type(entt::hashed_string(#klass)) \ + .traits(ComponentTypeTrait::InspectorExposed); \ + ComponentFactory.func<&klass::ComponentName>(HashedFnName::GetComponentName); \ + ComponentFactory.func<&klass::AddToEntity>(HashedFnName::AddToEntity); \ + ComponentFactory.func<&klass::RemoveFromEntity>(HashedFnName::RemoveFromEntity); \ + \ + if (klass::GetInitializeComponentClass() != Component::GetInitializeComponentClass()) \ + { \ + GetInitializeComponentClass()(); \ + } \ + \ + initialized = true; \ + \ + } \ + \ + template \ + static auto BindComponentField(const char* varName, const char* displayName) \ + { \ + return ComponentFactory \ + .data(entt::hashed_string(varName)) \ + .prop(HashedName::DisplayName, displayName); \ + } \ + \ + template \ + static auto BindComponentProperty(const char* varName, const char* displayName) \ + { \ + return ComponentFactory \ + .data(entt::hashed_string(varName)) \ + .prop(HashedName::DisplayName, displayName); \ + } \ + \ + static auto FieldFloatLimits(float stepSize, float min, float max) \ + { \ + return ComponentFactory \ + .prop(HashedFieldPropName::FloatStep, stepSize) \ + .prop(HashedFieldPropName::FloatMin, min) \ + .prop(HashedFieldPropName::FloatMax, max); \ + } \ + \ + static auto ResourceFileRestriction(const char* fileType) \ + { \ + return ComponentFactory \ + .prop(HashedFieldPropName::ResourceFileType, fileType); \ + } \ + \ + template \ + static auto SetFlags(Enums... enums) \ + { \ + static_assert((std::is_enum_v && ...), "All arguments must be of enum class type"); \ + return ComponentFactory.traits((enums | ...)); \ + } \ + \ + template \ + static void BindAction(const char* funcName, const char* actionName) \ + { \ + ComponentFactory \ + .func(entt::hashed_string(funcName)) \ + .prop(HashedName::DisplayName, actionName); \ + SetFlags(ComponentFuncTrait::Action); \ } diff --git a/Nuake/src/Scene/Entities/Entity.h b/Nuake/src/Scene/Entities/Entity.h index b64d3137..aacd59df 100644 --- a/Nuake/src/Scene/Entities/Entity.h +++ b/Nuake/src/Scene/Entities/Entity.h @@ -58,6 +58,32 @@ namespace Nuake func.invoke(newComponent, m_EntityHandle, &m_Scene->m_Registry); } + void RemoveComponent(entt::meta_type& enttMetaType) + { + if (!enttMetaType) + { + Logger::Log("Meta data empty/invalid", "Entity", WARNING); + return; + } + + entt::meta_any newComponent = enttMetaType.construct(); + if (!newComponent) + { + Logger::Log("Could not create a component from the meta type", "Entity", CRITICAL); + return; + } + + auto func = enttMetaType.func(HashedFnName::RemoveFromEntity); + // TODO: [WiggleWizard] Needs a lot more validation + if (!func) + { + Logger::Log("No such function exists or is registered on component", "Entity", CRITICAL); + return; + } + + func.invoke(newComponent, m_EntityHandle, &m_Scene->m_Registry); + } + template T& AddComponent() { From bb43bbe1b8ebdbf09f780ae51ec4bda7ff8e262a Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Mon, 16 Sep 2024 10:05:55 +0100 Subject: [PATCH 26/29] Fixed rebuild action for quake map component --- Nuake/src/Scene/Components/QuakeMap.h | 3 +++ Nuake/src/Scene/Scene.cpp | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Nuake/src/Scene/Components/QuakeMap.h b/Nuake/src/Scene/Components/QuakeMap.h index f99c4d3b..fd3bb888 100644 --- a/Nuake/src/Scene/Components/QuakeMap.h +++ b/Nuake/src/Scene/Components/QuakeMap.h @@ -35,6 +35,8 @@ namespace Nuake { bool AutoRebuild = false; float ScaleFactor = 1.f; + bool rebuildNextTick = false; + std::vector> m_Meshes; std::vector m_Brushes; std::vector m_SerializedBrushIDs; @@ -98,5 +100,6 @@ namespace Nuake { inline void QuakeMapComponent::ActionRebuild() { + rebuildNextTick = true; } } diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index f7b73998..cfa9c338 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -273,17 +273,29 @@ namespace Nuake for (const auto& e : view) { auto& map = view.get(e); + + bool buildMap = false; + if (map.rebuildNextTick && map.Path.Exist()) + { + buildMap = true; + map.rebuildNextTick = false; + } + if (map.AutoRebuild && map.Path.Exist()) { if (auto file = FileSystem::GetFile(map.Path.GetRelativePath()); file->Exist() && file->GetHasBeenModified()) { file->SetHasBeenModified(false); - - Entity entity = Entity(e, this); - QuakeMapBuilder builder; - builder.BuildQuakeMap(entity, map.HasCollisions); + buildMap = true; } } + + if (buildMap) + { + Entity entity = Entity(e, this); + QuakeMapBuilder builder; + builder.BuildQuakeMap(entity, map.HasCollisions); + } } } From d338a98c9b525fbf1a0f58003678856657f754e2 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Mon, 16 Sep 2024 10:18:32 +0100 Subject: [PATCH 27/29] Removed Wren script references in the UI --- Editor/src/ComponentsPanel/ScriptPanel.cpp | 115 -------------------- Editor/src/ComponentsPanel/ScriptPanel.h | 43 -------- Editor/src/Windows/EditorSelectionPanel.cpp | 1 - Editor/src/Windows/EditorSelectionPanel.h | 2 - Editor/src/Windows/FileSystemUI.cpp | 30 ----- 5 files changed, 191 deletions(-) delete mode 100644 Editor/src/ComponentsPanel/ScriptPanel.cpp delete mode 100644 Editor/src/ComponentsPanel/ScriptPanel.h diff --git a/Editor/src/ComponentsPanel/ScriptPanel.cpp b/Editor/src/ComponentsPanel/ScriptPanel.cpp deleted file mode 100644 index e712f7e7..00000000 --- a/Editor/src/ComponentsPanel/ScriptPanel.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "ScriptPanel.h" -#include "../Windows/FileSystemUI.h" -#include -#include "src/FileSystem/FileDialog.h" -#include "src/FileSystem/FileSystem.h" - -void ScriptPanel::Draw(Nuake::Entity entity) -{ - if (!entity.HasComponent()) - return; - - Nuake::WrenScriptComponent& component = entity.GetComponent(); - BeginComponentTable(SCRIPT, Nuake::WrenScriptComponent); - { - { - ImGui::Text("Script"); - ImGui::TableNextColumn(); - - std::string path = component.Script; - ImGui::Button( path.empty() ? "Create New" : component.Script.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script")) - { - char* file = (char*)payload->Data; - - std::string fullPath = std::string(file, 512); - path = Nuake::FileSystem::AbsoluteToRelative(std::move(fullPath)); - - component.LoadScript(path); - } - ImGui::EndDragDropTarget(); - } - - component.Script = path; - - // Double click on file - if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) - { - if(!component.Script.empty()) - { - if (component.mWrenScript) - { - Nuake::OS::OpenIn(component.mWrenScript->GetFile()->GetAbsolutePath()); - } - } - else - { - // TODO: Turn into command (Undo/Redo) - - std::string pathCreation = Nuake::FileDialog::SaveFile("*.wren"); - - if (!pathCreation.empty()) - { - if (!Nuake::String::EndsWith(pathCreation, ".wren")) - { - pathCreation += ".wren"; - } - - std::string fileName = Nuake::String::ToUpper(Nuake::FileSystem::GetFileNameFromPath(pathCreation)); - fileName = Nuake::String::RemoveWhiteSpace(fileName); - - if(!Nuake::String::IsDigit(fileName[0])) - { - Nuake::FileSystem::BeginWriteFile(pathCreation); - Nuake::FileSystem::WriteLine(TEMPLATE_SCRIPT_FIRST + fileName + TEMPLATE_SCRIPT_SECOND); - Nuake::FileSystem::EndWriteFile(); - - path = Nuake::FileSystem::AbsoluteToRelative(pathCreation); - Nuake::FileSystem::Scan(); - Nuake::FileSystemUI::m_CurrentDirectory = Nuake::FileSystem::RootDirectory; - component.LoadScript(path); - component.Script = path; - } - else - { - Nuake::Logger::Log("Cannot create script files that starts with a number.","fileSystem", Nuake::CRITICAL); - } - } - - } - } - - ImGui::TableNextColumn(); - - ComponentTableReset(component.Script, ""); - } - ImGui::TableNextColumn(); - { - ImGui::Text("Module"); - ImGui::TableNextColumn(); - - // Here we create a dropdown for every modules - auto& wrenScript = component.mWrenScript; - if (wrenScript) - { - auto modules = wrenScript->GetModules(); - - std::vector modulesC; - - for (auto& m : modules) - { - modulesC.push_back(m.c_str()); - } - static int currentModule = (int)component.mModule; - ImGui::Combo("##WrenModule", ¤tModule, &modulesC[0], modules.size()); - component.mModule = currentModule; - } - - ImGui::TableNextColumn(); - //ComponentTableReset(component.Class, ""); - } - } - EndComponentTable(); -} \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/ScriptPanel.h b/Editor/src/ComponentsPanel/ScriptPanel.h deleted file mode 100644 index dac4c0c2..00000000 --- a/Editor/src/ComponentsPanel/ScriptPanel.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include "ComponentPanel.h" - - -const std::string TEMPLATE_SCRIPT_FIRST = R"(import "Nuake:Engine" for Engine -import "Nuake:ScriptableEntity" for ScriptableEntity -import "Nuake:Input" for Input -import "Nuake:Math" for Vector3, Math -import "Nuake:Scene" for Scene - -class )"; - -const std::string TEMPLATE_SCRIPT_SECOND = R"( is ScriptableEntity { - construct new() { - } - - // Called when the scene gets initialized - init() { - // Engine.Log("Hello World!") - } - - // Called every update - update(ts) { - } - - // Called 90 times per second - fixedUpdate(ts) { - } - - // Called on shutdown - exit() { - } -} -)"; - - -class ScriptPanel : ComponentPanel { - -public: - ScriptPanel() {} - - void Draw(Nuake::Entity entity) override; -}; \ No newline at end of file diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index be5abe21..9e060ca4 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -161,7 +161,6 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) // Draw each component properties panels. mLightPanel.Draw(entity); - mScriptPanel.Draw(entity); mNetScriptPanel.Draw(entity); // mAudioEmitterPanel.Draw(entity); // mParticleEmitterPanel.Draw(entity); diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 6d8ba30a..448f7f93 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -7,7 +7,6 @@ #include "../ComponentsPanel/TransformPanel.h" #include "../ComponentsPanel/LightPanel.h" -#include "../ComponentsPanel/ScriptPanel.h" #include "../ComponentsPanel/MeshPanel.h" #include "../ComponentsPanel/CameraPanel.h" #include "../ComponentsPanel/BoxColliderPanel.h" @@ -35,7 +34,6 @@ class EditorSelectionPanel private: TransformPanel mTransformPanel; LightPanel mLightPanel; - ScriptPanel mScriptPanel; NetScriptPanel mNetScriptPanel; MeshPanel mMeshPanel; CameraPanel mCameraPanel; diff --git a/Editor/src/Windows/FileSystemUI.cpp b/Editor/src/Windows/FileSystemUI.cpp index 7304be65..4c52eb43 100644 --- a/Editor/src/Windows/FileSystemUI.cpp +++ b/Editor/src/Windows/FileSystemUI.cpp @@ -657,36 +657,6 @@ namespace Nuake } } - if (ImGui::MenuItem("Wren Script")) - { - std::string path = FileDialog::SaveFile("*.wren"); - - if (!String::EndsWith(path, ".wren")) - { - path += ".wren"; - } - - if (!path.empty()) - { - std::string fileName = String::ToUpper(FileSystem::GetFileNameFromPath(path)); - fileName = String::RemoveWhiteSpace(fileName); - - if(!String::IsDigit(fileName[0])) - { - - FileSystem::BeginWriteFile(path, true); - FileSystem::WriteLine(TEMPLATE_SCRIPT_FIRST + fileName + TEMPLATE_SCRIPT_SECOND); - FileSystem::EndWriteFile(); - - RefreshFileBrowser(); - } - else - { - Logger::Log("Cannot create script files that starts with a number.", "filesystem", CRITICAL); - } - } - } - ImGui::EndMenu(); } From 8b2511f995eb0e42c830f2cc8104628bd5fd8cbf Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Mon, 16 Sep 2024 10:57:22 +0100 Subject: [PATCH 28/29] Better API for binding inspector drawers and added the ability to add whole component drawers --- Editor/src/Windows/EditorSelectionPanel.cpp | 31 +++++++++++++-------- Editor/src/Windows/EditorSelectionPanel.h | 29 ++++++++++++++++--- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 9e060ca4..6c150868 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -4,7 +4,9 @@ #include "../Misc/ImGuiTextHelper.h" #include #include "src/Scene/Components/FieldTypes.h" + #include "../ComponentsPanel/MaterialEditor.h" +#include "../ComponentsPanel/BoxColliderPanel.h" #include #include @@ -19,10 +21,6 @@ #include "Tracy.hpp" - -#define REGISTER_TYPE_DRAWER(forType, fn) \ - FieldTypeDrawers[entt::type_id().hash()] = std::bind(&fn, this, std::placeholders::_1, std::placeholders::_2); - using namespace Nuake; EditorSelectionPanel::EditorSelectionPanel() @@ -31,12 +29,12 @@ EditorSelectionPanel::EditorSelectionPanel() virtualScene->SetName("Virtual Scene"); virtualScene->CreateEntity("Camera").AddComponent(); - REGISTER_TYPE_DRAWER(bool, EditorSelectionPanel::DrawFieldTypeBool); - REGISTER_TYPE_DRAWER(float, EditorSelectionPanel::DrawFieldTypeFloat); - REGISTER_TYPE_DRAWER(Vector3, EditorSelectionPanel::DrawFieldTypeVector3); - REGISTER_TYPE_DRAWER(std::string, EditorSelectionPanel::DrawFieldTypeString); - REGISTER_TYPE_DRAWER(ResourceFile, EditorSelectionPanel::DrawFieldTypeResourceFile); - REGISTER_TYPE_DRAWER(DynamicItemList, EditorSelectionPanel::DrawFieldTypeDynamicItemList); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); } void EditorSelectionPanel::ResolveFile(Ref file) @@ -171,7 +169,7 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) // mQuakeMapPanel.Draw(entity); mCameraPanel.Draw(entity); // mRigidbodyPanel.Draw(entity); - mBoxColliderPanel.Draw(entity); + // mBoxColliderPanel.Draw(entity); // mSphereColliderPanel.Draw(entity); mCapsuleColliderPanel.Draw(entity); mCylinderColliderPanel.Draw(entity); @@ -551,6 +549,17 @@ void EditorSelectionPanel::DrawComponent(Nuake::Entity& entity, entt::meta_any& { ZoneScoped; + // Call into custom component drawer if one is available for this component + + const auto componentIdHash = component.type().info().hash(); + if (ComponentTypeDrawers.contains(componentIdHash)) + { + const auto drawerFn = ComponentTypeDrawers[componentIdHash]; + drawerFn(entity, component); + + return; + } + const entt::meta_type componentMeta = component.type(); const std::string componentName = Component::GetName(componentMeta); diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 448f7f93..387b6603 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -9,7 +9,6 @@ #include "../ComponentsPanel/LightPanel.h" #include "../ComponentsPanel/MeshPanel.h" #include "../ComponentsPanel/CameraPanel.h" -#include "../ComponentsPanel/BoxColliderPanel.h" #include "../ComponentsPanel/CapsuleColliderPanel.h" #include "../ComponentsPanel/CylinderColliderPanel.h" #include "../ComponentsPanel/MeshColliderPanel.h" @@ -29,7 +28,8 @@ namespace Nuake class EditorSelectionPanel { - using DrawFieldTypeFn = std::function; + using DrawComponentTypeFn = std::function; + using DrawFieldTypeFn = std::function; private: TransformPanel mTransformPanel; @@ -37,7 +37,6 @@ private: NetScriptPanel mNetScriptPanel; MeshPanel mMeshPanel; CameraPanel mCameraPanel; - BoxColliderPanel mBoxColliderPanel; MeshColliderPanel mMeshColliderPanel; CapsuleColliderPanel mCapsuleColliderPanel; CylinderColliderPanel mCylinderColliderPanel; @@ -62,8 +61,30 @@ public: void DrawResource(Nuake::Resource resource); void DrawPrefabPanel(Ref prefab); + template + void RegisterComponentDrawer() + { + const auto t = entt::type_id(); + ComponentTypeDrawers[t.hash()] = std::bind(Func, std::placeholders::_1, std::placeholders::_2); + } + + template + void RegisterComponentDrawer(O* o) + { + ComponentTypeDrawers[entt::type_id().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2); + } + + template + void RegisterTypeDrawer(O* o) + { + FieldTypeDrawers[entt::type_id().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2); + } + protected: - // List of functions to call for each type that needs to be drawn + // Drawing functions for each component (for writing very specific inspectors for specific components) + std::unordered_map ComponentTypeDrawers; + + // List of functions to call for each component field type that needs to be drawn std::unordered_map FieldTypeDrawers; private: From d19ba4f9798dd4f899bd3c6d809a583df98ab256 Mon Sep 17 00:00:00 2001 From: WiggleWizard <1405402+WiggleWizard@users.noreply.github.com> Date: Mon, 16 Sep 2024 14:49:25 +0100 Subject: [PATCH 29/29] Converted last components to new component drawing system --- Editor/src/ComponentsPanel/BonePanel.h | 17 +++---- Editor/src/ComponentsPanel/CameraPanel.h | 17 ++++--- .../ComponentsPanel/CapsuleColliderPanel.h | 31 +++++++------ .../CharacterControllerPanel.h | 20 +++++---- Editor/src/ComponentsPanel/ComponentPanel.h | 6 ++- .../ComponentsPanel/CylinderColliderPanel.h | 31 +++++++------ Editor/src/ComponentsPanel/LightPanel.h | 17 +++---- .../src/ComponentsPanel/MeshColliderPanel.h | 18 ++++---- Editor/src/ComponentsPanel/MeshPanel.h | 12 +++-- .../src/ComponentsPanel/NavMeshVolumePanel.h | 17 ++++--- Editor/src/ComponentsPanel/NetScriptPanel.cpp | 45 +++++++++++++++++-- Editor/src/ComponentsPanel/NetScriptPanel.h | 42 ++--------------- Editor/src/Windows/EditorSelectionPanel.cpp | 33 +++++--------- Editor/src/Windows/EditorSelectionPanel.h | 11 +---- 14 files changed, 155 insertions(+), 162 deletions(-) diff --git a/Editor/src/ComponentsPanel/BonePanel.h b/Editor/src/ComponentsPanel/BonePanel.h index dd1e075b..52e1fa6f 100644 --- a/Editor/src/ComponentsPanel/BonePanel.h +++ b/Editor/src/ComponentsPanel/BonePanel.h @@ -6,19 +6,20 @@ #include #include -class BonePanel : ComponentPanel +class BonePanel { public: - BonePanel() {} - - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { using namespace Nuake; - - if (!entity.HasComponent()) + + Nuake::BoneComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) + { return; - - auto& component = entity.GetComponent(); + } + Nuake::BoneComponent& component = *componentPtr; + BeginComponentTable(BONE, BoneComponent); { { diff --git a/Editor/src/ComponentsPanel/CameraPanel.h b/Editor/src/ComponentsPanel/CameraPanel.h index e162b40d..34b99fa4 100644 --- a/Editor/src/ComponentsPanel/CameraPanel.h +++ b/Editor/src/ComponentsPanel/CameraPanel.h @@ -3,17 +3,20 @@ #include #include "src/FileSystem/FileSystem.h" -class CameraPanel : ComponentPanel { +class CameraPanel { public: - CameraPanel() {} - - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { - if (!entity.HasComponent()) + using namespace Nuake; + + Nuake::CameraComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) + { return; - - auto& component = entity.GetComponent(); + } + Nuake::CameraComponent& component = *componentPtr; + BeginComponentTable(CAMERA, Nuake::CameraComponent); { { diff --git a/Editor/src/ComponentsPanel/CapsuleColliderPanel.h b/Editor/src/ComponentsPanel/CapsuleColliderPanel.h index 6ca7dce6..f6a4f294 100644 --- a/Editor/src/ComponentsPanel/CapsuleColliderPanel.h +++ b/Editor/src/ComponentsPanel/CapsuleColliderPanel.h @@ -3,48 +3,47 @@ #include -class CapsuleColliderPanel : ComponentPanel +class CapsuleColliderPanel { public: - CapsuleColliderPanel() = default; - - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { using namespace Nuake; - - if (!entity.HasComponent()) + + Nuake::CapsuleColliderComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) { return; } - - auto& [Capsule, Radius, Height, IsTrigger] = entity.GetComponent(); + Nuake::CapsuleColliderComponent& component = *componentPtr; + BeginComponentTable(CAPSULE COLLIDER, CapsuleColliderComponent) { { ImGui::Text("Radius"); ImGui::TableNextColumn(); - ImGui::DragFloat("##Radius", &Radius, 0.01f, 0.001f); - Radius = std::max(Radius, 0.001f); + ImGui::DragFloat("##Radius", &component.Radius, 0.01f, 0.001f); + component.Radius = std::max(component.Radius, 0.001f); ImGui::TableNextColumn(); - ComponentTableReset(Radius, 0.5f) + ComponentTableReset(component.Radius, 0.5f) } ImGui::TableNextColumn(); { ImGui::Text("Height"); ImGui::TableNextColumn(); - ImGui::DragFloat("##Height", &Height, 0.01f, 0.001f); - Height = std::max(Height, 0.001f); + ImGui::DragFloat("##Height", &component.Height, 0.01f, 0.001f); + component.Height = std::max(component.Height, 0.001f); ImGui::TableNextColumn(); - ComponentTableReset(Height, 1.0f) + ComponentTableReset(component.Height, 1.0f) } ImGui::TableNextColumn(); { ImGui::Text("Is Trigger"); ImGui::TableNextColumn(); - ImGui::Checkbox("##isTrigger", &IsTrigger); + ImGui::Checkbox("##isTrigger", &component.IsTrigger); ImGui::TableNextColumn(); - ComponentTableReset(IsTrigger, false); + ComponentTableReset(component.IsTrigger, false); } } EndComponentTable() diff --git a/Editor/src/ComponentsPanel/CharacterControllerPanel.h b/Editor/src/ComponentsPanel/CharacterControllerPanel.h index 6e7a1a8c..8d720286 100644 --- a/Editor/src/ComponentsPanel/CharacterControllerPanel.h +++ b/Editor/src/ComponentsPanel/CharacterControllerPanel.h @@ -3,18 +3,20 @@ #include #include "src/FileSystem/FileSystem.h" -class CharacterControllerPanel : ComponentPanel { - +class CharacterControllerPanel +{ public: - CharacterControllerPanel() {} - - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { - if (!entity.HasComponent()) - return; using namespace Nuake; - - auto& component = entity.GetComponent(); + + Nuake::CharacterControllerComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) + { + return; + } + Nuake::CharacterControllerComponent& component = *componentPtr; + BeginComponentTable(CHARACTER CONTROLLER, Nuake::CharacterControllerComponent); { { diff --git a/Editor/src/ComponentsPanel/ComponentPanel.h b/Editor/src/ComponentsPanel/ComponentPanel.h index 0ed64a4d..f3969f36 100644 --- a/Editor/src/ComponentsPanel/ComponentPanel.h +++ b/Editor/src/ComponentsPanel/ComponentPanel.h @@ -93,5 +93,7 @@ ImGui::Text(##name); class ComponentPanel { public: - virtual void Draw(Nuake::Entity entity) = 0; -}; \ No newline at end of file + virtual void Draw(Nuake::Entity entity); +}; + +inline void ComponentPanel::Draw(Nuake::Entity entity) {} diff --git a/Editor/src/ComponentsPanel/CylinderColliderPanel.h b/Editor/src/ComponentsPanel/CylinderColliderPanel.h index a3cfd1fb..aa49729b 100644 --- a/Editor/src/ComponentsPanel/CylinderColliderPanel.h +++ b/Editor/src/ComponentsPanel/CylinderColliderPanel.h @@ -3,48 +3,47 @@ #include -class CylinderColliderPanel : ComponentPanel +class CylinderColliderPanel { public: - CylinderColliderPanel() = default; - - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { using namespace Nuake; - - if (!entity.HasComponent()) + + Nuake::CylinderColliderComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) { return; } - - auto& [Cylinder, Radius, Height, IsTrigger] = entity.GetComponent(); + Nuake::CylinderColliderComponent& component = *componentPtr; + BeginComponentTable(CYLINDER COLLIDER, CylinderColliderComponent) { { ImGui::Text("Radius"); ImGui::TableNextColumn(); - ImGui::DragFloat("##Radius", &Radius, 0.01f, 0.001f); - Radius = std::max(Radius, 0.001f); + ImGui::DragFloat("##Radius", &component.Radius, 0.01f, 0.001f); + component.Radius = std::max(component.Radius, 0.001f); ImGui::TableNextColumn(); - ComponentTableReset(Radius, 0.5f) + ComponentTableReset(component.Radius, 0.5f) } ImGui::TableNextColumn(); { ImGui::Text("Height"); ImGui::TableNextColumn(); - ImGui::DragFloat("##Height", &Height, 0.01f, 0.0001f); - Height = std::max(Height, 0.001f); + ImGui::DragFloat("##Height", &component.Height, 0.01f, 0.0001f); + component.Height = std::max(component.Height, 0.001f); ImGui::TableNextColumn(); - ComponentTableReset(Height, 1.0f) + ComponentTableReset(component.Height, 1.0f) } ImGui::TableNextColumn(); { ImGui::Text("Is Trigger"); ImGui::TableNextColumn(); - ImGui::Checkbox("##isTrigger", &IsTrigger); + ImGui::Checkbox("##isTrigger", &component.IsTrigger); ImGui::TableNextColumn(); - ComponentTableReset(IsTrigger, false); + ComponentTableReset(component.IsTrigger, false); } } EndComponentTable() diff --git a/Editor/src/ComponentsPanel/LightPanel.h b/Editor/src/ComponentsPanel/LightPanel.h index 794ccece..07204b6f 100644 --- a/Editor/src/ComponentsPanel/LightPanel.h +++ b/Editor/src/ComponentsPanel/LightPanel.h @@ -2,17 +2,18 @@ #include "ComponentPanel.h" #include "src/Scene/Components/LightComponent.h" -class LightPanel :ComponentPanel { - +class LightPanel +{ public: - LightPanel() { } - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { - if (!entity.HasComponent()) - return; - - Nuake::LightComponent& component = entity.GetComponent(); + Nuake::LightComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) + { + return; + } + Nuake::LightComponent& component = *componentPtr; BeginComponentTable(LIGHT, Nuake::LightComponent); { diff --git a/Editor/src/ComponentsPanel/MeshColliderPanel.h b/Editor/src/ComponentsPanel/MeshColliderPanel.h index bfbe5012..ef77abc6 100644 --- a/Editor/src/ComponentsPanel/MeshColliderPanel.h +++ b/Editor/src/ComponentsPanel/MeshColliderPanel.h @@ -9,23 +9,25 @@ #include #include -class MeshColliderPanel : ComponentPanel { -private: - Scope _modelInspector; - bool _expanded = false; +class MeshColliderPanel : ComponentPanel +{ public: MeshColliderPanel() { CreateScope(); } - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { using namespace Nuake; - if (!entity.HasComponent()) + + Nuake::MeshColliderComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) + { return; - - MeshColliderComponent& component = entity.GetComponent(); + } + Nuake::MeshColliderComponent& component = *componentPtr; + BeginComponentTable(MESH, MeshColliderComponent); { ImGui::Text("Model"); diff --git a/Editor/src/ComponentsPanel/MeshPanel.h b/Editor/src/ComponentsPanel/MeshPanel.h index a38639f3..15770266 100644 --- a/Editor/src/ComponentsPanel/MeshPanel.h +++ b/Editor/src/ComponentsPanel/MeshPanel.h @@ -26,13 +26,17 @@ public: CreateScope(); } - void Draw(Nuake::Entity entity) override + void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { using namespace Nuake; - if (!entity.HasComponent()) + + Nuake::ModelComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) + { return; - - ModelComponent& component = entity.GetComponent(); + } + Nuake::ModelComponent& component = *componentPtr; + BeginComponentTable(MESH, ModelComponent); { ImGui::Text("Model"); diff --git a/Editor/src/ComponentsPanel/NavMeshVolumePanel.h b/Editor/src/ComponentsPanel/NavMeshVolumePanel.h index b6c8e878..1994864d 100644 --- a/Editor/src/ComponentsPanel/NavMeshVolumePanel.h +++ b/Editor/src/ComponentsPanel/NavMeshVolumePanel.h @@ -8,21 +8,20 @@ #include #include -class NavMeshVolumePanel : ComponentPanel { - +class NavMeshVolumePanel +{ public: - NavMeshVolumePanel() {} - - void Draw(Nuake::Entity entity) override + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) { using namespace Nuake; - - if (!entity.HasComponent()) + + Nuake::NavMeshVolumeComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) { return; } - - auto& component = entity.GetComponent(); + Nuake::NavMeshVolumeComponent& component = *componentPtr; + BeginComponentTable(NAVMESH VOLUME, NavMeshVolumeComponent); { { diff --git a/Editor/src/ComponentsPanel/NetScriptPanel.cpp b/Editor/src/ComponentsPanel/NetScriptPanel.cpp index ed046e0c..488200f2 100644 --- a/Editor/src/ComponentsPanel/NetScriptPanel.cpp +++ b/Editor/src/ComponentsPanel/NetScriptPanel.cpp @@ -8,13 +8,50 @@ #include #include +const std::string NET_TEMPLATE_SCRIPT_FIRST = R"(using Nuake.Net; -void NetScriptPanel::Draw(Nuake::Entity entity) +namespace NuakeShowcase { - if (!entity.HasComponent()) - return; + class )"; - auto& component = entity.GetComponent(); +const std::string NET_TEMPLATE_SCRIPT_SECOND = R"( : Entity + { + public override void OnInit() + { + // Called once at the start of the game + } + + + public override void OnUpdate(float dt) + { + // Called every frame + } + + public override void OnFixedUpdate(float dt) + { + // Called every fixed update + } + + + public override void OnDestroy() + { + // Called at the end of the game fixed update + } + } +} +)"; + +void NetScriptPanel::Draw(Nuake::Entity& entity, entt::meta_any& componentInstance) +{ + using namespace Nuake; + + Nuake::NetScriptComponent* componentPtr = componentInstance.try_cast(); + if (componentPtr == nullptr) + { + return; + } + Nuake::NetScriptComponent& component = *componentPtr; + BeginComponentTable(.NETSCRIPT, Nuake::NetScriptComponent); { { diff --git a/Editor/src/ComponentsPanel/NetScriptPanel.h b/Editor/src/ComponentsPanel/NetScriptPanel.h index 83bd725c..8cd6d7b3 100644 --- a/Editor/src/ComponentsPanel/NetScriptPanel.h +++ b/Editor/src/ComponentsPanel/NetScriptPanel.h @@ -1,45 +1,9 @@ #pragma once + #include "ComponentPanel.h" - -const std::string NET_TEMPLATE_SCRIPT_FIRST = R"(using Nuake.Net; - -namespace NuakeShowcase +class NetScriptPanel { - class )"; - -const std::string NET_TEMPLATE_SCRIPT_SECOND = R"( : Entity - { - public override void OnInit() - { - // Called once at the start of the game - } - - - public override void OnUpdate(float dt) - { - // Called every frame - } - - public override void OnFixedUpdate(float dt) - { - // Called every fixed update - } - - - public override void OnDestroy() - { - // Called at the end of the game fixed update - } - } -} -)"; - - -class NetScriptPanel : ComponentPanel { - public: - NetScriptPanel() {} - - void Draw(Nuake::Entity entity) override; + static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance); }; \ No newline at end of file diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 6c150868..e704bb3e 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -28,6 +28,17 @@ EditorSelectionPanel::EditorSelectionPanel() virtualScene = CreateRef(); virtualScene->SetName("Virtual Scene"); virtualScene->CreateEntity("Camera").AddComponent(); + + RegisterComponentDrawer(); + RegisterComponentDrawer(&meshPanel); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); RegisterTypeDrawer(this); RegisterTypeDrawer(this); @@ -156,28 +167,6 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) } } - - // Draw each component properties panels. - mLightPanel.Draw(entity); - mNetScriptPanel.Draw(entity); - // mAudioEmitterPanel.Draw(entity); - // mParticleEmitterPanel.Draw(entity); - // mSpritePanel.Draw(entity); - mMeshPanel.Draw(entity); - // mSkinnedModelPanel.Draw(entity); - mBonePanel.Draw(entity); - // mQuakeMapPanel.Draw(entity); - mCameraPanel.Draw(entity); - // mRigidbodyPanel.Draw(entity); - // mBoxColliderPanel.Draw(entity); - // mSphereColliderPanel.Draw(entity); - mCapsuleColliderPanel.Draw(entity); - mCylinderColliderPanel.Draw(entity); - mMeshColliderPanel.Draw(entity); - mCharacterControllerPanel.Draw(entity); - mNavMeshVolumePanel.Draw(entity); - // mUiPanel.Draw(entity); - using namespace Nuake; float availWidth = ImGui::GetContentRegionAvail().x; diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 387b6603..6903db8e 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -33,16 +33,7 @@ class EditorSelectionPanel private: TransformPanel mTransformPanel; - LightPanel mLightPanel; - NetScriptPanel mNetScriptPanel; - MeshPanel mMeshPanel; - CameraPanel mCameraPanel; - MeshColliderPanel mMeshColliderPanel; - CapsuleColliderPanel mCapsuleColliderPanel; - CylinderColliderPanel mCylinderColliderPanel; - CharacterControllerPanel mCharacterControllerPanel; - BonePanel mBonePanel; - NavMeshVolumePanel mNavMeshVolumePanel; + MeshPanel meshPanel; Ref currentFile; Ref selectedResource;