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", }