From 54c195dae05d4247336ea7c1949cd9cd8add92f1 Mon Sep 17 00:00:00 2001 From: Light Date: Sun, 1 Aug 2021 16:55:26 +0430 Subject: [PATCH] PropertiesPanel - Added PropertiesPanel --- Dependencies/entt/entt.hpp | 45181 +++----------------- Engine/src/Engine/Scene/Entity.h | 12 +- Mirror/default_gui_layout.ini | 2 +- Mirror/src/MirrorLayer.h | 13 +- Mirror/src/Panels/PropertiesPanel.cpp | 54 + Mirror/src/Panels/PropertiesPanel.h | 23 + Mirror/src/Panels/SceneHierarchyPanel.cpp | 45 +- Mirror/src/Panels/SceneHierarchyPanel.h | 11 +- 8 files changed, 7122 insertions(+), 38219 deletions(-) create mode 100644 Mirror/src/Panels/PropertiesPanel.cpp create mode 100644 Mirror/src/Panels/PropertiesPanel.h diff --git a/Dependencies/entt/entt.hpp b/Dependencies/entt/entt.hpp index 80a7790..1024b5d 100644 --- a/Dependencies/entt/entt.hpp +++ b/Dependencies/entt/entt.hpp @@ -1,15 +1,3 @@ -// #include "config/version.h" -#ifndef ENTT_CONFIG_VERSION_H -#define ENTT_CONFIG_VERSION_H - - -#define ENTT_VERSION_MAJOR 3 -#define ENTT_VERSION_MINOR 8 -#define ENTT_VERSION_PATCH 0 - - -#endif - // #include "core/algorithm.hpp" #ifndef ENTT_CORE_ALGORITHM_HPP #define ENTT_CORE_ALGORITHM_HPP @@ -31,24 +19,18 @@ #define ENTT_CONFIG_CONFIG_H -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) +#ifndef ENTT_NOEXCEPT # define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) #endif -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws #endif @@ -66,47 +48,37 @@ #endif -#ifdef ENTT_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 #endif -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT +#ifndef ENTT_ASSERT # include -# define ENTT_ASSERT(condition, ...) assert(condition) +# define ENTT_ASSERT(condition) assert(condition) #endif -#ifdef ENTT_NO_ETO +#ifndef ENTT_NO_ETO # include -# define ENTT_IGNORE_IF_EMPTY std::false_type +# define ENTT_IS_EMPTY(Type) std::is_empty_v #else # include -# define ENTT_IGNORE_IF_EMPTY std::true_type +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) #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 '>' +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ # endif #endif @@ -127,7 +99,7 @@ namespace entt { * @return The submitted value as-is. */ template - [[nodiscard]] constexpr Type&& operator()(Type&& value) const ENTT_NOEXCEPT { + constexpr Type&& operator()(Type&& value) const ENTT_NOEXCEPT { return std::forward(value); } }; @@ -141,7 +113,7 @@ namespace entt { * @return Pointer to the member. */ template - [[nodiscard]] constexpr auto overload(Type Class::* member) ENTT_NOEXCEPT { return member; } + constexpr auto overload(Type Class::* member) ENTT_NOEXCEPT { return member; } /** @@ -151,7 +123,7 @@ namespace entt { * @return Pointer to the function. */ template - [[nodiscard]] constexpr auto overload(Func* func) ENTT_NOEXCEPT { return func; } + constexpr auto overload(Func* func) ENTT_NOEXCEPT { return func; } /** @@ -169,8 +141,7 @@ namespace entt { * @tparam Func Types of function objects. */ template - overloaded(Func...) - ->overloaded; + overloaded(Func...)->overloaded; /** @@ -286,7 +257,7 @@ namespace entt { */ 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"); + static_assert((N% Bit) == 0); /** * @brief Sorts the elements in a range. @@ -317,17 +288,17 @@ namespace entt { std::size_t index[buckets]{}; std::size_t count[buckets]{}; - for (auto it = from; it != to; ++it) { - ++count[(getter(*it) >> start) & mask]; - } + std::for_each(from, to, [&getter, &count, start](const value_type& item) { + ++count[(getter(item) >> start) & mask]; + }); - for (std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { - index[pos + 1u] = index[pos] + count[pos]; - } + std::for_each(std::next(std::begin(index)), std::end(index), [index = std::begin(index), count = std::begin(count)](auto& item) mutable { + item = *(index++) + *(count++); + }); - for (auto it = from; it != to; ++it) { - out[index[(getter(*it) >> start) & mask]++] = std::move(*it); - } + std::for_each(from, to, [&getter, &out, &index, start](value_type& item) { + out[index[(getter(item) >> start) & mask]++] = std::move(item); + }); }; for (std::size_t pass = 0; pass < (passes & ~1); pass += 2) { @@ -347,1961 +318,6 @@ namespace entt { } -#endif - -// #include "core/any.hpp" -#ifndef ENTT_CORE_ANY_HPP -#define ENTT_CORE_ANY_HPP - - -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 - -// #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 -// #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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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 : std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE }; - enum class policy : std::uint8_t { OWNER, REF, CREF }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void* (const operation, const basic_any&, 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 constexpr policy type_to_policy() { - if constexpr (std::is_lvalue_reference_v) { - if constexpr (std::is_const_v>) { - return policy::CREF; - } - else { - return policy::REF; - } - } - else { - return policy::OWNER; - } - } - - 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 const void* basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any& from, [[maybe_unused]] void* to) { - static_assert(std::is_same_v>, Type>, "Invalid type"); - - if constexpr (!std::is_void_v) { - const Type* instance = (in_situ && from.mode == policy::OWNER) - ? ENTT_LAUNDER(reinterpret_cast(&from.storage)) - : static_cast(from.instance); - - switch (op) { - case operation::COPY: - if constexpr (std::is_copy_constructible_v) { - static_cast(to)->emplace(*instance); - } - break; - case operation::MOVE: - if constexpr (in_situ) { - if (from.mode == policy::OWNER) { - return new (&static_cast(to)->storage) Type{ std::move(*const_cast(instance)) }; - } - } - - return (static_cast(to)->instance = std::exchange(const_cast(from).instance, nullptr)); - case operation::DTOR: - if (from.mode == policy::OWNER) { - if constexpr (in_situ) { - instance->~Type(); - } - else if constexpr (std::is_array_v) { - delete[] instance; - } - else { - delete instance; - } - } - break; - case operation::COMP: - return compare(instance, (*static_cast(to))->data()) ? to : nullptr; - case operation::ADDR: - if (from.mode == policy::CREF) { - return nullptr; - } - [[fallthrough]]; - case operation::CADDR: - return instance; - case operation::TYPE: - *static_cast(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 (sizeof...(Args) != 0u && std::is_aggregate_v) { - new (&storage) Type{ std::forward(args)... }; - } - else { - new (&storage) Type(std::forward(args)...); - } - } - else { - if constexpr (sizeof...(Args) != 0u && std::is_aggregate_v) { - instance = new Type{ std::forward(args)... }; - } - else { - instance = new Type(std::forward(args)...); - } - } - } - } - - basic_any(const basic_any& other, const policy pol) ENTT_NOEXCEPT - : instance{ other.data() }, - vtable{ other.vtable }, - mode{ pol } - {} - - public: - /*! @brief Size of the internal storage. */ - static constexpr auto length = Len; - /*! @brief Alignment requirement. */ - static constexpr auto alignment = Align; - - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - {} - - /** - * @brief Constructs a wrapper 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>> }, - mode{ type_to_policy() } - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs a wrapper 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{} - { - // invokes deprecated assignment operator (and avoids issues with vs2017) - *this = value; - } - - /** - * @brief Constructs a wrapper 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) - : instance{}, - vtable{ &basic_vtable> }, - mode{ policy::OWNER } - { - initialize>(std::forward(value)); - } - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any& other) - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any&& other) ENTT_NOEXCEPT - : instance{}, - vtable{ other.vtable }, - mode{ other.mode } - { - 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) { - reset(); - 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) ENTT_NOEXCEPT { - std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - mode = other.mode; - 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 - [[deprecated("Use std::in_place_type, entt::make_any, emplace or forward_as_any instead")]] - 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); - mode = type_to_policy(); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - mode = policy::OWNER; - } - - /** - * @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 { - const basic_any* trampoline = &other; - return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data()); - } - - /** - * @brief Aliasing constructor. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - return basic_any{ *this, (mode == policy::CREF ? policy::CREF : policy::REF) }; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - return basic_any{ *this, policy::CREF }; - } - - /** - * @brief Returns true if a wrapper owns its object, false otherwise. - * @return True if the wrapper owns its object, false otherwise. - */ - [[nodiscard]] bool owner() const ENTT_NOEXCEPT { - return (mode == policy::OWNER); - } - - private: - union { const void* instance; storage_type storage; }; - vtable_type* vtable; - policy mode; - }; - - - /** - * @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, "Invalid 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, "Invalid 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, "Invalid 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); - } - - - /** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - * @return A properly initialized wrapper for an object of the given type. - */ - template::length, std::size_t Align = basic_any::alignment, typename... Args> - basic_any make_any(Args &&... args) { - return basic_any{std::in_place_type, std::forward(args)...}; - } - - - /** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ - template::length, std::size_t Align = basic_any::alignment, typename Type> - basic_any forward_as_any(Type&& value) { - return basic_any{std::in_place_type, std::decay_t, Type>>, std::forward(value)}; - } - - -} - - #endif // #include "core/attribute.h" @@ -2347,6 +363,25 @@ namespace entt { // #include "../config/config.h" // #include "fwd.hpp" +#ifndef ENTT_CORE_FWD_HPP +#define ENTT_CORE_FWD_HPP + + +// #include "../config/config.h" + + + +namespace entt { + + + /*! @brief Alias declaration for type identifiers. */ + using id_type = ENTT_ID_TYPE; + + +} + + +#endif @@ -2430,7 +465,7 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ @@ -2456,7 +491,7 @@ namespace entt { }; // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { + static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { auto value = traits_type::offset; while (*curr != 0) { @@ -2472,18 +507,6 @@ namespace entt { /*! @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. * @@ -2500,7 +523,7 @@ namespace entt { * @return The numeric representation of the string. */ template - [[nodiscard]] static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { + static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { return helper(str); } @@ -2509,10 +532,22 @@ namespace entt { * @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 { + static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { return helper(wrapper.str); } + /** + * @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. + */ + static 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 Constructs an empty hashed string. */ constexpr basic_hashed_string() ENTT_NOEXCEPT : str{ nullptr }, hash{} @@ -2550,7 +585,7 @@ namespace entt { * @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 { + constexpr const value_type* data() const ENTT_NOEXCEPT { return str; } @@ -2558,25 +593,25 @@ namespace entt { * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the instance. */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { + constexpr hash_type value() const ENTT_NOEXCEPT { return hash; } /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type* () const ENTT_NOEXCEPT { return data(); } + 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(); } + 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 { + constexpr bool operator==(const basic_hashed_string& other) const ENTT_NOEXCEPT { return hash == other.hash; } @@ -2597,7 +632,7 @@ namespace entt { * @param str Human-readable identifer. */ template - basic_hashed_string(const Char(&str)[N]) + basic_hashed_string(const Char(&str)[N]) ENTT_NOEXCEPT ->basic_hashed_string; @@ -2609,7 +644,7 @@ namespace entt { * @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 { + constexpr bool operator!=(const basic_hashed_string& lhs, const basic_hashed_string& rhs) ENTT_NOEXCEPT { return !(lhs == rhs); } @@ -2622,32 +657,26 @@ namespace entt { 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 }; - } - - - } +/** + * @brief User defined literal for hashed strings. + * @param str The literal without its suffix. + * @return A properly initialized hashed string. + */ +constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(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. + */ +constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t* str, std::size_t) ENTT_NOEXCEPT { + return entt::hashed_wstring{ str }; } @@ -2658,6 +687,7 @@ namespace entt { #define ENTT_CORE_IDENT_HPP +#include #include #include #include @@ -2665,8 +695,6 @@ namespace entt { // #include "fwd.hpp" -// #include "type_traits.hpp" - namespace entt { @@ -2701,10 +729,12 @@ namespace entt { */ 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{})); + using tuple_type = std::tuple...>; + + template + static constexpr id_type get(std::index_sequence) { + static_assert(std::disjunction_v...>); + return (0 + ... + (std::is_same_v> ? id_type(Indexes) : id_type{})); } public: @@ -2793,11 +823,42 @@ namespace entt { #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" @@ -2817,239 +878,86 @@ namespace entt { namespace internal { - struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { + struct ENTT_API type_index { + 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 + * @endcond TURN_OFF_DOXYGEN */ /** - * @brief Type sequential identifier. + * @brief Type index. * @tparam Type Type for which to generate a sequential identifier. */ template - struct ENTT_API type_seq final { + struct ENTT_API type_index { /** * @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(); + static id_type value() ENTT_NOEXCEPT { + static const id_type value = internal::type_index::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. + * @brief Provides the member constant `value` to true if a given type is + * indexable, false otherwise. + * @tparam Type Potentially indexable type. + */ + template + struct has_type_index : std::false_type {}; + + + /*! @brief has_type_index */ + template + struct has_type_index::value())>> : std::true_type {}; + + + /** + * @brief Helper variable template. + * @tparam Type Potentially indexable type. + */ + template + inline constexpr bool has_type_index_v = has_type_index::value; + + + /** + * @brief Type info. + * @tparam Type Type for which to generate information. */ template - struct type_hash final { + struct ENTT_API type_info { /** * @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); + static ENTT_PRETTY_FUNCTION_CONSTEXPR() id_type id() ENTT_NOEXCEPT { + ENTT_PRETTY_FUNCTION_CONSTEXPR(static const) auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION); + return value; + } #else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); + static id_type id() ENTT_NOEXCEPT { + return type_index::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 @@ -3060,11 +968,12 @@ namespace entt { #include -#include -#include #include +#include // #include "../config/config.h" +// #include "hashed_string.hpp" + // #include "fwd.hpp" @@ -3072,6 +981,22 @@ namespace entt { namespace entt { + /** + * @brief Wraps a static constant. + * @tparam Value A static constant. + */ + template + using integral_constant = std::integral_constant; + + + /** + * @brief Alias template to ease the creation of named values. + * @tparam Value A constant value at least convertible to `id_type`. + */ + template + using tag = integral_constant; + + /** * @brief Utility class to disambiguate overloaded functions. * @tparam N Number of choices available. @@ -3081,7 +1006,7 @@ namespace entt { // Unfortunately, doxygen cannot parse such a construct. /*! @cond TURN_OFF_DOXYGEN */ : choice_t - /*! @endcond */ + /*! @endcond TURN_OFF_DOXYGEN */ {}; @@ -3098,146 +1023,32 @@ namespace entt { 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 A class to use to push around lists of types, nothing more. */ + template + struct type_list {}; + + + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_size; /** - * @brief Helper type. - * @tparam Type A type. + * @brief Compile-time number of elements in a type list. + * @tparam Type Types provided by the type list. */ - 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 + template + struct type_list_size> + : std::integral_constant {}; /** * @brief Helper variable template. - * @tparam Type The type of which to return the size. + * @tparam List Type list. */ - template - inline constexpr std::size_t 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 {}; } + template + inline constexpr auto type_list_size_v = type_list_size::value; /*! @brief Primary template isn't defined on purpose. */ @@ -3323,396 +1134,25 @@ namespace entt { /** - * @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. + * @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 type_list_contains; + template> + struct is_equality_comparable : std::false_type {}; - /** - * @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...> {}; + /*! @copydoc is_equality_comparable */ + template + struct is_equality_comparable() == std::declval())>> : std::true_type {}; /** * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ - template - inline constexpr bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. + * @tparam Type Potentially equality comparable type. */ template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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; + inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; /** @@ -3721,7 +1161,7 @@ namespace entt { */ template class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); + static_assert(std::is_member_pointer_v); template static Class* clazz(Ret(Class::*)(Args...)); @@ -3749,146 +1189,48 @@ namespace entt { } +/** + * @brief Defines an enum class to use for opaque identifiers and a dedicate + * `to_integer` function to convert the identifiers to their underlying type. + * @param clazz The name to use for the enum class. + * @param type The underlying type for the enum class. + */ +#define ENTT_OPAQUE_TYPE(clazz, type)\ + enum class clazz: type {};\ + constexpr auto to_integral(const clazz id) ENTT_NOEXCEPT {\ + return static_cast>(id);\ + }\ + static_assert(true) + + #endif -// #include "core/utility.hpp" -#ifndef ENTT_CORE_UTILITY_HPP -#define ENTT_CORE_UTILITY_HPP + // #include "core/utility.hpp" + + // #include "entity/actor.hpp" +#ifndef ENTT_ENTITY_ACTOR_HPP +#define ENTT_ENTITY_ACTOR_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/component.hpp" -#ifndef ENTT_ENTITY_COMPONENT_HPP -#define ENTT_ENTITY_COMPONENT_HPP - - #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) +#ifndef ENTT_NOEXCEPT # define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) #endif -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws #endif @@ -3906,1798 +1248,56 @@ namespace entt { #endif -#ifdef ENTT_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 #endif -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT +#ifndef ENTT_ASSERT # include -# define ENTT_ASSERT(condition, ...) assert(condition) +# define ENTT_ASSERT(condition) assert(condition) #endif -#ifdef ENTT_NO_ETO +#ifndef ENTT_NO_ETO # include -# define ENTT_IGNORE_IF_EMPTY std::false_type +# define ENTT_IS_EMPTY(Type) std::is_empty_v #else # include -# define ENTT_IGNORE_IF_EMPTY std::true_type +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) #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 '>' +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ # endif #endif #endif +// #include "registry.hpp" +#ifndef ENTT_ENTITY_REGISTRY_HPP +#define ENTT_ENTITY_REGISTRY_HPP -namespace entt { - - - /*! @brief Commonly used default traits for all types. */ - struct basic_component_traits { - /*! @brief Pointer stability, default is `std::false_type`. */ - using in_place_delete = std::false_type; - /*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */ - using ignore_if_empty = ENTT_IGNORE_IF_EMPTY; - }; - - - /** - * @brief Common way to access various properties of components. - * @tparam Type Type of component. - */ - template - struct component_traits : basic_component_traits { - static_assert(std::is_same_v, Type>, "Unsupported type"); - }; - - -} - - -#endif - -// #include "entity/entity.hpp" -#ifndef ENTT_ENTITY_ENTITY_HPP -#define ENTT_ENTITY_ENTITY_HPP - - +#include #include -#include -#include -// #include "../config/config.h" - - - -namespace entt { - - - /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - - namespace internal { - - - template - struct entt_traits; - - - template - struct entt_traits>> - : entt_traits> - {}; - - - template - struct entt_traits>> - : entt_traits - {}; - - - template<> - struct entt_traits { - using entity_type = std::uint32_t; - using version_type = std::uint16_t; - using difference_type = std::int64_t; - - static constexpr entity_type entity_mask = 0xFFFFF; - static constexpr entity_type version_mask = 0xFFF; - static constexpr std::size_t entity_shift = 20u; - }; - - - template<> - struct entt_traits { - using entity_type = std::uint64_t; - using version_type = std::uint32_t; - using difference_type = std::int64_t; - - static constexpr entity_type entity_mask = 0xFFFFFFFF; - static constexpr entity_type version_mask = 0xFFFFFFFF; - static constexpr std::size_t entity_shift = 32u; - }; - - - } - - - /** - * Internal details not to be documented. - * @endcond - */ - - - /** - * @brief Entity traits. - * @tparam Type Type of identifier. - */ - template - class entt_traits : private internal::entt_traits { - using traits_type = internal::entt_traits; - - public: - /*! @brief Value type. */ - using value_type = Type; - /*! @brief Underlying entity type. */ - using entity_type = typename traits_type::entity_type; - /*! @brief Underlying version type. */ - using version_type = typename traits_type::version_type; - /*! @brief Difference type. */ - using difference_type = typename traits_type::difference_type; - - /** - * @brief Converts an entity to its underlying type. - * @param value The value to convert. - * @return The integral representation of the given value. - */ - [[nodiscard]] static constexpr entity_type to_integral(const value_type value) ENTT_NOEXCEPT { - return static_cast(value); - } - - /** - * @brief Returns the entity part once converted to the underlying type. - * @param value The value to convert. - * @return The integral representation of the entity part. - */ - [[nodiscard]] static constexpr entity_type to_entity(const value_type value) ENTT_NOEXCEPT { - return (to_integral(value) & traits_type::entity_mask); - } - - /** - * @brief Returns the version part once converted to the underlying type. - * @param value The value to convert. - * @return The integral representation of the version part. - */ - [[nodiscard]] static constexpr version_type to_version(const value_type value) ENTT_NOEXCEPT { - constexpr auto mask = (traits_type::version_mask << traits_type::entity_shift); - return ((to_integral(value) & mask) >> traits_type::entity_shift); - } - - /** - * @brief Constructs an identifier from its parts. - * - * If the version part is not provided, a tombstone is returned.
- * If the entity part is not provided, a null identifier is returned. - * - * @param entity The entity part of the identifier. - * @param version The version part of the identifier. - * @return A properly constructed identifier. - */ - [[nodiscard]] static constexpr value_type construct(const entity_type entity = traits_type::entity_mask, const version_type version = traits_type::version_mask) ENTT_NOEXCEPT { - return value_type{ (entity & traits_type::entity_mask) | (version << traits_type::entity_shift) }; - } - }; - - - /** - * @brief Converts an entity 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 entt_traits::to_integral(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 type. - */ - template - [[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT { - return entt_traits::construct(); - } - - /** - * @brief Compares two null objects. - * @param other A null object. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT { - return true; - } - - /** - * @brief Compares two null objects. - * @param other A null object. - * @return False in all cases. - */ - [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) 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 entt_traits::to_entity(entity) == entt_traits::to_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. - * @return True if the two elements differ, false otherwise. - */ - template - [[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT { - return !(entity == *this); - } - - /** - * @brief Creates a null object from an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier to turn into a null object. - * @return The null representation for the given identifier. - */ - template - [[nodiscard]] constexpr Entity operator|(const Entity entity) const ENTT_NOEXCEPT { - return entt_traits::construct(entt_traits::to_entity(*this), entt_traits::to_version(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 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); - } - - - /*! @brief Tombstone object for all entity identifiers. */ - struct tombstone_t { - /** - * @brief Converts the tombstone object to identifiers of any type. - * @tparam Entity Type of entity identifier. - * @return The tombstone representation for the given type. - */ - template - [[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT { - return entt_traits::construct(); - } - - /** - * @brief Compares two tombstone objects. - * @param other A tombstone object. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT { - return true; - } - - /** - * @brief Compares two tombstone objects. - * @param other A tombstone object. - * @return False in all cases. - */ - [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT { - return false; - } - - /** - * @brief Compares a tombstone 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 entt_traits::to_version(entity) == entt_traits::to_version(*this); - } - - /** - * @brief Compares a tombstone 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 Creates a tombstone object from an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier to turn into a tombstone object. - * @return The tombstone representation for the given identifier. - */ - template - [[nodiscard]] constexpr Entity operator|(const Entity entity) const ENTT_NOEXCEPT { - return entt_traits::construct(entt_traits::to_entity(entity)); - } - }; - - - /** - * @brief Compares a tombstone 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 tombstone object yet to be converted. - * @return False if the two elements differ, true otherwise. - */ - template - [[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT { - return other.operator==(entity); - } - - - /** - * @brief Compares a tombstone 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 tombstone object yet to be converted. - * @return True if the two elements differ, false otherwise. - */ - template - [[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT { - return !(other == entity); - } - - - /** - * @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{}; - - - /** - * @brief Compile-time constant for tombstone entities. - * - * There exist implicit conversions from this variable to entity identifiers of - * any allowed type. Similarly, there exist comparision operators between the - * tombstone entity and any other entity identifier. - */ - inline constexpr tombstone_t tombstone{}; - - -} - - -#endif - -// #include "entity/group.hpp" -#ifndef ENTT_ENTITY_GROUP_HPP -#define ENTT_ENTITY_GROUP_HPP - - +#include +#include #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 -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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 { - - - /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - - namespace internal { - - - template - struct entt_traits; - - - template - struct entt_traits>> - : entt_traits> - {}; - - - template - struct entt_traits>> - : entt_traits - {}; - - - template<> - struct entt_traits { - using entity_type = std::uint32_t; - using version_type = std::uint16_t; - using difference_type = std::int64_t; - - static constexpr entity_type entity_mask = 0xFFFFF; - static constexpr entity_type version_mask = 0xFFF; - static constexpr std::size_t entity_shift = 20u; - }; - - - template<> - struct entt_traits { - using entity_type = std::uint64_t; - using version_type = std::uint32_t; - using difference_type = std::int64_t; - - static constexpr entity_type entity_mask = 0xFFFFFFFF; - static constexpr entity_type version_mask = 0xFFFFFFFF; - static constexpr std::size_t entity_shift = 32u; - }; - - - } - - - /** - * Internal details not to be documented. - * @endcond - */ - - - /** - * @brief Entity traits. - * @tparam Type Type of identifier. - */ - template - class entt_traits : private internal::entt_traits { - using traits_type = internal::entt_traits; - - public: - /*! @brief Value type. */ - using value_type = Type; - /*! @brief Underlying entity type. */ - using entity_type = typename traits_type::entity_type; - /*! @brief Underlying version type. */ - using version_type = typename traits_type::version_type; - /*! @brief Difference type. */ - using difference_type = typename traits_type::difference_type; - - /** - * @brief Converts an entity to its underlying type. - * @param value The value to convert. - * @return The integral representation of the given value. - */ - [[nodiscard]] static constexpr entity_type to_integral(const value_type value) ENTT_NOEXCEPT { - return static_cast(value); - } - - /** - * @brief Returns the entity part once converted to the underlying type. - * @param value The value to convert. - * @return The integral representation of the entity part. - */ - [[nodiscard]] static constexpr entity_type to_entity(const value_type value) ENTT_NOEXCEPT { - return (to_integral(value) & traits_type::entity_mask); - } - - /** - * @brief Returns the version part once converted to the underlying type. - * @param value The value to convert. - * @return The integral representation of the version part. - */ - [[nodiscard]] static constexpr version_type to_version(const value_type value) ENTT_NOEXCEPT { - constexpr auto mask = (traits_type::version_mask << traits_type::entity_shift); - return ((to_integral(value) & mask) >> traits_type::entity_shift); - } - - /** - * @brief Constructs an identifier from its parts. - * - * If the version part is not provided, a tombstone is returned.
- * If the entity part is not provided, a null identifier is returned. - * - * @param entity The entity part of the identifier. - * @param version The version part of the identifier. - * @return A properly constructed identifier. - */ - [[nodiscard]] static constexpr value_type construct(const entity_type entity = traits_type::entity_mask, const version_type version = traits_type::version_mask) ENTT_NOEXCEPT { - return value_type{ (entity & traits_type::entity_mask) | (version << traits_type::entity_shift) }; - } - }; - - - /** - * @brief Converts an entity 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 entt_traits::to_integral(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 type. - */ - template - [[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT { - return entt_traits::construct(); - } - - /** - * @brief Compares two null objects. - * @param other A null object. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT { - return true; - } - - /** - * @brief Compares two null objects. - * @param other A null object. - * @return False in all cases. - */ - [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) 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 entt_traits::to_entity(entity) == entt_traits::to_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. - * @return True if the two elements differ, false otherwise. - */ - template - [[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT { - return !(entity == *this); - } - - /** - * @brief Creates a null object from an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier to turn into a null object. - * @return The null representation for the given identifier. - */ - template - [[nodiscard]] constexpr Entity operator|(const Entity entity) const ENTT_NOEXCEPT { - return entt_traits::construct(entt_traits::to_entity(*this), entt_traits::to_version(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 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); - } - - - /*! @brief Tombstone object for all entity identifiers. */ - struct tombstone_t { - /** - * @brief Converts the tombstone object to identifiers of any type. - * @tparam Entity Type of entity identifier. - * @return The tombstone representation for the given type. - */ - template - [[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT { - return entt_traits::construct(); - } - - /** - * @brief Compares two tombstone objects. - * @param other A tombstone object. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT { - return true; - } - - /** - * @brief Compares two tombstone objects. - * @param other A tombstone object. - * @return False in all cases. - */ - [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT { - return false; - } - - /** - * @brief Compares a tombstone 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 entt_traits::to_version(entity) == entt_traits::to_version(*this); - } - - /** - * @brief Compares a tombstone 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 Creates a tombstone object from an entity identifier of any type. - * @tparam Entity Type of entity identifier. - * @param entity Entity identifier to turn into a tombstone object. - * @return The tombstone representation for the given identifier. - */ - template - [[nodiscard]] constexpr Entity operator|(const Entity entity) const ENTT_NOEXCEPT { - return entt_traits::construct(entt_traits::to_entity(entity)); - } - }; - - - /** - * @brief Compares a tombstone 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 tombstone object yet to be converted. - * @return False if the two elements differ, true otherwise. - */ - template - [[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT { - return other.operator==(entity); - } - - - /** - * @brief Compares a tombstone 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 tombstone object yet to be converted. - * @return True if the two elements differ, false otherwise. - */ - template - [[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT { - return !(other == entity); - } - - - /** - * @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{}; - - - /** - * @brief Compile-time constant for tombstone entities. - * - * There exist implicit conversions from this variable to entity identifiers of - * any allowed type. Similarly, there exist comparision operators between the - * tombstone entity and any other entity identifier. - */ - inline constexpr tombstone_t tombstone{}; - - -} - - -#endif - -// #include "fwd.hpp" -#ifndef ENTT_ENTITY_FWD_HPP -#define ENTT_ENTITY_FWD_HPP - - -#include -// #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> - struct basic_storage; - - - template - class basic_registry; - - - template - struct 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" @@ -5717,6 +1317,75 @@ namespace entt { #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_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws +#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 + + +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 +#endif + + +#ifndef ENTT_ASSERT +# include +# define ENTT_ASSERT(condition) assert(condition) +#endif + + +#ifndef ENTT_NO_ETO +# include +# define ENTT_IS_EMPTY(Type) std::is_empty_v +#else +# include +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) +#endif + + +#ifndef ENTT_STANDARD_CPP +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ +# endif +#endif + + +#endif @@ -5732,7 +1401,7 @@ namespace entt { * @return The submitted value as-is. */ template - [[nodiscard]] constexpr Type&& operator()(Type&& value) const ENTT_NOEXCEPT { + constexpr Type&& operator()(Type&& value) const ENTT_NOEXCEPT { return std::forward(value); } }; @@ -5746,7 +1415,7 @@ namespace entt { * @return Pointer to the member. */ template - [[nodiscard]] constexpr auto overload(Type Class::* member) ENTT_NOEXCEPT { return member; } + constexpr auto overload(Type Class::* member) ENTT_NOEXCEPT { return member; } /** @@ -5756,7 +1425,7 @@ namespace entt { * @return Pointer to the function. */ template - [[nodiscard]] constexpr auto overload(Func* func) ENTT_NOEXCEPT { return func; } + constexpr auto overload(Func* func) ENTT_NOEXCEPT { return func; } /** @@ -5774,8 +1443,7 @@ namespace entt { * @tparam Func Types of function objects. */ template - overloaded(Func...) - ->overloaded; + overloaded(Func...)->overloaded; /** @@ -5891,7 +1559,7 @@ namespace entt { */ 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"); + static_assert((N% Bit) == 0); /** * @brief Sorts the elements in a range. @@ -5922,17 +1590,17 @@ namespace entt { std::size_t index[buckets]{}; std::size_t count[buckets]{}; - for (auto it = from; it != to; ++it) { - ++count[(getter(*it) >> start) & mask]; - } + std::for_each(from, to, [&getter, &count, start](const value_type& item) { + ++count[(getter(item) >> start) & mask]; + }); - for (std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { - index[pos + 1u] = index[pos] + count[pos]; - } + std::for_each(std::next(std::begin(index)), std::end(index), [index = std::begin(index), count = std::begin(count)](auto& item) mutable { + item = *(index++) + *(count++); + }); - for (auto it = from; it != to; ++it) { - out[index[(getter(*it) >> start) & mask]++] = std::move(*it); - } + std::for_each(from, to, [&getter, &out, &index, start](value_type& item) { + out[index[(getter(item) >> start) & mask]++] = std::move(item); + }); }; for (std::size_t pass = 0; pass < (passes & ~1); pass += 2) { @@ -5955,1098 +1623,10 @@ namespace entt { #endif // #include "../core/fwd.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - - /*! @brief Sparse set deletion policy. */ - enum class deletion_policy : std::uint8_t { - /*! @brief Swap-and-pop deletion policy. */ - swap_and_pop = 0u, - /*! @brief In-place deletion policy. */ - in_place = 1u - }; - - - /** - * @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). - * @tparam Allocator Type of allocator used to manage memory and elements. - */ - template - class basic_sparse_set { - static constexpr auto growth_factor = 1.5; - static constexpr auto sparse_page = ENTT_SPARSE_PAGE; - - using traits_type = entt_traits; - - using alloc_traits = typename std::allocator_traits::template rebind_traits; - using alloc_pointer = typename alloc_traits::pointer; - using alloc_const_pointer = typename alloc_traits::const_pointer; - - using bucket_alloc_traits = typename std::allocator_traits::template rebind_traits; - using bucket_alloc_pointer = typename bucket_alloc_traits::pointer; - - static_assert(alloc_traits::propagate_on_container_move_assignment::value); - static_assert(bucket_alloc_traits::propagate_on_container_move_assignment::value); - - struct sparse_set_iterator final { - using difference_type = typename traits_type::difference_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(const alloc_const_pointer* ref, const difference_type idx) ENTT_NOEXCEPT - : packed{ ref }, - index{ idx } - {} - - 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 std::addressof((*packed)[pos]); - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - const alloc_const_pointer* packed; - difference_type index; - }; - - [[nodiscard]] static auto page(const Entity entt) ENTT_NOEXCEPT { - return size_type{ traits_type::to_entity(entt) / sparse_page }; - } - - [[nodiscard]] static auto offset(const Entity entt) ENTT_NOEXCEPT { - return size_type{ traits_type::to_entity(entt) & (sparse_page - 1) }; - } - - [[nodiscard]] auto assure_page(const std::size_t idx) { - if (!(idx < bucket)) { - const size_type sz = idx + 1u; - const auto mem = bucket_alloc_traits::allocate(bucket_allocator, sz); - - std::uninitialized_value_construct(mem + bucket, mem + sz); - std::uninitialized_copy(sparse, sparse + bucket, mem); - - std::destroy(sparse, sparse + bucket); - bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket); - - sparse = mem; - bucket = sz; - } - - if (!sparse[idx]) { - sparse[idx] = alloc_traits::allocate(allocator, sparse_page); - std::uninitialized_fill(sparse[idx], sparse[idx] + sparse_page, null); - } - - return sparse[idx]; - } - - void resize_packed(const std::size_t req) { - ENTT_ASSERT((req != reserved) && !(req < count), "Invalid request"); - const auto mem = alloc_traits::allocate(allocator, req); - - std::uninitialized_copy(packed, packed + count, mem); - std::uninitialized_fill(mem + count, mem + req, tombstone); - - std::destroy(packed, packed + reserved); - alloc_traits::deallocate(allocator, packed, reserved); - - packed = mem; - reserved = req; - } - - void release_memory() { - if (packed) { - for (size_type pos{}; pos < bucket; ++pos) { - if (sparse[pos]) { - std::destroy(sparse[pos], sparse[pos] + sparse_page); - alloc_traits::deallocate(allocator, sparse[pos], sparse_page); - } - } - - std::destroy(packed, packed + reserved); - std::destroy(sparse, sparse + bucket); - alloc_traits::deallocate(allocator, packed, reserved); - bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket); - } - } - - protected: - /** - * @brief Swaps two entities in the internal packed array. - * @param lhs A valid position of an entity within storage. - * @param rhs A valid position of an entity within storage. - */ - virtual void swap_at([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {} - - /** - * @brief Moves an entity in the internal packed array. - * @param from A valid position of an entity within storage. - * @param to A valid position of an entity within storage. - */ - virtual void move_and_pop([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) {} - - /** - * @brief Attempts to erase an entity from the internal packed array. - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - virtual void swap_and_pop(const Entity entt, [[maybe_unused]] void* ud) { - auto& ref = sparse[page(entt)][offset(entt)]; - const auto pos = size_type{ traits_type::to_entity(ref) }; - ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier"); - auto& last = packed[--count]; - - packed[pos] = last; - sparse[page(last)][offset(last)] = ref; - // lazy self-assignment guard - ref = null; - // unnecessary but it helps to detect nasty bugs - ENTT_ASSERT((last = tombstone, true), ""); - } - - /** - * @brief Attempts to erase an entity from the internal packed array. - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - virtual void in_place_pop(const Entity entt, [[maybe_unused]] void* ud) { - auto& ref = sparse[page(entt)][offset(entt)]; - const auto pos = size_type{ traits_type::to_entity(ref) }; - ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier"); - - packed[pos] = std::exchange(free_list, traits_type::construct(static_cast(pos))); - // lazy self-assignment guard - ref = null; - } - - public: - /*! @brief Allocator type. */ - using allocator_type = typename alloc_traits::allocator_type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Pointer type to contained entities. */ - using pointer = alloc_const_pointer; - /*! @brief Random access iterator type. */ - using iterator = sparse_set_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = std::reverse_iterator; - - /** - * @brief Constructs an empty container with the given policy and allocator. - * @param pol Type of deletion policy. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(deletion_policy pol, const allocator_type& alloc = {}) - : allocator{ alloc }, - bucket_allocator{ alloc }, - sparse{ bucket_alloc_traits::allocate(bucket_allocator, 0u) }, - packed{ alloc_traits::allocate(allocator, 0u) }, - bucket{ 0u }, - count{ 0u }, - reserved{ 0u }, - free_list{ tombstone }, - mode{ pol } - {} - - /** - * @brief Constructs an empty container with the given allocator. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(const allocator_type& alloc = {}) - : basic_sparse_set{ deletion_policy::swap_and_pop, alloc } - {} - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_sparse_set(basic_sparse_set&& other) ENTT_NOEXCEPT - : allocator{ std::move(other.allocator) }, - bucket_allocator{ std::move(other.bucket_allocator) }, - sparse{ std::exchange(other.sparse, bucket_alloc_pointer{}) }, - packed{ std::exchange(other.packed, alloc_pointer{}) }, - bucket{ std::exchange(other.bucket, 0u) }, - count{ std::exchange(other.count, 0u) }, - reserved{ std::exchange(other.reserved, 0u) }, - free_list{ std::exchange(other.free_list, tombstone) }, - mode{ other.mode } - {} - - /*! @brief Default destructor. */ - virtual ~basic_sparse_set() { - release_memory(); - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This sparse set. - */ - basic_sparse_set& operator=(basic_sparse_set&& other) ENTT_NOEXCEPT { - release_memory(); - - allocator = std::move(other.allocator); - bucket_allocator = std::move(other.bucket_allocator); - sparse = std::exchange(other.sparse, bucket_alloc_pointer{}); - packed = std::exchange(other.packed, alloc_pointer{}); - bucket = std::exchange(other.bucket, 0u); - count = std::exchange(other.count, 0u); - reserved = std::exchange(other.reserved, 0u); - free_list = std::exchange(other.free_list, tombstone); - mode = other.mode; - - return *this; - } - - /** - * @brief Returns the deletion policy of a sparse set. - * @return The deletion policy of the sparse set. - */ - [[nodiscard]] deletion_policy policy() const ENTT_NOEXCEPT { - return mode; - } - - /** - * @brief Returns the next slot available for insertion. - * @return The next slot available for insertion. - */ - [[nodiscard]] size_type slot() const ENTT_NOEXCEPT { - return free_list == null ? count : size_type{ traits_type::to_entity(free_list) }; - } - - /** - * @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) { - if (cap > reserved) { - resize_packed(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 reserved; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - if (count < reserved) { - resize_packed(count); - } - } - - /** - * @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 bucket * sparse_page; - } - - /** - * @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 count; - } - - /** - * @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 (count == size_type{}); - } - - /** - * @brief Direct access to the internal packed array. - * @return A pointer to the internal packed array. - */ - [[nodiscard]] pointer data() const ENTT_NOEXCEPT { - return packed; - } - - /** - * @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 { - return iterator{ std::addressof(packed), static_cast(count) }; - } - - /** - * @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{ std::addressof(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 std::make_reverse_iterator(end()); - } - - /** - * @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 std::make_reverse_iterator(begin()); - } - - /** - * @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 ENTT_NOEXCEPT { - 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 ENTT_NOEXCEPT { - ENTT_ASSERT(entt != tombstone && entt != null, "Invalid entity"); - const auto curr = page(entt); - // testing versions permits to avoid accessing the packed array - return (curr < bucket&& 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_NOEXCEPT { - ENTT_ASSERT(contains(entt), "Set does not contain entity"); - return size_type{ traits_type::to_entity(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 ENTT_NOEXCEPT { - return pos < count ? 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_NOEXCEPT { - ENTT_ASSERT(pos < count, "Position is out of bounds"); - return packed[pos]; - } - - /** - * @brief Appends 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. - * @return The slot used for insertion. - */ - size_type emplace_back(const entity_type entt) { - ENTT_ASSERT(!contains(entt), "Set already contains entity"); - - if (count == reserved) { - const size_type sz = static_cast(reserved * growth_factor); - resize_packed(sz + !(sz > reserved)); - } - - assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast(count)); - packed[count] = entt; - return count++; - } - - /** - * @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. - * @return The slot used for insertion. - */ - size_type emplace(const entity_type entt) { - if (free_list == null) { - return emplace_back(entt); - } - else { - ENTT_ASSERT(!contains(entt), "Set already contains entity"); - const auto pos = size_type{ traits_type::to_entity(free_list) }; - sparse[page(entt)][offset(entt)] = traits_type::construct(static_cast(pos)); - free_list = std::exchange(packed[pos], entt); - return pos; - } - } - - /** - * @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) { - reserve(count + std::distance(first, last)); - - for (; first != last; ++first) { - const auto entt = *first; - ENTT_ASSERT(!contains(entt), "Set already contains entity"); - assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast(count)); - packed[count++] = entt; - } - } - - /** - * @brief Erases an entity from a sparse set. - * - * @warning - * Attempting to erase 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 erase(const entity_type entt, void* ud = nullptr) { - ENTT_ASSERT(contains(entt), "Set does not contain entity"); - (mode == deletion_policy::in_place) ? in_place_pop(entt, ud) : swap_and_pop(entt, ud); - } - - /** - * @brief Erases entities from a set. - * - * @sa erase - * - * @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 erase(It first, It last, void* ud = nullptr) { - for (; first != last; ++first) { - erase(*first, ud); - } - } - - /** - * @brief Removes an entity from a sparse set if it exists. - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - * @return True if the entity is actually removed, false otherwise. - */ - bool remove(const entity_type entt, void* ud = nullptr) { - return contains(entt) && (erase(entt, ud), true); - } - - /** - * @brief Removes entities from a sparse set if they exist. - * @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. - * @return The number of entities actually removed. - */ - template - size_type remove(It first, It last, void* ud = nullptr) { - size_type found{}; - - for (; first != last; ++first) { - found += remove(*first, ud); - } - - return found; - } - - /*! @brief Removes all tombstones from the packed array of a sparse set. */ - void compact() { - size_type next = count; - for (; next && packed[next - 1u] == tombstone; --next); - - for (auto* it = &free_list; *it != null && next; it = std::addressof(packed[traits_type::to_entity(*it)])) { - if (const size_type pos = traits_type::to_entity(*it); pos < next) { - --next; - move_and_pop(next, pos); - std::swap(packed[next], packed[pos]); - sparse[page(packed[pos])][offset(packed[pos])] = traits_type::construct(static_cast(pos)); - *it = traits_type::construct(static_cast(next)); - for (; next && packed[next - 1u] == tombstone; --next); - } - } - - free_list = tombstone; - count = next; - } - - /** - * @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) { - ENTT_ASSERT(contains(lhs), "Set does not contain entity"); - ENTT_ASSERT(contains(rhs), "Set does not contain entity"); - - auto& entt = sparse[page(lhs)][offset(lhs)]; - auto& other = sparse[page(rhs)][offset(rhs)]; - - const auto from = size_type{ traits_type::to_entity(entt) }; - const auto to = size_type{ traits_type::to_entity(other) }; - - // basic no-leak guarantee (with invalid state) if swapping throws - swap_at(from, to); - std::swap(entt, other); - std::swap(packed[from], packed[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 length 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 length, Compare compare, Sort algo = Sort{}, Args &&... args) { - // basic no-leak guarantee (with invalid state) if sorting throws - ENTT_ASSERT(!(length > count), "Length exceeds the number of elements"); - compact(); - - algo(std::make_reverse_iterator(packed + length), std::make_reverse_iterator(packed), std::move(compare), std::forward(args)...); - - for (size_type pos{}; pos < length; ++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)] = traits_type::construct(static_cast(curr)); - curr = std::exchange(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(count, 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) { - compact(); - - const auto to = other.end(); - auto from = other.begin(); - - for (size_type pos = count - 1; pos && from != to; ++from) { - if (contains(*from)) { - if (*from != packed[pos]) { - // basic no-leak guarantee (with invalid state) if swapping throws - swap(packed[pos], *from); - } - - --pos; - } - } - } - - /** - * @brief Clears a sparse set. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void clear(void* ud = nullptr) { - for (auto&& entity : *this) { - if (entity != tombstone) { - in_place_pop(entity, ud); - } - } - - free_list = tombstone; - count = 0u; - } - - private: - typename alloc_traits::allocator_type allocator; - typename bucket_alloc_traits::allocator_type bucket_allocator; - bucket_alloc_pointer sparse; - alloc_pointer packed; - std::size_t bucket; - std::size_t count; - std::size_t reserved; - entity_type free_list; - deletion_policy mode; - }; - - -} - - -#endif - -// #include "storage.hpp" -#ifndef ENTT_ENTITY_STORAGE_HPP -#define ENTT_ENTITY_STORAGE_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "../core/fwd.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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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" @@ -7054,16 +1634,417 @@ static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 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 "../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 TURN_OFF_DOXYGEN + */ + + + /** + * @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 + 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. + * + * 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 + 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. + */ + static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { + return helper(wrapper.str); + } + + /** + * @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. + */ + static 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 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. + */ + 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. + */ + constexpr hash_type value() const ENTT_NOEXCEPT { + return hash; + } + + /*! @copydoc data */ + 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. + */ + 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. + */ + 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]) ENTT_NOEXCEPT + ->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 + 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; + + +} + + +/** + * @brief User defined literal for hashed strings. + * @param str The literal without its suffix. + * @return A properly initialized hashed string. + */ +constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(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. + */ +constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(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_index { + static id_type next() ENTT_NOEXCEPT { + static ENTT_MAYBE_ATOMIC(id_type) value {}; + return value++; + } + }; + + + } + + + /** + * Internal details not to be documented. + * @endcond TURN_OFF_DOXYGEN + */ + + + /** + * @brief Type index. + * @tparam Type Type for which to generate a sequential identifier. + */ + template + struct ENTT_API type_index { + /** + * @brief Returns the sequential identifier of a given type. + * @return The sequential identifier of a given type. + */ + static id_type value() ENTT_NOEXCEPT { + static const id_type value = internal::type_index::next(); + return value; + } + }; + + + /** + * @brief Provides the member constant `value` to true if a given type is + * indexable, false otherwise. + * @tparam Type Potentially indexable type. + */ + template + struct has_type_index : std::false_type {}; + + + /*! @brief has_type_index */ + template + struct has_type_index::value())>> : std::true_type {}; + + + /** + * @brief Helper variable template. + * @tparam Type Potentially indexable type. + */ + template + inline constexpr bool has_type_index_v = has_type_index::value; + + + /** + * @brief Type info. + * @tparam Type Type for which to generate information. + */ + template + struct ENTT_API type_info { + /** + * @brief Returns the numeric representation of a given type. + * @return The numeric representation of the given type. + */ +#if defined ENTT_PRETTY_FUNCTION + static ENTT_PRETTY_FUNCTION_CONSTEXPR() id_type id() ENTT_NOEXCEPT { + ENTT_PRETTY_FUNCTION_CONSTEXPR(static const) auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION); + return value; + } +#else + static id_type id() ENTT_NOEXCEPT { + return type_index::value(); + } +#endif + }; } @@ -7071,11 +2052,41 @@ namespace entt { #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 "hashed_string.hpp" + +// #include "fwd.hpp" + namespace entt { + /** + * @brief Wraps a static constant. + * @tparam Value A static constant. + */ + template + using integral_constant = std::integral_constant; + + + /** + * @brief Alias template to ease the creation of named values. + * @tparam Value A constant value at least convertible to `id_type`. + */ + template + using tag = integral_constant; + + /** * @brief Utility class to disambiguate overloaded functions. * @tparam N Number of choices available. @@ -7085,7 +2096,7 @@ namespace entt { // Unfortunately, doxygen cannot parse such a construct. /*! @cond TURN_OFF_DOXYGEN */ : choice_t - /*! @endcond */ + /*! @endcond TURN_OFF_DOXYGEN */ {}; @@ -7102,146 +2113,32 @@ namespace entt { 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 A class to use to push around lists of types, nothing more. */ + template + struct type_list {}; + + + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_size; /** - * @brief Helper type. - * @tparam Type A type. + * @brief Compile-time number of elements in a type list. + * @tparam Type Types provided by the type list. */ - 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 + template + struct type_list_size> + : std::integral_constant {}; /** * @brief Helper variable template. - * @tparam Type The type of which to return the size. + * @tparam List Type list. */ - template - inline constexpr std::size_t 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 {}; } + template + inline constexpr auto type_list_size_v = type_list_size::value; /*! @brief Primary template isn't defined on purpose. */ @@ -7327,396 +2224,25 @@ namespace entt { /** - * @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. + * @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 type_list_contains; + template> + struct is_equality_comparable : std::false_type {}; - /** - * @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...> {}; + /*! @copydoc is_equality_comparable */ + template + struct is_equality_comparable() == std::declval())>> : std::true_type {}; /** * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ - template - inline constexpr bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. + * @tparam Type Potentially equality comparable type. */ template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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; + inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; /** @@ -7725,7 +2251,7 @@ namespace entt { */ template class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); + static_assert(std::is_member_pointer_v); template static Class* clazz(Ret(Class::*)(Args...)); @@ -7753,8 +2279,114 @@ namespace entt { } +/** + * @brief Defines an enum class to use for opaque identifiers and a dedicate + * `to_integer` function to convert the identifiers to their underlying type. + * @param clazz The name to use for the enum class. + * @param type The underlying type for the enum class. + */ +#define ENTT_OPAQUE_TYPE(clazz, type)\ + enum class clazz: type {};\ + constexpr auto to_integral(const clazz id) ENTT_NOEXCEPT {\ + return static_cast>(id);\ + }\ + static_assert(true) + + #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" +#ifndef ENTT_CONFIG_CONFIG_H +#define ENTT_CONFIG_CONFIG_H + + +#ifndef ENTT_NOEXCEPT +# define ENTT_NOEXCEPT noexcept +#endif + + +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws +#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 + + +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 +#endif + + +#ifndef ENTT_ASSERT +# include +# define ENTT_ASSERT(condition) assert(condition) +#endif + + +#ifndef ENTT_NO_ETO +# include +# define ENTT_IS_EMPTY(Type) std::is_empty_v +#else +# include +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) +#endif + + +#ifndef ENTT_STANDARD_CPP +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ +# endif +#endif + + +#endif + +// #include "delegate.hpp" +#ifndef ENTT_SIGNAL_DELEGATE_HPP +#define ENTT_SIGNAL_DELEGATE_HPP + + +#include +#include +#include +#include +#include // #include "../config/config.h" @@ -7796,7 +2428,7 @@ namespace entt { template - [[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) { + constexpr auto index_sequence_for(Ret(*)(Args...)) { return std::index_sequence_for{}; } @@ -7806,7 +2438,7 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ @@ -7844,39 +2476,37 @@ namespace entt { */ template class delegate { + using proto_fn_type = Ret(const void*, Args...); + template - [[nodiscard]] auto wrap(std::index_sequence) ENTT_NOEXCEPT { + 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))...)); + const auto arguments = std::forward_as_tuple(std::forward(args)...); + return Ret(std::invoke(Candidate, std::forward>>(std::get(arguments))...)); }; } template - [[nodiscard]] auto wrap(Type&, std::index_sequence) ENTT_NOEXCEPT { + 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))...)); + const auto arguments = std::forward_as_tuple(std::forward(args)...); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); + return Ret(std::invoke(Candidate, *curr, std::forward>>(std::get(arguments))...)); }; } template - [[nodiscard]] auto wrap(Type*, std::index_sequence) ENTT_NOEXCEPT { + 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))...)); + const auto arguments = std::forward_as_tuple(std::forward(args)...); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); + return Ret(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; + using function_type = Ret(Args...); /*! @brief Default constructor. */ delegate() ENTT_NOEXCEPT @@ -7889,7 +2519,9 @@ namespace entt { * @tparam Candidate Function or member to connect to the delegate. */ template - delegate(connect_arg_t) ENTT_NOEXCEPT { + delegate(connect_arg_t) ENTT_NOEXCEPT + : delegate{} + { connect(); } @@ -7901,20 +2533,12 @@ namespace entt { * @param value_or_instance A valid object that fits the purpose. */ template - delegate(connect_arg_t, Type&& value_or_instance) ENTT_NOEXCEPT { + delegate(connect_arg_t, Type&& value_or_instance) ENTT_NOEXCEPT + : delegate{} + { 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. @@ -7929,7 +2553,7 @@ namespace entt { }; } else if constexpr (std::is_member_pointer_v) { - fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); + fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); } else { fn = wrap(internal::index_sequence_for(internal::function_pointer_t{})); @@ -7942,7 +2566,7 @@ namespace entt { * * 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.
+ * 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. @@ -7957,7 +2581,7 @@ namespace entt { if constexpr (std::is_invocable_r_v) { fn = [](const void* payload, Args... args) -> Ret { - Type* curr = static_cast(const_cast *>(payload)); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); return Ret(std::invoke(Candidate, *curr, std::forward(args)...)); }; } @@ -7982,7 +2606,7 @@ namespace entt { if constexpr (std::is_invocable_r_v) { fn = [](const void* payload, Args... args) -> Ret { - Type* curr = static_cast(const_cast *>(payload)); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); return Ret(std::invoke(Candidate, curr, std::forward(args)...)); }; } @@ -7991,24 +2615,6 @@ namespace entt { } } - /** - * @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. * @@ -8023,7 +2629,7 @@ namespace entt { * @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 { + const void* instance() const ENTT_NOEXCEPT { return data; } @@ -8034,13 +2640,15 @@ namespace entt { * * @warning * Attempting to trigger an invalid delegate results in undefined - * behavior. + * behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * delegate has not yet been set. * * @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), "Uninitialized delegate"); + ENTT_ASSERT(fn); return fn(data, std::forward(args)...); } @@ -8048,7 +2656,7 @@ namespace entt { * @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 { + explicit operator bool() const ENTT_NOEXCEPT { // no need to test also data return !(fn == nullptr); } @@ -8058,12 +2666,12 @@ namespace entt { * @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 { + bool operator==(const delegate& other) const ENTT_NOEXCEPT { return fn == other.fn && data == other.data; } private: - function_type* fn; + proto_fn_type* fn; const void* data; }; @@ -8077,7 +2685,7 @@ namespace entt { * @return True if the two contents differ, false otherwise. */ template - [[nodiscard]] bool operator!=(const delegate& lhs, const delegate& rhs) ENTT_NOEXCEPT { + bool operator!=(const delegate& lhs, const delegate& rhs) ENTT_NOEXCEPT { return !(lhs == rhs); } @@ -8087,7 +2695,7 @@ namespace entt { * @tparam Candidate Function or member to connect to the delegate. */ template - delegate(connect_arg_t) + delegate(connect_arg_t) ENTT_NOEXCEPT ->delegate>>; @@ -8097,20 +2705,10 @@ namespace entt { * @tparam Type Type of class or type of payload. */ template - delegate(connect_arg_t, Type&&) + delegate(connect_arg_t, Type&&) ENTT_NOEXCEPT ->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; - - } @@ -8124,27 +2722,28 @@ namespace entt { namespace entt { + /*! @class delegate */ template class delegate; - + /*! @class dispatcher */ class dispatcher; - + /*! @class emitter */ template class emitter; - + /*! @class connection */ class connection; - + /*! @class scoped_connection */ struct scoped_connection; - + /*! @class sink */ template class sink; - + /*! @class sigh */ template class sigh; @@ -8207,7 +2806,7 @@ namespace entt { /*! @brief Unsigned integer type. */ using size_type = std::size_t; /*! @brief Sink type. */ - using sink_type = sink; + using sink_type = entt::sink; /** * @brief Instance type when it comes to connecting member functions. @@ -8220,7 +2819,7 @@ namespace entt { * @brief Number of listeners connected to the signal. * @return Number of listeners currently connected. */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { + size_type size() const ENTT_NOEXCEPT { return calls.size(); } @@ -8228,7 +2827,7 @@ namespace entt { * @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 { + bool empty() const ENTT_NOEXCEPT { return calls.empty(); } @@ -8312,7 +2911,7 @@ namespace entt { * @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 { + explicit operator bool() const ENTT_NOEXCEPT { return static_cast(disconnect); } @@ -8379,7 +2978,7 @@ namespace entt { * @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 { + explicit operator bool() const ENTT_NOEXCEPT { return static_cast(conn); } @@ -8404,10 +3003,6 @@ namespace entt { * 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. */ @@ -8440,7 +3035,7 @@ namespace entt { * @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 { + bool empty() const ENTT_NOEXCEPT { return signal->calls.empty(); } @@ -8451,7 +3046,7 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before() { + sink before() { delegate call{}; call.template connect(); @@ -8472,9 +3067,9 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before(Type&& value_or_instance) { + sink before(Type&& value_or_instance) { delegate call{}; - call.template connect(value_or_instance); + call.template connect(std::forward(value_or_instance)); const auto& calls = signal->calls; const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); @@ -8492,7 +3087,7 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before(Type& value_or_instance) { + sink before(Type& value_or_instance) { return before(&value_or_instance); } @@ -8504,7 +3099,7 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before(Type* value_or_instance) { + sink before(Type* value_or_instance) { sink other{ *this }; if (value_or_instance) { @@ -8523,7 +3118,7 @@ namespace entt { * @brief Returns a sink that connects before anything else. * @return A properly initialized sink object. */ - [[nodiscard]] sink before() { + sink before() { sink other{ *this }; other.offset = signal->calls.size(); return other; @@ -8604,7 +3199,7 @@ namespace entt { void disconnect(Type&& value_or_instance) { auto& calls = signal->calls; delegate call{}; - call.template connect(value_or_instance); + call.template connect(std::forward(value_or_instance)); calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); } @@ -8656,45 +3251,7 @@ namespace entt { * @tparam Args Types of arguments of a function type. */ template - sink(sigh&) - ->sink; - - -} - - -#endif - -// #include "component.hpp" -#ifndef ENTT_ENTITY_COMPONENT_HPP -#define ENTT_ENTITY_COMPONENT_HPP - - -#include -// #include "../config/config.h" - - - -namespace entt { - - - /*! @brief Commonly used default traits for all types. */ - struct basic_component_traits { - /*! @brief Pointer stability, default is `std::false_type`. */ - using in_place_delete = std::false_type; - /*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */ - using ignore_if_empty = ENTT_IGNORE_IF_EMPTY; - }; - - - /** - * @brief Common way to access various properties of components. - * @tparam Type Type of component. - */ - template - struct component_traits : basic_component_traits { - static_assert(std::is_same_v, Type>, "Unsupported type"); - }; + sink(sigh&) ENTT_NOEXCEPT->sink; } @@ -8702,12 +3259,957 @@ namespace entt { #endif +// #include "entity.hpp" +#ifndef ENTT_ENTITY_ENTITY_HPP +#define ENTT_ENTITY_ENTITY_HPP + + +#include +#include +// #include "../config/config.h" + +// #include "../core/type_traits.hpp" + +// #include "../core/fwd.hpp" + + + +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 a 16 bits entity identifier. + * + * A 16 bits entity identifier guarantees: + * + * * 12 bits for the entity number (up to 4k entities). + * * 4 bit for the version (resets in [0-15]). + */ + template<> + struct entt_traits { + /*! @brief Underlying entity type. */ + using entity_type = std::uint16_t; + /*! @brief Underlying version type. */ + using version_type = std::uint8_t; + /*! @brief Difference type. */ + using difference_type = std::int32_t; + + /*! @brief Mask to use to get the entity number out of an identifier. */ + static constexpr std::uint16_t entity_mask = 0xFFF; + /*! @brief Mask to use to get the version out of an identifier. */ + static constexpr std::uint16_t version_mask = 0xF; + /*! @brief Extent of the entity number within an identifier. */ + static constexpr auto entity_shift = 12; + }; + + + /** + * @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 std::uint32_t entity_mask = 0xFFFFF; + /*! @brief Mask to use to get the version out of an identifier. */ + static constexpr std::uint32_t version_mask = 0xFFF; + /*! @brief Extent of the entity number within an identifier. */ + static constexpr auto entity_shift = 20; + }; + + + /** + * @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 std::uint64_t entity_mask = 0xFFFFFFFF; + /*! @brief Mask to use to get the version out of an identifier. */ + static constexpr std::uint64_t version_mask = 0xFFFFFFFF; + /*! @brief Extent of the entity number within an identifier. */ + static constexpr auto entity_shift = 32; + }; + + + /** + * @cond TURN_OFF_DOXYGEN + * Internal details not to be documented. + */ + + + namespace internal { + + + class null { + template + using traits_type = entt_traits>; + + public: + template + constexpr operator Entity() const ENTT_NOEXCEPT { + return Entity{ traits_type::entity_mask }; + } + + constexpr bool operator==(null) const ENTT_NOEXCEPT { + return true; + } + + constexpr bool operator!=(null) const ENTT_NOEXCEPT { + return false; + } + + template + constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT { + return (to_integral(entity) & traits_type::entity_mask) == to_integral(static_cast(*this)); + } + + template + constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT { + return !(entity == *this); + } + }; + + + template + constexpr bool operator==(const Entity entity, null other) ENTT_NOEXCEPT { + return other.operator==(entity); + } + + + template + constexpr bool operator!=(const Entity entity, null other) ENTT_NOEXCEPT { + return !(other == entity); + } + + + } + + + /** + * Internal details not to be documented. + * @endcond TURN_OFF_DOXYGEN + */ + + + /*! @brief Default entity identifier. */ + ENTT_OPAQUE_TYPE(entity, id_type); + + + /** + * @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 auto null = internal::null{}; + + +} + + +#endif + +// #include "fwd.hpp" +#ifndef ENTT_ENTITY_FWD_HPP +#define ENTT_ENTITY_FWD_HPP + + +// #include "../core/fwd.hpp" + + + +namespace entt { + + + /*! @class basic_registry */ + template + class basic_registry; + + /*! @class basic_view */ + template + class basic_view; + + /*! @class basic_runtime_view */ + template + class basic_runtime_view; + + /*! @class basic_group */ + template + class basic_group; + + /*! @class basic_observer */ + template + class basic_observer; + + /*! @struct basic_actor */ + template + struct basic_actor; + + /*! @class basic_snapshot */ + template + class basic_snapshot; + + /*! @class basic_snapshot_loader */ + template + class basic_snapshot_loader; + + /*! @class basic_continuous_loader */ + template + class basic_continuous_loader; + + /*! @class entity */ + enum class entity : id_type; + + /*! @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 actor = basic_actor; + + /*! @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 Types Types of components iterated by the view. + */ + 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 Types Types of components iterated by the group. + */ + template + using group = basic_group; + + +} + + +#endif + +// #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 "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 + * 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. + * + * @note + * Internal data structures arrange elements to maximize performance. Because of + * that, there are no guarantees that elements have the expected order when + * iterate directly the internal packed array (see `data` and `size` member + * functions for that). Use `begin` and `end` instead. + * + * @tparam Entity A valid entity type (see entt_traits for more details). + */ + template + class sparse_set { + static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE& (ENTT_PAGE_SIZE - 1)) == 0)); + static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(Entity); + + using traits_type = entt_traits>; + using page_type = std::unique_ptr; + + class sparse_set_iterator final { + friend class 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 operator++(), 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; + } + + reference operator[](const difference_type value) const { + const auto pos = size_type(index - value - 1); + return (*packed)[pos]; + } + + bool operator==(const sparse_set_iterator& other) const ENTT_NOEXCEPT { + return other.index == index; + } + + bool operator!=(const sparse_set_iterator& other) const ENTT_NOEXCEPT { + return !(*this == other); + } + + bool operator<(const sparse_set_iterator& other) const ENTT_NOEXCEPT { + return index > other.index; + } + + bool operator>(const sparse_set_iterator& other) const ENTT_NOEXCEPT { + return index < other.index; + } + + bool operator<=(const sparse_set_iterator& other) const ENTT_NOEXCEPT { + return !(*this > other); + } + + bool operator>=(const sparse_set_iterator& other) const ENTT_NOEXCEPT { + return !(*this < other); + } + + pointer operator->() const { + const auto pos = size_type(index - 1); + return &(*packed)[pos]; + } + + reference operator*() const { + return *operator->(); + } + + private: + const packed_type* packed; + index_type index; + }; + + auto page(const Entity entt) const ENTT_NOEXCEPT { + return std::size_t{ (to_integral(entt) & traits_type::entity_mask) / entt_per_page }; + } + + auto offset(const Entity entt) const ENTT_NOEXCEPT { + return std::size_t{ to_integral(entt) & (entt_per_page - 1) }; + } + + page_type& assure(const std::size_t pos) { + if (!(pos < sparse.size())) { + sparse.resize(pos + 1); + } + + if (!sparse[pos]) { + sparse[pos] = std::make_unique(entt_per_page); + // null is safe in all cases for our purposes + for (auto* first = sparse[pos].get(), *last = first + entt_per_page; first != last; ++first) { + *first = null; + } + } + + return sparse[pos]; + } + + 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 Default constructor. */ + sparse_set() = default; + + /*! @brief Default move constructor. */ + sparse_set(sparse_set&&) = default; + + /*! @brief Default destructor. */ + virtual ~sparse_set() = default; + + /*! @brief Default move assignment operator. @return This sparse set. */ + sparse_set& operator=(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. + */ + 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. + */ + size_type extent() const ENTT_NOEXCEPT { + return sparse.size() * entt_per_page; + } + + /** + * @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. + */ + 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. + */ + 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 + * There are no guarantees on the order, even though `respect` has been + * previously invoked. Internal data structures arrange elements to maximize + * performance. Accessing them directly gives a performance boost but less + * guarantees. Use `begin` and `end` if you want to iterate the sparse set + * in the expected order. + * + * @return A pointer to the internal packed array. + */ + 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()`. + * + * @note + * Random access iterators stay true to the order imposed by a call to + * `respect`. + * + * @return An iterator to the first entity of the internal packed array. + */ + 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. + * + * @note + * Random access iterators stay true to the order imposed by a call to + * `respect`. + * + * @return An iterator to the element following the last entity of the + * internal packed array. + */ + iterator end() const ENTT_NOEXCEPT { + return iterator{ packed, {} }; + } + + /** + * @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. + */ + 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. + */ + 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); + } + + /*! @copydoc contains */ + [[deprecated("use ::contains instead")]] + bool has(const entity_type entt) const { + return contains(entt); + } + + /** + * @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.
+ * An assertion will abort the execution at runtime in debug mode if the + * sparse set doesn't contain the given entity. + * + * @param entt A valid entity identifier. + * @return The position of the entity in the sparse set. + */ + size_type index(const entity_type entt) const { + ENTT_ASSERT(contains(entt)); + return size_type(sparse[page(entt)][offset(entt)]); + } + + /** + * @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.
+ * An assertion will abort the execution at runtime in debug mode if the + * sparse set already contains the given entity. + * + * @param entt A valid entity identifier. + */ + void emplace(const entity_type entt) { + ENTT_ASSERT(!contains(entt)); + assure(page(entt))[offset(entt)] = entity_type(packed.size()); + packed.push_back(entt); + } + + /*! @copydoc emplace */ + [[deprecated("use ::emplace instead")]] + void construct(const entity_type entt) { + emplace(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.
+ * An assertion will abort the execution at runtime in debug mode if the + * sparse set already contains the given entity. + * + * @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 = packed.size(); + packed.insert(packed.end(), first, last); + + while (first != last) { + const auto entt = *(first++); + ENTT_ASSERT(!contains(entt)); + assure(page(entt))[offset(entt)] = entity_type(next++); + } + } + + /*! @copydoc insert */ + template + [[deprecated("use ::insert instead")]] + void construct(It first, It last) { + insert(std::move(first), std::move(last)); + } + + /** + * @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.
+ * An assertion will abort the execution at runtime in debug mode if the + * sparse set doesn't contain the given entity. + * + * @param entt A valid entity identifier. + */ + void erase(const entity_type entt) { + ENTT_ASSERT(contains(entt)); + const auto curr = page(entt); + const auto pos = offset(entt); + packed[size_type(sparse[curr][pos])] = entity_type(packed.back()); + sparse[page(packed.back())][offset(packed.back())] = sparse[curr][pos]; + sparse[curr][pos] = null; + packed.pop_back(); + } + + /*! @copydoc erase */ + [[deprecated("use ::erase instead")]] + void destroy(const entity_type entt) { + erase(entt); + } + + /** + * @brief Swaps two entities in the internal packed array. + * + * 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.
+ * An assertion will abort the execution at runtime in debug mode if the + * sparse set doesn't contain the given entities. + * + * @param lhs A valid entity identifier. + * @param rhs A valid entity identifier. + */ + virtual void swap(const entity_type lhs, const entity_type rhs) { + auto& from = sparse[page(lhs)][offset(lhs)]; + auto& to = sparse[page(rhs)][offset(rhs)]; + std::swap(packed[size_type(from)], packed[size_type(to)]); + std::swap(from, to); + } + + /** + * @brief Sort elements according to the given comparison function. + * + * Sort the elements so that iterating the range with a couple of iterators + * returns them 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 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 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. + * + * @note + * Attempting to iterate elements using a raw pointer returned by a call to + * `data` gives no guarantees on the order, even though `sort` has been + * invoked. + * + * @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 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 algo A valid sort function object. + * @param args Arguments to forward to the sort function object, if any. + */ + template + void sort(iterator first, iterator last, Compare compare, Sort algo = Sort{}, Args &&... args) { + ENTT_ASSERT(!(last < first)); + ENTT_ASSERT(!(last > end())); + + const auto length = std::distance(first, last); + const auto skip = std::distance(last, end()); + const auto to = packed.rend() - skip; + const auto from = to - length; + + algo(from, to, std::move(compare), std::forward(args)...); + + for (size_type pos = skip, end = skip + length; pos < end; ++pos) { + sparse[page(packed[pos])][offset(packed[pos])] = entity_type(pos); + } + } + + /** + * @brief Sort elements according to the given comparison function. + * + * @sa sort + * + * This function is a slightly slower version of `sort` that invokes the + * caller to indicate which entities are swapped.
+ * It's recommended when the caller wants to sort its own data structures to + * align them with the order induced in the sparse set. + * + * The signature of the callback should be equivalent to the following: + * + * @code{.cpp} + * bool(const Entity, const Entity); + * @endcode + * + * @tparam Apply Type of function object to invoke to notify the caller. + * @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 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 apply A valid function object to use as a callback. + * @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 arrange(iterator first, iterator last, Apply apply, Compare compare, Sort algo = Sort{}, Args &&... args) { + ENTT_ASSERT(!(last < first)); + ENTT_ASSERT(!(last > end())); + + const auto length = std::distance(first, last); + const auto skip = std::distance(last, end()); + const auto to = packed.rend() - skip; + const auto from = to - length; + + algo(from, to, std::move(compare), std::forward(args)...); + + for (size_type pos = skip, end = skip + length; pos < end; ++pos) { + auto curr = pos; + auto next = index(packed[curr]); + + while (curr != next) { + apply(packed[curr], packed[next]); + sparse[page(packed[curr])][offset(packed[curr])] = entity_type(curr); + + curr = next; + next = index(packed[curr]); + } + } + } + + /** + * @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. + * + * @note + * Attempting to iterate elements using a raw pointer returned by a call to + * `data` gives no guarantees on the order, even though `respect` has been + * invoked. + * + * @param other The sparse sets that imposes the order of the entities. + */ + void respect(const 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. + */ + void clear() ENTT_NOEXCEPT { + sparse.clear(); + packed.clear(); + } + + 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 "../config/config.h" + +// #include "../core/algorithm.hpp" + // #include "sparse_set.hpp" +// #include "entity.hpp" + namespace entt { @@ -8722,12 +4224,15 @@ namespace entt { * to the entities. * * @note - * Entities and objects have the same order. + * 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. + * Internal data structures arrange elements to maximize performance. Because of + * that, there are no guarantees that elements have the expected order when + * iterate directly the internal packed array (see `raw` and `size` member + * functions for that). Use `begin` and `end` instead. * * @warning * Empty types aren't explicitly instantiated. Therefore, many of the functions @@ -8737,52 +4242,42 @@ namespace entt { * * @tparam Entity A valid entity type (see entt_traits for more details). * @tparam Type Type of objects assigned to the entities. - * @tparam Allocator Type of allocator used to manage memory and elements. */ - template - class basic_storage_impl : public basic_sparse_set::template rebind_alloc> { - static constexpr auto packed_page = ENTT_PACKED_PAGE; + template> + class storage : public sparse_set { + static_assert(std::is_move_constructible_v); + static_assert(std::is_move_assignable_v); - using comp_traits = component_traits; + using underlying_type = sparse_set; + using traits_type = entt_traits>; - using underlying_type = basic_sparse_set::template rebind_alloc>; - using difference_type = typename entt_traits::difference_type; + template + class storage_iterator final { + friend class storage; - using alloc_traits = typename std::allocator_traits::template rebind_traits; - using alloc_pointer = typename alloc_traits::pointer; - using alloc_const_pointer = typename alloc_traits::const_pointer; + using instance_type = std::conditional_t, std::vector>; + using index_type = typename traits_type::difference_type; - using bucket_alloc_traits = typename std::allocator_traits::template rebind_traits; - using bucket_alloc_pointer = typename bucket_alloc_traits::pointer; + storage_iterator(instance_type& ref, const index_type idx) ENTT_NOEXCEPT + : instances{ &ref }, index{ idx } + {} - using bucket_alloc_const_type = typename std::allocator_traits::template rebind_alloc; - using bucket_alloc_const_pointer = typename std::allocator_traits::const_pointer; - - static_assert(alloc_traits::propagate_on_container_move_assignment::value); - static_assert(bucket_alloc_traits::propagate_on_container_move_assignment::value); - - template - struct storage_iterator final { - using difference_type = typename basic_storage_impl::difference_type; - using value_type = Value; - using pointer = value_type*; - using reference = value_type&; + public: + using difference_type = index_type; + using value_type = Type; + using pointer = std::conditional_t; + using reference = std::conditional_t; using iterator_category = std::random_access_iterator_tag; storage_iterator() ENTT_NOEXCEPT = default; - storage_iterator(bucket_alloc_pointer const* ref, const typename basic_storage_impl::difference_type idx) ENTT_NOEXCEPT - : packed{ ref }, - index{ idx } - {} - storage_iterator& operator++() ENTT_NOEXCEPT { return --index, * this; } storage_iterator operator++(int) ENTT_NOEXCEPT { storage_iterator orig = *this; - return ++(*this), orig; + return operator++(), orig; } storage_iterator& operator--() ENTT_NOEXCEPT { @@ -8816,239 +4311,60 @@ namespace entt { return other.index - index; } - [[nodiscard]] reference operator[](const difference_type value) const ENTT_NOEXCEPT { + reference operator[](const difference_type value) const ENTT_NOEXCEPT { const auto pos = size_type(index - value - 1); - return (*packed)[page(pos)][offset(pos)]; + return (*instances)[pos]; } - [[nodiscard]] bool operator==(const storage_iterator& other) const ENTT_NOEXCEPT { + bool operator==(const storage_iterator& other) const ENTT_NOEXCEPT { return other.index == index; } - [[nodiscard]] bool operator!=(const storage_iterator& other) const ENTT_NOEXCEPT { + bool operator!=(const storage_iterator& other) const ENTT_NOEXCEPT { return !(*this == other); } - [[nodiscard]] bool operator<(const storage_iterator& other) const ENTT_NOEXCEPT { + bool operator<(const storage_iterator& other) const ENTT_NOEXCEPT { return index > other.index; } - [[nodiscard]] bool operator>(const storage_iterator& other) const ENTT_NOEXCEPT { + bool operator>(const storage_iterator& other) const ENTT_NOEXCEPT { return index < other.index; } - [[nodiscard]] bool operator<=(const storage_iterator& other) const ENTT_NOEXCEPT { + bool operator<=(const storage_iterator& other) const ENTT_NOEXCEPT { return !(*this > other); } - [[nodiscard]] bool operator>=(const storage_iterator& other) const ENTT_NOEXCEPT { + 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 std::addressof((*packed)[page(pos)][offset(pos)]); + pointer operator->() const ENTT_NOEXCEPT { + const auto pos = size_type(index - 1); + return &(*instances)[pos]; } - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { + reference operator*() const ENTT_NOEXCEPT { return *operator->(); } private: - bucket_alloc_pointer const* packed; - difference_type index; + instance_type* instances; + index_type index; }; - [[nodiscard]] static auto page(const std::size_t pos) ENTT_NOEXCEPT { - return pos / packed_page; - } - - [[nodiscard]] static auto offset(const std::size_t pos) ENTT_NOEXCEPT { - return pos & (packed_page - 1); - } - - void release_memory() { - if (packed) { - // no-throw stable erase iteration - underlying_type::clear(); - - for (size_type pos{}; pos < bucket; ++pos) { - alloc_traits::deallocate(allocator, packed[pos], packed_page); - bucket_alloc_traits::destroy(bucket_allocator, std::addressof(packed[pos])); - } - - bucket_alloc_traits::deallocate(bucket_allocator, packed, bucket); - } - } - - void assure_at_least(const std::size_t last) { - if (const auto idx = page(last - 1u); !(idx < bucket)) { - const size_type sz = idx + 1u; - const auto mem = bucket_alloc_traits::allocate(bucket_allocator, sz); - std::uninitialized_copy(packed, packed + bucket, mem); - size_type pos{}; - - ENTT_TRY{ - for (pos = bucket; pos < sz; ++pos) { - auto pg = alloc_traits::allocate(allocator, packed_page); - bucket_alloc_traits::construct(bucket_allocator, std::addressof(mem[pos]), pg); - } - } ENTT_CATCH{ - for (auto next = bucket; next < pos; ++next) { - alloc_traits::deallocate(allocator, mem[next], packed_page); - } - - std::destroy(mem, mem + pos); - bucket_alloc_traits::deallocate(bucket_allocator, mem, sz); - ENTT_THROW; - } - - std::destroy(packed, packed + bucket); - bucket_alloc_traits::deallocate(bucket_allocator, packed, bucket); - - packed = mem; - bucket = sz; - } - } - - void release_unused_pages() { - if (const auto length = underlying_type::size() / packed_page; length < bucket) { - const auto mem = bucket_alloc_traits::allocate(bucket_allocator, length); - std::uninitialized_copy(packed, packed + length, mem); - - for (auto pos = length; pos < bucket; ++pos) { - alloc_traits::deallocate(allocator, packed[pos], packed_page); - bucket_alloc_traits::destroy(bucket_allocator, std::addressof(packed[pos])); - } - - bucket_alloc_traits::deallocate(bucket_allocator, packed, bucket); - - packed = mem; - bucket = length; - } - } - - template - auto& push_at(const std::size_t pos, Args &&... args) { - ENTT_ASSERT(pos < (bucket* packed_page), "Out of bounds index"); - auto* instance = std::addressof(packed[page(pos)][offset(pos)]); - - if constexpr (std::is_aggregate_v) { - alloc_traits::construct(allocator, instance, Type{ std::forward(args)... }); - } - else { - alloc_traits::construct(allocator, instance, std::forward(args)...); - } - - return *instance; - } - - void pop_at(const std::size_t pos) { - alloc_traits::destroy(allocator, std::addressof(packed[page(pos)][offset(pos)])); - } - - protected: - /*! @copydoc basic_sparse_set::swap_at */ - void swap_at(const std::size_t lhs, const std::size_t rhs) final { - std::swap(packed[page(lhs)][offset(lhs)], packed[page(rhs)][offset(rhs)]); - } - - /*! @copydoc basic_sparse_set::move_and_pop */ - void move_and_pop(const std::size_t from, const std::size_t to) final { - push_at(to, std::move(packed[page(from)][offset(from)])); - pop_at(from); - } - - /*! @copydoc basic_sparse_set::swap_and_pop */ - void swap_and_pop(const Entity entt, void* ud) override { - const auto pos = underlying_type::index(entt); - const auto last = underlying_type::size() - 1u; - auto&& elem = packed[page(pos)][offset(pos)]; - - // support for nosy destructors - [[maybe_unused]] auto unused = std::move(elem); - elem = std::move(packed[page(last)][offset(last)]); - pop_at(last); - - underlying_type::swap_and_pop(entt, ud); - } - - /*! @copydoc basic_sparse_set::in_place_pop */ - void in_place_pop(const Entity entt, void* ud) override { - const auto pos = underlying_type::index(entt); - underlying_type::in_place_pop(entt, ud); - // support for nosy destructors - pop_at(pos); - } - public: - /*! @brief Allocator type. */ - using allocator_type = typename alloc_traits::allocator_type; - /*! @brief Type of the objects assigned to entities. */ - using value_type = Type; + /*! @brief Type of the objects associated with the entities. */ + using object_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = std::size_t; - /*! @brief Pointer type to contained elements. */ - using pointer = bucket_alloc_pointer; - /*! @brief Constant pointer type to contained elements. */ - using const_pointer = bucket_alloc_const_pointer; /*! @brief Random access iterator type. */ - using iterator = storage_iterator; + using iterator = storage_iterator; /*! @brief Constant random access iterator type. */ - using const_iterator = storage_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = std::reverse_iterator; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = std::reverse_iterator; - - /** - * @brief Default constructor. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_storage_impl(const allocator_type& alloc = {}) - : underlying_type{ deletion_policy{comp_traits::in_place_delete::value}, alloc }, - allocator{ alloc }, - bucket_allocator{ alloc }, - packed{ bucket_alloc_traits::allocate(bucket_allocator, 0u) }, - bucket{} - {} - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_storage_impl(basic_storage_impl&& other) ENTT_NOEXCEPT - : underlying_type{ std::move(other) }, - allocator{ std::move(other.allocator) }, - bucket_allocator{ std::move(other.bucket_allocator) }, - packed{ std::exchange(other.packed, bucket_alloc_pointer{}) }, - bucket{ std::exchange(other.bucket, 0u) } - {} - - /*! @brief Default destructor. */ - ~basic_storage_impl() override { - release_memory(); - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This sparse set. - */ - basic_storage_impl& operator=(basic_storage_impl&& other) ENTT_NOEXCEPT { - release_memory(); - - underlying_type::operator=(std::move(other)); - - allocator = std::move(other.allocator); - bucket_allocator = std::move(other.bucket_allocator); - packed = std::exchange(other.packed, bucket_alloc_pointer{}); - bucket = std::exchange(other.bucket, 0u); - - return *this; - } + using const_iterator = storage_iterator; /** * @brief Increases the capacity of a storage. @@ -9060,153 +4376,128 @@ namespace entt { */ void reserve(const size_type cap) { underlying_type::reserve(cap); - - if (cap > underlying_type::size()) { - assure_at_least(cap); - } - } - - /** - * @brief Returns the number of elements that a storage has currently - * allocated space for. - * @return Capacity of the storage. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return bucket * packed_page; + instances.reserve(cap); } /*! @brief Requests the removal of unused capacity. */ void shrink_to_fit() { underlying_type::shrink_to_fit(); - release_unused_pages(); + 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 + * There are no guarantees on the order, even though either `sort` or + * `respect` has been previously invoked. Internal data structures arrange + * elements to maximize performance. Accessing them directly gives a + * performance boost but less guarantees. Use `begin` and `end` if you want + * to iterate the storage in the expected order. + * * @return A pointer to the array of objects. */ - [[nodiscard]] const_pointer raw() const ENTT_NOEXCEPT { - return packed; + const object_type* raw() const ENTT_NOEXCEPT { + return instances.data(); } /*! @copydoc raw */ - [[nodiscard]] pointer raw() ENTT_NOEXCEPT { - return packed; + object_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()`. + * The returned iterator points to the first instance of the given type. If + * the storage is empty, the returned iterator will be equal to `end()`. * - * @return An iterator to the first instance of the internal array. + * @note + * Random access iterators stay true to the order imposed by a call to + * either `sort` or `respect`. + * + * @return An iterator to the first instance of the given type. */ - [[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT { - const difference_type pos = underlying_type::size(); - return const_iterator{ std::addressof(packed), pos }; + 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 { + const_iterator begin() const ENTT_NOEXCEPT { return cbegin(); } /*! @copydoc begin */ - [[nodiscard]] iterator begin() ENTT_NOEXCEPT { - const difference_type pos = underlying_type::size(); - return iterator{ std::addressof(packed), pos }; + 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 + * of the given type. Attempting to dereference the returned iterator * results in undefined behavior. * + * @note + * Random access iterators stay true to the order imposed by a call to + * either `sort` or `respect`. + * * @return An iterator to the element following the last instance of the - * internal array. + * given type. */ - [[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT { - return const_iterator{ std::addressof(packed), {} }; + const_iterator cend() const ENTT_NOEXCEPT { + return const_iterator{ instances, {} }; } /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const ENTT_NOEXCEPT { + const_iterator end() const ENTT_NOEXCEPT { return cend(); } /*! @copydoc end */ - [[nodiscard]] iterator end() ENTT_NOEXCEPT { - return iterator{ std::addressof(packed), {} }; + 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 std::make_reverse_iterator(cend()); - } - - /*! @copydoc crbegin */ - [[nodiscard]] const_reverse_iterator rbegin() const ENTT_NOEXCEPT { - return crbegin(); - } - - /*! @copydoc rbegin */ - [[nodiscard]] reverse_iterator rbegin() ENTT_NOEXCEPT { - return std::make_reverse_iterator(end()); - } - - /** - * @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 std::make_reverse_iterator(cbegin()); - } - - /*! @copydoc crend */ - [[nodiscard]] const_reverse_iterator rend() const ENTT_NOEXCEPT { - return crend(); - } - - /*! @copydoc rend */ - [[nodiscard]] reverse_iterator rend() ENTT_NOEXCEPT { - return std::make_reverse_iterator(begin()); - } - - /** - * @brief Returns the object assigned to an entity. + * @brief Returns the object associated with an entity. * * @warning * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. + * undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * storage doesn't contain the given entity. * * @param entt A valid entity identifier. - * @return The object assigned to the entity. + * @return The object associated with the entity. */ - [[nodiscard]] const value_type& get(const entity_type entt) const ENTT_NOEXCEPT { - const auto idx = underlying_type::index(entt); - return packed[page(idx)][offset(idx)]; + const object_type& get(const entity_type entt) const { + return instances[underlying_type::index(entt)]; } /*! @copydoc get */ - [[nodiscard]] value_type& get(const entity_type entt) ENTT_NOEXCEPT { - return const_cast(std::as_const(*this).get(entt)); + object_type& get(const entity_type entt) { + return const_cast(std::as_const(*this).get(entt)); + } + + /** + * @brief Returns a pointer to the object associated with an entity, if any. + * @param entt A valid entity identifier. + * @return The object associated with the entity, if any. + */ + const object_type* try_get(const entity_type entt) const { + return underlying_type::contains(entt) ? (instances.data() + underlying_type::index(entt)) : nullptr; + } + + /*! @copydoc try_get */ + object_type* try_get(const entity_type entt) { + return const_cast(std::as_const(*this).try_get(entt)); } /** @@ -9218,44 +4509,32 @@ namespace entt { * * @warning * Attempting to use an entity that already belongs to the storage results - * in undefined behavior. + * in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * storage already contains the given entity. * * @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) { - const auto pos = underlying_type::slot(); - assure_at_least(pos + 1u); - - auto& value = push_at(pos, std::forward(args)...); - - ENTT_TRY{ - [[maybe_unused]] const auto curr = underlying_type::emplace(entt); - ENTT_ASSERT(pos == curr, "Misplaced component"); - } ENTT_CATCH{ - pop_at(pos); - ENTT_THROW; + void 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)...); } - return value; + // entity goes after component in case constructor throws + 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 entt A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the updated instance. - */ - template - decltype(auto) patch(const entity_type entt, Func &&... func) { - const auto idx = underlying_type::index(entt); - auto&& elem = packed[page(idx)][offset(idx)]; - (std::forward(func)(elem), ...); - return elem; + /*! @copydoc emplace */ + template + [[deprecated("use ::emplace instead")]] + void construct(const entity_type entt, Args &&... args) { + emplace(entt, std::forward(args)...); } /** @@ -9264,7 +4543,9 @@ namespace entt { * * @warning * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. + * results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * storage already contains the given entity. * * @tparam It Type of input iterator. * @param first An iterator to the first element of the range of entities. @@ -9272,21 +4553,18 @@ namespace entt { * @param value An instance of the object to construct. */ template - void insert(It first, It last, const value_type& value = {}) { - const auto cap = underlying_type::size() + std::distance(first, last); - underlying_type::reserve(cap); - assure_at_least(cap); + void insert(It first, It last, const object_type& value = {}) { + instances.insert(instances.end(), std::distance(first, last), value); + // entities go after components in case constructors throw + underlying_type::insert(first, last); + } - for (; first != last; ++first) { - push_at(underlying_type::size(), value); - - ENTT_TRY{ - underlying_type::emplace_back(*first); - } ENTT_CATCH{ - pop_at(underlying_type::size()); - ENTT_THROW; - } - } + /*! @copydoc insert */ + template + [[deprecated("use ::insert instead")]] + std::enable_if_t::value_type, entity_type>, void> + construct(It first, It last, const object_type& value = {}) { + insert(std::move(first), std::move(last), value); } /** @@ -9300,28 +4578,71 @@ namespace entt { * @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::value_type>, value_type>>> - void insert(EIt first, EIt last, CIt from) { - const auto cap = underlying_type::size() + std::distance(first, last); - underlying_type::reserve(cap); - assure_at_least(cap); + 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); + } - for (; first != last; ++first, ++from) { - push_at(underlying_type::size(), *from); + /*! @copydoc insert */ + template + [[deprecated("use ::insert instead")]] + std::enable_if_t::value_type, entity_type>, void> + construct(EIt first, EIt last, CIt value) { + insert(std::move(first), std::move(last), std::move(value)); + } - ENTT_TRY{ - underlying_type::emplace_back(*first); - } ENTT_CATCH{ - pop_at(underlying_type::size()); - ENTT_THROW; - } - } + /** + * @brief Removes an entity from a storage and destroys its object. + * + * @warning + * Attempting to use an entity that doesn't belong to the storage results in + * undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * storage doesn't contain the given entity. + * + * @param entt A valid entity identifier. + */ + void erase(const entity_type entt) { + auto other = std::move(instances.back()); + instances[underlying_type::index(entt)] = std::move(other); + instances.pop_back(); + underlying_type::erase(entt); + } + + /*! @copydoc erase */ + [[deprecated("use ::erase instead")]] + void destroy(const entity_type entt) { + erase(entt); + } + + /** + * @brief Swaps entities and objects in the internal packed arrays. + * + * @warning + * Attempting to swap entities that don't belong to the sparse set results + * in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * sparse set doesn't contain the given entities. + * + * @param lhs A valid entity identifier. + * @param rhs A valid entity identifier. + */ + void swap(const entity_type lhs, const entity_type rhs) override { + std::swap(instances[underlying_type::index(lhs)], instances[underlying_type::index(rhs)]); + underlying_type::swap(lhs, rhs); } /** * @brief Sort elements according to the given comparison function. * + * Sort the elements so that iterating the range with a couple of iterators + * returns them 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: @@ -9341,6 +4662,11 @@ namespace entt { * * An iterator past the last element of the range to sort. * * A comparison function to use to compare the elements. * + * @note + * Attempting to iterate elements using a raw pointer returned by a call to + * either `data` or `raw` gives no guarantees on the order, even though + * `sort` has been invoked. + * * @warning * Empty types are never instantiated. Therefore, only comparison function * objects that require to return entities rather than components are @@ -9349,95 +4675,67 @@ namespace entt { * @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 length Number of elements to sort. + * @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 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 length, Compare compare, Sort algo = Sort{}, Args &&... args) { - if constexpr (std::is_invocable_v) { - underlying_type::sort_n(length, [this, compare = std::move(compare)](const auto lhs, const auto rhs) { - const auto ilhs = underlying_type::index(lhs), irhs = underlying_type::index(rhs); - return compare(std::as_const(packed[page(ilhs)][offset(ilhs)]), std::as_const(packed[page(irhs)][offset(irhs)])); + void sort(iterator first, iterator last, Compare compare, Sort algo = Sort{}, Args &&... args) { + ENTT_ASSERT(!(last < first)); + ENTT_ASSERT(!(last > end())); + + const auto from = underlying_type::begin() + std::distance(begin(), first); + const auto to = from + std::distance(first, last); + + const auto apply = [this](const auto lhs, const auto rhs) { + std::swap(instances[underlying_type::index(lhs)], instances[underlying_type::index(rhs)]); + }; + + if constexpr (std::is_invocable_v) { + underlying_type::arrange(from, to, std::move(apply), [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(length, std::move(compare), std::move(algo), std::forward(args)...); + underlying_type::arrange(from, to, std::move(apply), 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(underlying_type::size(), std::move(compare), std::move(algo), std::forward(args)...); + /*! @brief Clears a storage. */ + void clear() { + underlying_type::clear(); + instances.clear(); } private: - typename alloc_traits::allocator_type allocator; - typename bucket_alloc_traits::allocator_type bucket_allocator; - bucket_alloc_pointer packed; - size_type bucket; + std::vector instances; }; - /*! @copydoc basic_storage_impl */ - template - class basic_storage_impl::ignore_if_empty::value&& std::is_empty_v>> - : public basic_sparse_set::template rebind_alloc> - { - using comp_traits = component_traits; - using underlying_type = basic_sparse_set::template rebind_alloc>; - using alloc_traits = typename std::allocator_traits::template rebind_traits; + /*! @copydoc storage */ + template + class storage> : public sparse_set { + using traits_type = entt_traits>; + using underlying_type = sparse_set; public: - /*! @brief Allocator type. */ - using allocator_type = typename alloc_traits::allocator_type; - /*! @brief Type of the objects assigned to entities. */ - using value_type = Type; + /*! @brief Type of the objects associated with the entities. */ + using object_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = std::size_t; - /** - * @brief Default constructor. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_storage_impl(const allocator_type& alloc = {}) - : underlying_type{ deletion_policy{comp_traits::in_place_delete::value}, alloc } - {} - - /** - * @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_NOEXCEPT { - ENTT_ASSERT(underlying_type::contains(entt), "Storage does not contain entity"); - } - /** * @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. + * in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * storage already contains the given entity. * * @tparam Args Types of arguments to use to construct the object. * @param entt A valid entity identifier. @@ -9445,20 +4743,15 @@ namespace entt { */ template void emplace(const entity_type entt, Args &&... args) { - [[maybe_unused]] value_type instance{ std::forward(args)... }; + [[maybe_unused]] object_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 entt A valid entity identifier. - * @param func Valid function objects. - */ - template - void patch([[maybe_unused]] const entity_type entt, Func &&... func) { - ENTT_ASSERT(underlying_type::contains(entt), "Storage does not contain entity"); - (std::forward(func)(), ...); + /*! @copydoc emplace */ + template + [[deprecated("use ::emplace instead")]] + void construct(const entity_type entt, Args &&... args) { + emplace(entt, std::forward(args)...); } /** @@ -9466,273 +4759,32 @@ namespace entt { * * @warning * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. + * results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * storage already contains the given entity. * * @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 & = {}) { + void insert(It first, It last, const object_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 Inherited constructors. */ - using Type::Type; /** - * @brief Assigns entities to a storage. - * @tparam Args Types of arguments to use to construct the object. - * @param entt A valid entity identifier. - * @param args Parameters to use to initialize the object. - * @return A reference to the newly created object. + * @copydoc insert + * @param value An instance of the object to construct. */ - template - decltype(auto) emplace(basic_registry&, const entity_type entt, Args &&... args) { - return Type::emplace(entt, 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 entt 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 entt, Func &&... func) { - return Type::patch(entt, std::forward(func)...); + template + [[deprecated("use ::insert instead")]] + std::enable_if_t::value_type, entity_type>, void> + construct(It first, It last, const object_type& value = {}) { + insert(std::move(first), std::move(last), value); } }; - /** - * @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 { - /*! @copydoc basic_sparse_set::swap_and_pop */ - void swap_and_pop(const typename Type::entity_type entt, void* ud) final { - ENTT_ASSERT(ud != nullptr, "Invalid pointer to registry"); - destruction.publish(*static_cast *>(ud), entt); - Type::swap_and_pop(entt, ud); - } - - /*! @copydoc basic_sparse_set::in_place_pop */ - void in_place_pop(const typename Type::entity_type entt, void* ud) final { - ENTT_ASSERT(ud != nullptr, "Invalid pointer to registry"); - destruction.publish(*static_cast *>(ud), entt); - Type::in_place_pop(entt, 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 Inherited constructors. */ - using Type::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 entt 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 entt, Args &&... args) { - Type::emplace(entt, std::forward(args)...); - construction.publish(owner, entt); - return this->get(entt); - } - - /** - * @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 entt 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 entt, Func &&... func) { - Type::patch(entt, std::forward(func)...); - update.publish(owner, entt); - return this->get(entt); - } - - private: - sigh&, const entity_type)> construction{}; - sigh&, const entity_type)> destruction{}; - sigh&, const entity_type)> update{}; - }; - - - /** - * @brief Storage implementation dispatcher. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects assigned to the entities. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ - template - struct basic_storage : basic_storage_impl { - using basic_storage_impl::basic_storage_impl; - }; - - - /** - * @brief Provides a common way to access certain properties of storage types. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects managed by the storage class. - */ - 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 entt 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 entt) { - 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(entt)); - } - } - - } @@ -9787,3228 +4839,10 @@ namespace entt { #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; - - using basic_common_type = basic_sparse_set; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable final { - template - struct iterable_iterator final { - 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; - - template - iterable_iterator(It from, const std::tuple *...>& args) ENTT_NOEXCEPT - : it{ from }, - pools{ args } - {} - - iterable_iterator& operator++() ENTT_NOEXCEPT { - return ++it, * this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_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_iterator& other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple *...> pools; - }; - - public: - using iterator = iterable_iterator; - using reverse_iterator = iterable_iterator; - - iterable(basic_common_type* const ref, const std::tuple *...>& cpools) - : handler{ ref }, - pools{ cpools } - {} - - [[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_common_type* const handler; - const std::tuple *...> pools; - }; - - basic_group(basic_common_type& 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_common_type::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_common_type::reverse_iterator; - /*! @brief Iterable group type. */ - using iterable_group = iterable; - - /*! @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]] auto 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), "Group does not contain entity"); - - 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 < Func, decltype(std::tuple_cat(std::tuple{}, 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_common_type* 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; - - using basic_common_type = basic_sparse_set; - - template - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable final { - template - struct iterable_iterator; - - template - struct iterable_iterator> final { - 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; - - template - iterable_iterator(It from, const std::tuple& other, const std::tuple *...>& cpools) ENTT_NOEXCEPT - : it{ from }, - owned{ std::get(other)... }, - get{ cpools } - {} - - iterable_iterator& operator++() ENTT_NOEXCEPT { - return ++it, (++std::get(owned), ...), * this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_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_iterator& other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple owned; - std::tuple *...> get; - }; - - public: - using iterator = iterable_iterator< - typename basic_common_type::iterator, - type_list_cat_t < std::conditional_t < std::is_void_v>().get({})) > , type_list<>, type_list>().end()) >> ... > - > ; - using reverse_iterator = iterable_iterator< - typename basic_common_type::reverse_iterator, - type_list_cat_t < std::conditional_t < std::is_void_v>().get({})) > , type_list<>, type_list>().rbegin()) >> ... > - > ; - - iterable(std::tuple *..., storage_type *...> cpools, const std::size_t* const extent) - : pools{ cpools }, - length{ extent } - {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return length ? iterator{ - std::get<0>(pools)->basic_common_type::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_common_type::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_common_type::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_common_type::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_common_type::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_common_type::reverse_iterator; - /*! @brief Iterable group type. */ - using iterable_group = iterable; - - /*! @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 raw representation offered by the storage. - * - * @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]] auto raw() const ENTT_NOEXCEPT { - static_assert((std::is_same_v || ...), "Non-owned type"); - auto* cpool = std::get*>(pools); - return cpool ? cpool->raw() : decltype(cpool->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]] auto 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_common_type::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_common_type::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_common_type::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_common_type::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), "Group does not contain entity"); - - 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 < Func, decltype(std::tuple_cat(std::tuple{}, 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 "../config/config.h" - -// #include "../core/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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 - -// #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 -// #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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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 : std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE }; - enum class policy : std::uint8_t { OWNER, REF, CREF }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void* (const operation, const basic_any&, 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 constexpr policy type_to_policy() { - if constexpr (std::is_lvalue_reference_v) { - if constexpr (std::is_const_v>) { - return policy::CREF; - } - else { - return policy::REF; - } - } - else { - return policy::OWNER; - } - } - - 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 const void* basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any& from, [[maybe_unused]] void* to) { - static_assert(std::is_same_v>, Type>, "Invalid type"); - - if constexpr (!std::is_void_v) { - const Type* instance = (in_situ && from.mode == policy::OWNER) - ? ENTT_LAUNDER(reinterpret_cast(&from.storage)) - : static_cast(from.instance); - - switch (op) { - case operation::COPY: - if constexpr (std::is_copy_constructible_v) { - static_cast(to)->emplace(*instance); - } - break; - case operation::MOVE: - if constexpr (in_situ) { - if (from.mode == policy::OWNER) { - return new (&static_cast(to)->storage) Type{ std::move(*const_cast(instance)) }; - } - } - - return (static_cast(to)->instance = std::exchange(const_cast(from).instance, nullptr)); - case operation::DTOR: - if (from.mode == policy::OWNER) { - if constexpr (in_situ) { - instance->~Type(); - } - else if constexpr (std::is_array_v) { - delete[] instance; - } - else { - delete instance; - } - } - break; - case operation::COMP: - return compare(instance, (*static_cast(to))->data()) ? to : nullptr; - case operation::ADDR: - if (from.mode == policy::CREF) { - return nullptr; - } - [[fallthrough]]; - case operation::CADDR: - return instance; - case operation::TYPE: - *static_cast(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 (sizeof...(Args) != 0u && std::is_aggregate_v) { - new (&storage) Type{ std::forward(args)... }; - } - else { - new (&storage) Type(std::forward(args)...); - } - } - else { - if constexpr (sizeof...(Args) != 0u && std::is_aggregate_v) { - instance = new Type{ std::forward(args)... }; - } - else { - instance = new Type(std::forward(args)...); - } - } - } - } - - basic_any(const basic_any& other, const policy pol) ENTT_NOEXCEPT - : instance{ other.data() }, - vtable{ other.vtable }, - mode{ pol } - {} - - public: - /*! @brief Size of the internal storage. */ - static constexpr auto length = Len; - /*! @brief Alignment requirement. */ - static constexpr auto alignment = Align; - - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - {} - - /** - * @brief Constructs a wrapper 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>> }, - mode{ type_to_policy() } - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs a wrapper 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{} - { - // invokes deprecated assignment operator (and avoids issues with vs2017) - *this = value; - } - - /** - * @brief Constructs a wrapper 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) - : instance{}, - vtable{ &basic_vtable> }, - mode{ policy::OWNER } - { - initialize>(std::forward(value)); - } - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any& other) - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any&& other) ENTT_NOEXCEPT - : instance{}, - vtable{ other.vtable }, - mode{ other.mode } - { - 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) { - reset(); - 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) ENTT_NOEXCEPT { - std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - mode = other.mode; - 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 - [[deprecated("Use std::in_place_type, entt::make_any, emplace or forward_as_any instead")]] - 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); - mode = type_to_policy(); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - mode = policy::OWNER; - } - - /** - * @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 { - const basic_any* trampoline = &other; - return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data()); - } - - /** - * @brief Aliasing constructor. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - return basic_any{ *this, (mode == policy::CREF ? policy::CREF : policy::REF) }; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - return basic_any{ *this, policy::CREF }; - } - - /** - * @brief Returns true if a wrapper owns its object, false otherwise. - * @return True if the wrapper owns its object, false otherwise. - */ - [[nodiscard]] bool owner() const ENTT_NOEXCEPT { - return (mode == policy::OWNER); - } - - private: - union { const void* instance; storage_type storage; }; - vtable_type* vtable; - policy mode; - }; - - - /** - * @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, "Invalid 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, "Invalid 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, "Invalid 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); - } - - - /** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - * @return A properly initialized wrapper for an object of the given type. - */ - template::length, std::size_t Align = basic_any::alignment, typename... Args> - basic_any make_any(Args &&... args) { - return basic_any{std::in_place_type, std::forward(args)...}; - } - - - /** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ - template::length, std::size_t Align = basic_any::alignment, typename Type> - basic_any forward_as_any(Type&& value) { - return basic_any{std::in_place_type, std::decay_t, Type>>, std::forward(value)}; - } - - -} - - -#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 "component.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 { @@ -13061,115 +4895,55 @@ namespace entt { * @tparam Get Type of components observed by the group. */ template - class basic_group, get_t> final { + class basic_group, get_t> { /*! @brief A registry is allowed to create groups. */ friend class basic_registry; - using basic_common_type = basic_sparse_set; - template - using storage_type = constness_as_t>::storage_type, Component>; + using pool_type = std::conditional_t, const storage>, storage>; - class iterable final { - template - struct iterable_iterator final { - 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; - - template - iterable_iterator(It from, const std::tuple *...>& args) ENTT_NOEXCEPT - : it{ from }, - pools{ args } - {} - - iterable_iterator& operator++() ENTT_NOEXCEPT { - return ++it, * this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_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_iterator& other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple *...> pools; - }; - - public: - using iterator = iterable_iterator; - using reverse_iterator = iterable_iterator; - - iterable(basic_common_type* const ref, const std::tuple *...>& cpools) - : handler{ ref }, - pools{ cpools } - {} - - [[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_common_type* const handler; - const std::tuple *...> pools; - }; - - basic_group(basic_common_type& ref, storage_type &... gpool) ENTT_NOEXCEPT + // we could use pool_type &..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug) + basic_group(sparse_set& ref, storage> &... gpool) ENTT_NOEXCEPT : handler{ &ref }, pools{ &gpool... } {} + template + void traverse(Func func, type_list) const { + for (const auto entt : *handler) { + if constexpr (std::is_invocable_v < Func, decltype(get({}))... > ) { + func(std::get*>(pools)->get(entt)...); + } + else { + func(entt, std::get*>(pools)->get(entt)...); + } + } + } + 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_common_type::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_common_type::reverse_iterator; - /*! @brief Iterable group type. */ - using iterable_group = iterable; + /*! @brief Input iterator type. */ + using iterator = typename sparse_set::iterator; - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() ENTT_NOEXCEPT - : handler{} - {} + /** + * @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 + size_type size() const ENTT_NOEXCEPT { + return std::get*>(pools)->size(); + } /** * @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{}; + size_type size() const ENTT_NOEXCEPT { + return handler->size(); } /** @@ -13177,108 +4951,139 @@ namespace entt { * allocated space for. * @return Capacity of the group. */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return *this ? handler->capacity() : size_type{}; + size_type capacity() const ENTT_NOEXCEPT { + return handler->capacity(); } /*! @brief Requests the removal of unused capacity. */ void shrink_to_fit() { - if (*this) { - handler->shrink_to_fit(); + handler->shrink_to_fit(); + } + + /** + * @brief Checks whether a group or some pools are empty. + * @tparam Component Types of components in which one is interested. + * @return True if the group or the pools are empty, false otherwise. + */ + template + bool empty() const ENTT_NOEXCEPT { + if constexpr (sizeof...(Component) == 0) { + return handler->empty(); + } + else { + return (std::get*>(pools)->empty() && ...); } } /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. + * @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. + * + * @note + * There are no guarantees on the order of the components. Use `begin` and + * `end` if you want to iterate the group in the expected order. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of components. */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return !*this || handler->empty(); + template + Component* raw() const ENTT_NOEXCEPT { + return std::get*>(pools)->raw(); + } + + /** + * @brief Direct access to the list of entities of a given pool. + * + * The returned pointer is such that range + * `[data(), data() + size()]` is always a + * valid range, even if the container is empty. + * + * @note + * There are no guarantees on the order of the entities. Use `begin` and + * `end` if you want to iterate the group in the expected order. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of entities. + */ + template + const entity_type* data() const ENTT_NOEXCEPT { + return std::get*>(pools)->data(); } /** * @brief Direct access to the list of entities. * - * The returned pointer is such that range `[data(), data() + size())` is + * The returned pointer is such that range `[data(), data() + size()]` is * always a valid range, even if the container is empty. * + * @note + * There are no guarantees on the order of the entities. Use `begin` and + * `end` if you want to iterate the group in the expected order. + * * @return A pointer to the array of entities. */ - [[nodiscard]] auto data() const ENTT_NOEXCEPT { - return *this ? handler->data() : nullptr; + const entity_type* data() const ENTT_NOEXCEPT { + return handler->data(); } /** - * @brief Returns an iterator to the first entity of the group. + * @brief Returns an iterator to the first entity that has the given + * components. * - * The returned iterator points to the first entity of the group. If the - * group is empty, the returned iterator will be equal to `end()`. + * The returned iterator points to the first entity that has the given + * components. If the group is empty, the returned iterator will be equal to + * `end()`. * - * @return An iterator to the first entity of the group. + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the first entity that has the given components. */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return *this ? handler->begin() : iterator{}; + iterator begin() const ENTT_NOEXCEPT { + return handler->begin(); } /** - * @brief Returns an iterator that is past the last entity of the group. + * @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 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 + * 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 of the - * reversed group. + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the entity following the last entity that has the + * given components. */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return *this ? handler->rend() : reverse_iterator{}; + iterator end() const ENTT_NOEXCEPT { + return handler->end(); } /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. + * @brief Returns the first entity that has the given components, if any. + * @return The first entity that has the given components if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type front() const { + 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. + * @brief Returns the last entity that has the given components, if any. + * @return The last entity that has the given components if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; + entity_type back() const { + const auto it = std::make_reverse_iterator(end()); + return it != std::make_reverse_iterator(begin()) ? *it : null; } /** @@ -13287,8 +5092,8 @@ namespace entt { * @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{}; + iterator find(const entity_type entt) const { + const auto it = handler->find(entt); return it != end() && *it == entt ? it : end(); } @@ -13297,25 +5102,17 @@ namespace entt { * @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 { + 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); + bool contains(const entity_type entt) const { + return handler->contains(entt); } /** @@ -13327,24 +5124,23 @@ namespace entt { * @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. + * results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * group doesn't contain the given entity. * * @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), "Group does not contain entity"); + decltype(auto) get([[maybe_unused]] 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), ...); + if constexpr (sizeof...(Component) == 1) { + return (std::get*>(pools)->get(entt), ...); } else { - return std::tuple_cat(get_as_tuple(*std::get*>(pools), entt)...); + return std::tuple({}))... > {get(entt)...}; } } @@ -13372,31 +5168,36 @@ namespace entt { */ template void each(Func func) const { - for (const auto entt : *this) { - if constexpr (is_applicable_v < Func, decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))) > ) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); - } - else { - std::apply(func, get(entt)); - } - } + using get_type_list = type_list_cat_t, type_list>...>; + traverse(std::move(func), get_type_list{}); } /** - * @brief Returns an iterable object to use to _visit_ the group. + * @brief Iterates entities and components and applies the given function + * object to them. * - * 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. + * 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. * - * @return An iterable object to use to _visit_ the group. + * @tparam Func Type of the function object to invoke. + * @param func A valid function object. */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{ handler, pools }; + template + [[deprecated("use ::each instead")]] + void less(Func func) const { + each(std::move(func)); } /** @@ -13427,6 +5228,11 @@ namespace entt { * * An iterator past the last element of the range to sort. * * A comparison function to use to compare the elements. * + * @note + * Attempting to iterate elements using a raw pointer returned by a call to + * either `data` or `raw` gives no guarantees on the order, even though + * `sort` has been invoked. + * * @tparam Component Optional types of components to compare. * @tparam Compare Type of comparison function object. * @tparam Sort Type of sort function object. @@ -13437,21 +5243,19 @@ namespace entt { */ 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)...); - } + if constexpr (sizeof...(Component) == 0) { + static_assert(std::is_invocable_v); + handler->sort(handler->begin(), handler->end(), std::move(compare), std::move(algo), std::forward(args)...); + } + else if constexpr (sizeof...(Component) == 1) { + handler->sort(handler->begin(), handler->end(), [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(handler->begin(), handler->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { + return compare(std::tuple({}))... > {std::get*>(pools)->get(lhs)...}, std::tuple({}))... > {std::get*>(pools)->get(rhs)...}); + }, std::move(algo), std::forward(args)...); } } @@ -13473,14 +5277,12 @@ namespace entt { */ template void sort() const { - if (*this) { - handler->respect(*std::get*>(pools)); - } + handler->respect(*std::get*>(pools)); } private: - basic_common_type* const handler; - const std::tuple *...> pools; + sparse_set* handler; + const std::tuple *...> pools; }; @@ -13531,254 +5333,201 @@ namespace entt { * @tparam Owned Types of components owned by the group. */ template - class basic_group, get_t, Owned...> final { + class basic_group, get_t, Owned...> { /*! @brief A registry is allowed to create groups. */ friend class basic_registry; - using basic_common_type = basic_sparse_set; + template + using pool_type = std::conditional_t, const storage>, storage>; template - using storage_type = constness_as_t>::storage_type, Component>; + using component_iterator = decltype(std::declval>().begin()); - class iterable final { - template - struct iterable_iterator; - - template - struct iterable_iterator> final { - 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; - - template - iterable_iterator(It from, const std::tuple& other, const std::tuple *...>& cpools) ENTT_NOEXCEPT - : it{ from }, - owned{ std::get(other)... }, - get{ cpools } - {} - - iterable_iterator& operator++() ENTT_NOEXCEPT { - return ++it, (++std::get(owned), ...), * this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_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_iterator& other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - std::tuple owned; - std::tuple *...> get; - }; - - public: - using iterator = iterable_iterator< - typename basic_common_type::iterator, - type_list_cat_t < std::conditional_t < std::is_void_v>().get({})) > , type_list<>, type_list>().end()) >> ... > - > ; - using reverse_iterator = iterable_iterator< - typename basic_common_type::reverse_iterator, - type_list_cat_t < std::conditional_t < std::is_void_v>().get({})) > , type_list<>, type_list>().rbegin()) >> ... > - > ; - - iterable(std::tuple *..., storage_type *...> cpools, const std::size_t* const extent) - : pools{ cpools }, - length{ extent } - {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return length ? iterator{ - std::get<0>(pools)->basic_common_type::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_common_type::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_common_type::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_common_type::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 + // we could use pool_type &..., but vs complains about it and refuses to compile for unknown reasons (most likely a bug) + basic_group(const std::size_t& ref, const std::size_t& extent, storage> &... opool, storage> &... gpool) ENTT_NOEXCEPT : pools{ &opool..., &gpool... }, - length{ &extent } + length{ &extent }, + super{ &ref } {} + template + void traverse(Func func, type_list, type_list) const { + [[maybe_unused]] auto it = std::make_tuple((std::get*>(pools)->end() - *length)...); + [[maybe_unused]] auto data = std::get<0>(pools)->sparse_set::end() - *length; + + for (auto next = *length; next; --next) { + if constexpr (std::is_invocable_v < Func, decltype(get({}))..., decltype(get({}))... > ) { + if constexpr (sizeof...(Weak) == 0) { + func(*(std::get>(it)++)...); + } + else { + const auto entt = *(data++); + func(*(std::get>(it)++)..., std::get*>(pools)->get(entt)...); + } + } + else { + const auto entt = *(data++); + func(entt, *(std::get>(it)++)..., std::get*>(pools)->get(entt)...); + } + } + } + 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_common_type::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_common_type::reverse_iterator; - /*! @brief Iterable group type. */ - using iterable_group = iterable; + /*! @brief Input iterator type. */ + using iterator = typename sparse_set::iterator; - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() ENTT_NOEXCEPT - : length{} - {} + /** + * @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 + size_type size() const ENTT_NOEXCEPT { + return std::get*>(pools)->size(); + } /** * @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{}; + size_type size() const ENTT_NOEXCEPT { + return *length; } /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. + * @brief Checks whether a group or some pools are empty. + * @tparam Component Types of components in which one is interested. + * @return True if the group or the pools are empty, false otherwise. */ - [[nodiscard]] bool empty() const ENTT_NOEXCEPT { - return !*this || !*length; + template + bool empty() const ENTT_NOEXCEPT { + if constexpr (sizeof...(Component) == 0) { + return !*length; + } + else { + return (std::get*>(pools)->empty() && ...); + } } /** - * @brief Direct access to the raw representation offered by the storage. + * @brief Direct access to the list of components of a given pool. * - * @warning - * This function is only available for owned types. + * The returned pointer is such that range + * `[raw(), raw() + size()]` is always a + * valid range, even if the container is empty.
+ * Moreover, in case the group owns the given component, the range + * `[raw(), raw() + size()]` is such that it contains + * the instances that are part of the group itself. + * + * @note + * There are no guarantees on the order of the components. Use `begin` and + * `end` if you want to iterate the group in the expected order. * * @tparam Component Type of component in which one is interested. * @return A pointer to the array of components. */ template - [[nodiscard]] auto raw() const ENTT_NOEXCEPT { - static_assert((std::is_same_v || ...), "Non-owned type"); - auto* cpool = std::get*>(pools); - return cpool ? cpool->raw() : decltype(cpool->raw()){}; + Component* raw() const ENTT_NOEXCEPT { + return std::get*>(pools)->raw(); + } + + /** + * @brief Direct access to the list of entities of a given pool. + * + * The returned pointer is such that range + * `[data(), data() + size()]` is always a + * valid range, even if the container is empty.
+ * Moreover, in case the group owns the given component, the range + * `[data(), data() + size()]` is such that it + * contains the entities that are part of the group itself. + * + * @note + * There are no guarantees on the order of the entities. Use `begin` and + * `end` if you want to iterate the group in the expected order. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of entities. + */ + template + const entity_type* data() const ENTT_NOEXCEPT { + return std::get*>(pools)->data(); } /** * @brief Direct access to the list of entities. * - * The returned pointer is such that range `[data(), data() + size())` is + * The returned pointer is such that range `[data(), data() + size()]` is * always a valid range, even if the container is empty. * + * @note + * There are no guarantees on the order of the entities. Use `begin` and + * `end` if you want to iterate the group in the expected order. + * * @return A pointer to the array of entities. */ - [[nodiscard]] auto data() const ENTT_NOEXCEPT { - return *this ? std::get<0>(pools)->data() : nullptr; + const entity_type* data() const ENTT_NOEXCEPT { + return std::get<0>(pools)->data(); } /** - * @brief Returns an iterator to the first entity of the group. + * @brief Returns an iterator to the first entity that has the given + * components. * - * The returned iterator points to the first entity of the group. If the - * group is empty, the returned iterator will be equal to `end()`. + * The returned iterator points to the first entity that has the given + * components. If the group is empty, the returned iterator will be equal to + * `end()`. * - * @return An iterator to the first entity of the group. + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the first entity that has the given components. */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return *this ? (std::get<0>(pools)->basic_common_type::end() - *length) : iterator{}; + iterator begin() const ENTT_NOEXCEPT { + return std::get<0>(pools)->sparse_set::end() - *length; } /** - * @brief Returns an iterator that is past the last entity of the group. + * @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 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_common_type::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_common_type::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 + * 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 of the - * reversed group. + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the entity following the last entity that has the + * given components. */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return *this ? (std::get<0>(pools)->basic_common_type::rbegin() + *length) : reverse_iterator{}; + iterator end() const ENTT_NOEXCEPT { + return std::get<0>(pools)->sparse_set::end(); } /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. + * @brief Returns the first entity that has the given components, if any. + * @return The first entity that has the given components if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type front() const { + 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. + * @brief Returns the last entity that has the given components, if any. + * @return The last entity that has the given components if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; + entity_type back() const { + const auto it = std::make_reverse_iterator(end()); + return it != std::make_reverse_iterator(begin()) ? *it : null; } /** @@ -13787,8 +5536,8 @@ namespace entt { * @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{}; + iterator find(const entity_type entt) const { + const auto it = std::get<0>(pools)->find(entt); return it != end() && it >= begin() && *it == entt ? it : end(); } @@ -13797,25 +5546,17 @@ namespace entt { * @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 { + 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)); + bool contains(const entity_type entt) const { + return std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < (*length)); } /** @@ -13827,24 +5568,23 @@ namespace entt { * @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. + * results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * group doesn't contain the given entity. * * @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), "Group does not contain entity"); + decltype(auto) get([[maybe_unused]] 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), ...); + if constexpr (sizeof...(Component) == 1) { + return (std::get*>(pools)->get(entt), ...); } else { - return std::tuple_cat(get_as_tuple(*std::get*>(pools), entt)...); + return std::tuple({}))... > {get(entt)...}; } } @@ -13872,31 +5612,46 @@ namespace entt { */ template void each(Func func) const { - for (auto args : each()) { - if constexpr (is_applicable_v < Func, decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))) > ) { - std::apply(func, args); - } - else { - std::apply([&func](auto, auto &&... less) { func(std::forward(less)...); }, args); - } - } + using owned_type_list = type_list_cat_t, type_list>...>; + using get_type_list = type_list_cat_t, type_list>...>; + traverse(std::move(func), owned_type_list{}, get_type_list{}); } /** - * @brief Returns an iterable object to use to _visit_ the group. + * @brief Iterates entities and components and applies the given function + * object to them. * - * 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. + * 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. * - * @return An iterable object to use to _visit_ the group. + * @tparam Func Type of the function object to invoke. + * @param func A valid function object. */ - [[nodiscard]] iterable_group each() const ENTT_NOEXCEPT { - return iterable_group{ pools, length }; + template + [[deprecated("use ::each instead")]] + void less(Func func) const { + each(std::move(func)); + } + + /** + * @brief Checks whether the group can be sorted. + * @return True if the group can be sorted, false otherwise. + */ + bool sortable() const ENTT_NOEXCEPT { + constexpr auto size = sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude); + return *super == size; } /** @@ -13928,6 +5683,11 @@ namespace entt { * * An iterator past the last element of the range to sort. * * A comparison function to use to compare the elements. * + * @note + * Attempting to iterate elements using a raw pointer returned by a call to + * either `data` or `raw` gives no guarantees on the order, even though + * `sort` has been invoked. + * * @tparam Component Optional types of components to compare. * @tparam Compare Type of comparison function object. * @tparam Sort Type of sort function object. @@ -13937,21 +5697,22 @@ namespace entt { * @param args Arguments to forward to the sort function object, if any. */ template - void sort(Compare compare, Sort algo = Sort{}, Args &&... args) const { + void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { + ENTT_ASSERT(sortable()); 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)...); + static_assert(std::is_invocable_v); + cpool->sort(cpool->end() - *length, cpool->end(), 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), ...)); + cpool->sort(cpool->end() - *length, cpool->end(), [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)...)); + cpool->sort(cpool->end() - *length, cpool->end(), [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) { + return compare(std::tuple({}))... > {std::get*>(pools)->get(lhs)...}, std::tuple({}))... > {std::get*>(pools)->get(rhs)...}); }, std::move(algo), std::forward(args)...); } @@ -13961,3534 +5722,13 @@ namespace entt { [[maybe_unused]] const auto entt = head->data()[pos]; (other->swap(other->data()[pos], entt), ...); } - }(std::get*>(pools)...); + }(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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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/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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 - -// #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 -// #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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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 : std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE }; - enum class policy : std::uint8_t { OWNER, REF, CREF }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void* (const operation, const basic_any&, 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 constexpr policy type_to_policy() { - if constexpr (std::is_lvalue_reference_v) { - if constexpr (std::is_const_v>) { - return policy::CREF; - } - else { - return policy::REF; - } - } - else { - return policy::OWNER; - } - } - - 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 const void* basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any& from, [[maybe_unused]] void* to) { - static_assert(std::is_same_v>, Type>, "Invalid type"); - - if constexpr (!std::is_void_v) { - const Type* instance = (in_situ && from.mode == policy::OWNER) - ? ENTT_LAUNDER(reinterpret_cast(&from.storage)) - : static_cast(from.instance); - - switch (op) { - case operation::COPY: - if constexpr (std::is_copy_constructible_v) { - static_cast(to)->emplace(*instance); - } - break; - case operation::MOVE: - if constexpr (in_situ) { - if (from.mode == policy::OWNER) { - return new (&static_cast(to)->storage) Type{ std::move(*const_cast(instance)) }; - } - } - - return (static_cast(to)->instance = std::exchange(const_cast(from).instance, nullptr)); - case operation::DTOR: - if (from.mode == policy::OWNER) { - if constexpr (in_situ) { - instance->~Type(); - } - else if constexpr (std::is_array_v) { - delete[] instance; - } - else { - delete instance; - } - } - break; - case operation::COMP: - return compare(instance, (*static_cast(to))->data()) ? to : nullptr; - case operation::ADDR: - if (from.mode == policy::CREF) { - return nullptr; - } - [[fallthrough]]; - case operation::CADDR: - return instance; - case operation::TYPE: - *static_cast(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 (sizeof...(Args) != 0u && std::is_aggregate_v) { - new (&storage) Type{ std::forward(args)... }; - } - else { - new (&storage) Type(std::forward(args)...); - } - } - else { - if constexpr (sizeof...(Args) != 0u && std::is_aggregate_v) { - instance = new Type{ std::forward(args)... }; - } - else { - instance = new Type(std::forward(args)...); - } - } - } - } - - basic_any(const basic_any& other, const policy pol) ENTT_NOEXCEPT - : instance{ other.data() }, - vtable{ other.vtable }, - mode{ pol } - {} - - public: - /*! @brief Size of the internal storage. */ - static constexpr auto length = Len; - /*! @brief Alignment requirement. */ - static constexpr auto alignment = Align; - - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - {} - - /** - * @brief Constructs a wrapper 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>> }, - mode{ type_to_policy() } - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs a wrapper 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{} - { - // invokes deprecated assignment operator (and avoids issues with vs2017) - *this = value; - } - - /** - * @brief Constructs a wrapper 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) - : instance{}, - vtable{ &basic_vtable> }, - mode{ policy::OWNER } - { - initialize>(std::forward(value)); - } - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any& other) - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any&& other) ENTT_NOEXCEPT - : instance{}, - vtable{ other.vtable }, - mode{ other.mode } - { - 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) { - reset(); - 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) ENTT_NOEXCEPT { - std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - mode = other.mode; - 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 - [[deprecated("Use std::in_place_type, entt::make_any, emplace or forward_as_any instead")]] - 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); - mode = type_to_policy(); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - mode = policy::OWNER; - } - - /** - * @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 { - const basic_any* trampoline = &other; - return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data()); - } - - /** - * @brief Aliasing constructor. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - return basic_any{ *this, (mode == policy::CREF ? policy::CREF : policy::REF) }; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - return basic_any{ *this, policy::CREF }; - } - - /** - * @brief Returns true if a wrapper owns its object, false otherwise. - * @return True if the wrapper owns its object, false otherwise. - */ - [[nodiscard]] bool owner() const ENTT_NOEXCEPT { - return (mode == policy::OWNER); - } - - private: - union { const void* instance; storage_type storage; }; - vtable_type* vtable; - policy mode; - }; - - - /** - * @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, "Invalid 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, "Invalid 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, "Invalid 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); - } - - - /** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - * @return A properly initialized wrapper for an object of the given type. - */ - template::length, std::size_t Align = basic_any::alignment, typename... Args> - basic_any make_any(Args &&... args) { - return basic_any{std::in_place_type, std::forward(args)...}; - } - - - /** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ - template::length, std::size_t Align = basic_any::alignment, typename Type> - basic_any forward_as_any(Type&& value) { - return basic_any{std::in_place_type, std::decay_t, Type>>, std::forward(value)}; - } - - -} - - -#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 -// #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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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 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>; + const std::tuple *..., pool_type *...> pools; + const size_type* length; + const size_type* super; }; @@ -17509,8 +5749,6 @@ namespace entt { #include // #include "../config/config.h" -// #include "entity.hpp" - // #include "sparse_set.hpp" // #include "fwd.hpp" @@ -17559,17 +5797,30 @@ namespace entt { * @tparam Entity A valid entity type (see entt_traits for more details). */ template - class basic_runtime_view final { - using basic_common_type = basic_sparse_set; - using underlying_iterator = typename basic_common_type::iterator; + class basic_runtime_view { + /*! @brief A registry is allowed to create views. */ + friend class basic_registry; + + using underlying_iterator = typename sparse_set::iterator; class view_iterator final { - [[nodiscard]] bool valid() const { - const auto entt = *it; + friend class basic_runtime_view; - return (!stable_storage || (entt != tombstone)) - && std::all_of(pools->begin()++, pools->end(), [entt](const auto* curr) { return curr->contains(entt); }) - && std::none_of(filter->cbegin(), filter->cend(), [entt](const auto* curr) { return curr && curr->contains(entt); }); + using direct_type = std::vector*>; + + view_iterator(const direct_type& all, underlying_iterator curr) ENTT_NOEXCEPT + : pools{ &all }, + it{ curr } + { + if (it != (*pools)[0]->end() && !valid()) { + ++(*this); + } + } + + bool valid() const { + return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto* curr) { + return curr->contains(entt); + }); } public: @@ -17581,17 +5832,6 @@ namespace entt { view_iterator() ENTT_NOEXCEPT = default; - view_iterator(const std::vector& cpools, const std::vector& ignore, underlying_iterator curr) ENTT_NOEXCEPT - : pools{ &cpools }, - filter{ &ignore }, - it{ curr }, - stable_storage{ std::any_of(pools->cbegin(), pools->cend(), [](const basic_common_type* cpool) { return (cpool->policy() == deletion_policy::in_place); }) } - { - if (it != (*pools)[0]->end() && !valid()) { - ++(*this); - } - } - view_iterator& operator++() { while (++it != (*pools)[0]->end() && !valid()); return *this; @@ -17599,7 +5839,7 @@ namespace entt { view_iterator operator++(int) { view_iterator orig = *this; - return ++(*this), orig; + return operator++(), orig; } view_iterator& operator--() ENTT_NOEXCEPT { @@ -17612,30 +5852,39 @@ namespace entt { return operator--(), orig; } - [[nodiscard]] bool operator==(const view_iterator& other) const ENTT_NOEXCEPT { + bool operator==(const view_iterator& other) const ENTT_NOEXCEPT { return other.it == it; } - [[nodiscard]] bool operator!=(const view_iterator& other) const ENTT_NOEXCEPT { + bool operator!=(const view_iterator& other) const ENTT_NOEXCEPT { return !(*this == other); } - [[nodiscard]] pointer operator->() const { + pointer operator->() const { return it.operator->(); } - [[nodiscard]] reference operator*() const { + reference operator*() const { return *operator->(); } private: - const std::vector* pools; - const std::vector* filter; + const direct_type* pools; underlying_iterator it; - bool stable_storage; }; - [[nodiscard]] bool valid() const { + basic_runtime_view(std::vector*> others) ENTT_NOEXCEPT + : pools{ std::move(others) } + { + 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()); + } + + bool valid() const { return !pools.empty() && pools.front(); } @@ -17644,36 +5893,23 @@ namespace entt { using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = std::size_t; - /*! @brief Bidirectional iterator type. */ + /*! @brief Input 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. + * @brief Estimates the number of entities that have the given components. + * @return Estimated number of entities that have the given components. */ - basic_runtime_view(std::vector cpools, std::vector epools) ENTT_NOEXCEPT - : pools{ std::move(cpools) }, - filter{ std::move(epools) } - { - // brings the best candidate (if any) on front of the vector - std::rotate(pools.begin(), std::min_element(pools.begin(), pools.end(), [](const auto* lhs, const auto* rhs) { - return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size()); - }), pools.end()); + size_type size() const { + return valid() ? pools.front()->size() : size_type{}; } /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. + * @brief Checks if the view is definitely empty. + * @return True if the view is definitely empty, false otherwise. */ - [[nodiscard]] size_type size_hint() const { - return valid() ? pools.front()->size() : size_type{}; + bool empty() const { + return !valid() || pools.front()->empty(); } /** @@ -17684,10 +5920,20 @@ namespace entt { * components. If the view is empty, the returned iterator will be equal to * `end()`. * + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * * @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{}; + iterator begin() const { + iterator it{}; + + if (valid()) { + it = { pools, pools[0]->begin() }; + } + + return it; } /** @@ -17698,11 +5944,21 @@ namespace entt { * has the given components. Attempting to dereference the returned iterator * results in undefined behavior. * + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * * @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{}; + iterator end() const { + iterator it{}; + + if (valid()) { + it = { pools, pools[0]->end() }; + } + + return it; } /** @@ -17710,9 +5966,10 @@ namespace entt { * @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); }); + bool contains(const entity_type entt) const { + return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto* view) { + return view->find(entt) != view->end(); + }); } /** @@ -17738,8 +5995,614 @@ namespace entt { } private: - std::vector pools; - std::vector filter; + std::vector*> pools; + }; + + +} + + +#endif + +// #include "snapshot.hpp" +#ifndef ENTT_ENTITY_SNAPSHOT_HPP +#define ENTT_ENTITY_SNAPSHOT_HPP + + +#include +#include +#include +#include +#include +#include +#include +// #include "../config/config.h" + +// #include "entity.hpp" + +// #include "fwd.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 { + /*! @brief A registry is allowed to create snapshots. */ + friend class basic_registry; + + using traits_type = entt_traits>; + + template + void get(Archive& archive, std::size_t sz, It first, It last) const { + archive(typename traits_type::entity_type(sz)); + + while (first != last) { + const auto entt = *(first++); + + if (reg->template has(entt)) { + if constexpr (std::is_empty_v) { + archive(entt); + } + else { + archive(entt, reg->template 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 has(entt) ? ++size[Indexes] : size[Indexes]), ...); + } + + (get(archive, size[Indexes], 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(); + auto first = reg->data(); + const auto last = first + sz; + + archive(typename traits_type::entity_type(sz)); + + while (first != last) { + archive(*(first++)); + } + + return *this; + } + + /** + * @brief Deprecated function. Currently, it does nothing. + * @tparam Archive Type of output archive. + * @return An object of this type to continue creating the snapshot. + */ + template + [[deprecated("use ::entities instead, it exports now also destroyed entities")]] + const basic_snapshot& destroyed(Archive&) const { 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 { + (component(archive, reg->template data(), reg->template data() + reg->template size()), ...); + 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 { + /*! @brief A registry is allowed to create snapshot loaders. */ + friend class basic_registry; + + using traits_type = entt_traits>; + + template + void assign(Archive& archive, Args... args) const { + typename traits_type::entity_type length{}; + archive(length); + + while (length--) { + entity_type entt{}; + + if constexpr (std::is_empty_v) { + archive(entt); + const auto entity = reg->valid(entt) ? entt : reg->create(entt); + ENTT_ASSERT(entity == entt); + reg->template emplace(args..., entt); + } + else { + Type instance{}; + archive(entt, instance); + const auto entity = reg->valid(entt) ? entt : reg->create(entt); + ENTT_ASSERT(entity == entt); + reg->template emplace(args..., entt, std::as_const(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]); + } + + reg->assign(all.cbegin(), all.cend()); + + return *this; + } + + /** + * @brief Deprecated function. Currently, it does nothing. + * @tparam Archive Type of input archive. + * @return A valid loader to continue restoring data. + */ + template + [[deprecated("use ::entities instead, it imports now also destroyed entities")]] + const basic_snapshot_loader& destroyed(Archive&) const { 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) { + const auto it = remloc.find(entt); + + if (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 { + remloc[entt].first = 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); + 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); + + 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); + + while (length--) { + entity_type entt{}; + + if constexpr (std::is_empty_v) { + archive(entt); + restore(entt); + reg->template emplace_or_replace(map(entt)); + } + else { + Other instance{}; + archive(entt, instance); + (update(instance, member), ...); + restore(entt); + reg->template emplace_or_replace(map(entt), std::as_const(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); + } + } + + return *this; + } + + /** + * @brief Deprecated function. Currently, it does nothing. + * @tparam Archive Type of input archive. + * @return A non-const reference to this loader. + */ + template + [[deprecated("use ::entities instead, it imports now also destroyed entities")]] + basic_continuous_loader& destroyed(Archive&) { 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. + */ + bool contains(entity_type entt) const ENTT_NOEXCEPT { + return (remloc.find(entt) != remloc.cend()); + } + + /*! @copydoc contains */ + [[deprecated("use ::contains instead")]] + bool has(entity_type entt) const ENTT_NOEXCEPT { + return contains(entt); + } + + /** + * @brief Returns the identifier to which an entity refers. + * @param entt An entity identifier. + * @return The local identifier if any, the null entity otherwise. + */ + 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; }; @@ -17769,172 +6632,29 @@ namespace entt { // #include "../core/type_traits.hpp" -// #include "component.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - // #include "sparse_set.hpp" // #include "storage.hpp" // #include "utility.hpp" +// #include "entity.hpp" + +// #include "fwd.hpp" + namespace entt { /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - - namespace internal { - - - template - class view_iterator final { - using basic_common_type = basic_sparse_set::value_type>; - - [[nodiscard]] bool valid() const { - const auto entt = *it; - return Policy::accept(entt) - && std::apply([entt](const auto *... curr) { return (curr->contains(entt) && ...); }, pools) - && std::apply([entt](const auto *... curr) { return (!curr->contains(entt) && ...); }, filter); - } - - public: - using iterator_type = It; - 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 - : first{}, - last{}, - it{}, - pools{}, - filter{} - {} - - view_iterator(It from, It to, It curr, std::array all_of, std::array none_of) ENTT_NOEXCEPT - : first{ from }, - last{ to }, - it{ curr }, - pools{ all_of }, - filter{ none_of } - { - if (it != last && !valid()) { - ++(*this); - } - } - - 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; - std::array pools; - std::array filter; - }; - - - } - - - /** - * Internal details not to be documented. - * @endcond - */ - - - /*! @brief Stable storage policy, aimed at pointer stability. */ - struct stable_storage_policy { - /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - template - [[nodiscard]] static constexpr bool accept(const Entity entity) ENTT_NOEXCEPT { - return entity != tombstone; - } - /** - * Internal details not to be documented. - * @endcond - */ - }; - - - /*! @brief Packed storage policy, aimed at faster linear iteration. */ - struct packed_storage_policy { - /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - template - [[nodiscard]] static constexpr bool accept(const Entity) ENTT_NOEXCEPT { - return true; - } - /** - * Internal details not to be documented. - * @endcond - */ - }; - - - /** - * @brief View implementation. + * @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_impl; - - - /*! @brief View implementation dispatcher. */ - template - struct basic_view; + class basic_view; /** @@ -17966,145 +6686,152 @@ namespace entt { * 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 Policy Common (stricter) storage policy. * @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_impl, Component...> { - using basic_common_type = basic_sparse_set; + template + class basic_view, Component...> { + /*! @brief A registry is allowed to create views. */ + friend class basic_registry; template - using storage_type = constness_as_t>::storage_type, Comp>; + using pool_type = std::conditional_t, const storage>, storage>; - class iterable final { - template - struct iterable_iterator final { - 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; + template + using component_iterator = decltype(std::declval>().begin()); - iterable_iterator(It from, const basic_view_impl* parent) ENTT_NOEXCEPT - : it{ from }, - view{ parent } - {} + using underlying_iterator = typename sparse_set::iterator; + using unchecked_type = std::array*, (sizeof...(Component) - 1)>; + using filter_type = std::array*, sizeof...(Exclude)>; - iterable_iterator& operator++() ENTT_NOEXCEPT { - return ++it, * this; + class view_iterator final { + friend class basic_view, Component...>; + + view_iterator(const sparse_set& candidate, unchecked_type other, filter_type ignore, underlying_iterator curr) ENTT_NOEXCEPT + : view{ &candidate }, + unchecked{ other }, + filter{ ignore }, + it{ curr } + { + if (it != view->end() && !valid()) { + ++(*this); } + } - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_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_iterator& other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - const basic_view_impl* view; - }; + bool valid() const { + return std::all_of(unchecked.cbegin(), unchecked.cend(), [entt = *it](const sparse_set* curr) { return curr->contains(entt); }) + && std::none_of(filter.cbegin(), filter.cend(), [entt = *it](const sparse_set* curr) { return curr->contains(entt); }); + } public: - using iterator = iterable_iterator>; - using reverse_iterator = iterable_iterator>; + 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; - iterable(const basic_view_impl& parent) - : view{ parent } - {} + view_iterator() ENTT_NOEXCEPT = default; - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return { view.begin(), &view }; + view_iterator& operator++() { + while (++it != view->end() && !valid()); + return *this; } - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return { view.end(), &view }; + view_iterator operator++(int) { + view_iterator orig = *this; + return operator++(), orig; } - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return { view.rbegin(), &view }; + view_iterator& operator--() ENTT_NOEXCEPT { + while (--it != view->begin() && !valid()); + return *this; } - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return { view.rend(), &view }; + view_iterator operator--(int) ENTT_NOEXCEPT { + view_iterator orig = *this; + return operator--(), orig; + } + + bool operator==(const view_iterator& other) const ENTT_NOEXCEPT { + return other.it == it; + } + + bool operator!=(const view_iterator& other) const ENTT_NOEXCEPT { + return !(*this == other); + } + + pointer operator->() const { + return it.operator->(); + } + + reference operator*() const { + return *operator->(); } private: - const basic_view_impl view; + const sparse_set* view; + unchecked_type unchecked; + filter_type filter; + underlying_iterator it; }; - [[nodiscard]] const auto* candidate() const ENTT_NOEXCEPT { - return (std::min)({ static_cast(std::get*>(pools))... }, [](const auto* lhs, const auto* rhs) { + // we could use pool_type &..., but vs complains about it and refuses to compile for unknown reasons (likely a bug) + basic_view(storage> &... component, storage> &... epool) ENTT_NOEXCEPT + : pools{ &component..., &epool... } + {} + + const 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]] auto pools_to_unchecked_array() const ENTT_NOEXCEPT { + unchecked_type unchecked(const sparse_set& view) const { std::size_t pos{}; - std::array other{}; - (static_cast(std::get*>(pools) == view ? void() : void(other[pos++] = std::get*>(pools))), ...); + unchecked_type other{}; + ((std::get*>(pools) == &view ? nullptr : (other[pos++] = std::get*>(pools))), ...); return other; } - [[nodiscard]] auto filter_to_array() const ENTT_NOEXCEPT { - return std::array{std::get*>(filter)...}; - } - - 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); + template + decltype(auto) get([[maybe_unused]] component_iterator it, [[maybe_unused]] pool_type* cpool, [[maybe_unused]] const Entity entt) const { + if constexpr (std::is_same_v) { + return *it; } else { - return get_as_tuple(*std::get*>(pools), entt); + return cpool->get(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 (Policy::accept(entt) && ((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && (!std::get *>(filter)->contains(entt) && ...)) - { - if constexpr (is_applicable_v < Func, decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))) > ) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); + template + void traverse(Func func, type_list) const { + if constexpr (std::disjunction_v...>) { + auto it = std::get*>(pools)->begin(); + + for (const auto entt : static_cast&>(*std::get*>(pools))) { + auto curr = it++; + + if (((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) && (!std::get *>(pools)->contains(entt) && ...)) { + if constexpr (std::is_invocable_v < Func, decltype(get({}))... > ) { + func(get(curr, std::get*>(pools), entt)...); } else { - std::apply(func, get(entt)); + func(entt, get(curr, std::get*>(pools), entt)...); } } } } else { - auto it = std::get*>(pools)->begin(); - - for (const auto entt : static_cast(*std::get*>(pools))) { - if (Policy::accept(entt) && ((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && (!std::get *>(filter)->contains(entt) && ...)) - { - if constexpr (is_applicable_v < Func, decltype(std::tuple_cat(std::tuple{}, std::declval().get({}))) > ) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get(it, entt)...)); + for (const auto entt : static_cast&>(*std::get*>(pools))) { + if (((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) && (!std::get *>(pools)->contains(entt) && ...)) { + if constexpr (std::is_invocable_v < Func, decltype(get({}))... > ) { + func(std::get*>(pools)->get(entt)...); } else { - std::apply(func, std::tuple_cat(dispatch_get(it, entt)...)); + func(entt, std::get*>(pools)->get(entt)...); } } - - ++it; } } } @@ -18114,116 +6841,147 @@ namespace entt { using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = std::size_t; - /*! @brief Bidirectional iterator type. */ - using iterator = internal::view_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = internal::view_iterator; - /*! @brief Iterable view type. */ - using iterable_view = iterable; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view_impl() ENTT_NOEXCEPT - : view{} - {} + /*! @brief Input iterator type. */ + using iterator = view_iterator; /** - * @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_impl(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. + * @brief Returns the number of existing components of the given type. + * + * This isn't the number of entities iterated by the view. + * + * @tparam Comp Type of component of which to return the size. + * @return Number of existing components of the given type. */ template - void use() const ENTT_NOEXCEPT { - view = std::get*>(pools); + size_type size() const ENTT_NOEXCEPT { + return std::get*>(pools)->size(); } /** * @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(); + size_type size() const ENTT_NOEXCEPT { + return std::min({ std::get*>(pools)->size()... }); } /** - * @brief Returns an iterator to the first entity of the view. + * @brief Checks whether a view or some pools are empty. * - * The returned iterator points to the first entity of the view. If the view - * is empty, the returned iterator will be equal to `end()`. + * The view is definitely empty if one of the pools it uses is empty. In all + * other cases, the view may be empty and not return entities even if this + * function returns false. * - * @return An iterator to the first entity of the view. + * @tparam Comp Types of components in which one is interested. + * @return True if the view or the pools are empty, false otherwise. */ - [[nodiscard]] iterator begin() const { - return iterator{ view->begin(), view->end(), view->begin(), pools_to_unchecked_array(), filter_to_array() }; + template + bool empty() const ENTT_NOEXCEPT { + if constexpr (sizeof...(Comp) == 0) { + return (std::get*>(pools)->empty() || ...); + } + else { + return (std::get*>(pools)->empty() && ...); + } } /** - * @brief Returns an iterator that is past the last entity of the view. + * @brief Direct access to the list of components of a given pool. * - * The returned iterator points to the entity following the last entity of - * the view. Attempting to dereference the returned iterator results in - * undefined behavior. + * The returned pointer is such that range + * `[raw(), raw() + size()]` is always a valid range, even + * if the container is empty. * - * @return An iterator to the entity following the last entity of the view. + * @note + * There are no guarantees on the order of the components. Use `begin` and + * `end` if you want to iterate the view in the expected order. + * + * @tparam Comp Type of component in which one is interested. + * @return A pointer to the array of components. */ - [[nodiscard]] iterator end() const { - return iterator{ view->begin(), view->end(), view->end(), pools_to_unchecked_array(), filter_to_array() }; + template + Comp* raw() const ENTT_NOEXCEPT { + return std::get*>(pools)->raw(); } /** - * @brief Returns an iterator to the first entity of the reversed view. + * @brief Direct access to the list of entities of a given pool. * - * 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()`. + * The returned pointer is such that range + * `[data(), data() + size()]` is always a valid range, + * even if the container is empty. * - * @return An iterator to the first entity of the reversed view. + * @note + * There are no guarantees on the order of the entities. Use `begin` and + * `end` if you want to iterate the view in the expected order. + * + * @tparam Comp Type of component in which one is interested. + * @return A pointer to the array of entities. */ - [[nodiscard]] reverse_iterator rbegin() const { - return reverse_iterator{ view->rbegin(), view->rend(), view->rbegin(), pools_to_unchecked_array(), filter_to_array() }; + template + const entity_type* data() const ENTT_NOEXCEPT { + return std::get*>(pools)->data(); } /** - * @brief Returns an iterator that is past the last entity of the reversed - * view. + * @brief Returns an iterator to the first entity that has the given + * components. * - * The returned iterator points to the entity following the last entity of - * the reversed view. Attempting to dereference the returned iterator + * 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()`. + * + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the first entity that has the given components. + */ + iterator begin() const { + const auto& view = candidate(); + const filter_type ignore{ std::get*>(pools)... }; + return iterator{ view, unchecked(view), ignore, view.begin() }; + } + + /** + * @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 of the - * reversed view. + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the entity following the last entity that has the + * given components. */ - [[nodiscard]] reverse_iterator rend() const { - return reverse_iterator{ view->rbegin(), view->rend(), view->rend(), pools_to_unchecked_array(), filter_to_array() }; + iterator end() const { + const auto& view = candidate(); + const filter_type ignore{ std::get*>(pools)... }; + return iterator{ view, unchecked(view), ignore, view.end() }; } /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. + * @brief Returns the first entity that has the given components, if any. + * @return The first entity that has the given components if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type front() const { + 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. + * @brief Returns the last entity that has the given components, if any. + * @return The last entity that has the given components if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; + entity_type back() const { + const auto it = std::make_reverse_iterator(end()); + return it != std::make_reverse_iterator(begin()) ? *it : null; } /** @@ -18232,26 +6990,21 @@ namespace entt { * @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), pools_to_unchecked_array(), filter_to_array() }; + iterator find(const entity_type entt) const { + const auto& view = candidate(); + const filter_type ignore{ std::get*>(pools)... }; + iterator it{ view, unchecked(view), ignore, view.find(entt) }; 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) && ...); + bool contains(const entity_type entt) const { + return (std::get*>(pools)->contains(entt) && ...) + && (!std::get*>(pools)->contains(entt) && ...); } /** @@ -18263,24 +7016,27 @@ namespace entt { * @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. + * results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * view doesn't contain the given entity. * * @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), "View does not contain entity"); + 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)...); + static_assert(sizeof...(Component) == 1); + return (std::get*>(pools)->get(entt), ...); } else if constexpr (sizeof...(Comp) == 1) { - return (std::get*>(pools)->get(entt), ...); + return (std::get*>(pools)->get(entt), ...); } else { - return std::tuple_cat(get_as_tuple(*std::get*>(pools), entt)...); + return std::tuple({}))... > {get(entt)...}; } } @@ -18308,7 +7064,8 @@ namespace entt { */ template void each(Func func) const { - ((std::get*>(pools) == view ? traverse(std::move(func)) : void()), ...); + const auto& view = candidate(); + ((std::get*>(pools) == &view ? each(std::move(func)) : void()), ...); } /** @@ -18317,71 +7074,74 @@ namespace entt { * * 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. + * 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 Comp Type of component to use to enforce the iteration order. * @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)); + using non_empty_type = type_list_cat_t, type_list>...>; + traverse(std::move(func), non_empty_type{}); } /** - * @brief Returns an iterable object to use to _visit_ the view. + * @brief Iterates entities and components and applies the given function + * object to them. * - * 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. + * 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. * - * @return An iterable object to use to _visit_ the view. + * @tparam Func Type of the function object to invoke. + * @param func A valid function object. */ - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - return iterable_view{ *this }; + template + [[deprecated("use ::each instead")]] + void less(Func func) const { + each(std::move(func)); } /** - * @brief Returns an iterable object to use to _visit_ the view. + * @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 elements will therefore respect the order of the pool associated - * with that type. + * 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 + * @sa less * - * @tparam Comp Type of component to use to drive the iteration. - * @return An iterable object to use to _visit_ the view. + * @tparam Comp Type of component to use to enforce the iteration order. + * @tparam Func Type of the function object to invoke. + * @param func A valid function object. */ - template - [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT { - use(); - return iterable_view{ *this }; + template + [[deprecated("use ::each instead")]] + void less(Func func) const { + each(std::move(func)); } - /** - * @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_common_type* view; + const std::tuple *..., pool_type *...> pools; }; @@ -18417,218 +7177,129 @@ namespace entt { * @tparam Component Type of component iterated by the view. */ template - class basic_view_impl, Component> { - using basic_common_type = basic_sparse_set; - using storage_type = constness_as_t>::storage_type, Component>; + class basic_view, Component> { + /*! @brief A registry is allowed to create views. */ + friend class basic_registry; - class iterable final { - template - struct iterable_iterator final { - 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; + using pool_type = std::conditional_t, const storage>, storage>; - template - iterable_iterator(It... from, Discard...) ENTT_NOEXCEPT - : it{ from... } - {} - - iterable_iterator& operator++() ENTT_NOEXCEPT { - return (++std::get(it), ...), * this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return { *std::get(it)... }; - } - - [[nodiscard]] bool operator==(const iterable_iterator& other) const ENTT_NOEXCEPT { - return std::get<0>(other.it) == std::get<0>(it); - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - std::tuple it; - }; - - public: - using iterator = std::conditional_t < - std::is_void_v().get({})) > , - iterable_iterator, - iterable_iterator().begin())> - > ; - using reverse_iterator = std::conditional_t < - std::is_void_v().get({})) > , - iterable_iterator, - iterable_iterator().rbegin())> - > ; - - iterable(storage_type& ref) - : pool{ &ref } - {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return iterator{ pool->basic_common_type::begin(), pool->begin() }; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{ pool->basic_common_type::end(), pool->end() }; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return reverse_iterator{ pool->basic_common_type::rbegin(), pool->rbegin() }; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return reverse_iterator{ pool->basic_common_type::rend(), pool->rend() }; - } - - private: - storage_type* const pool; - }; + basic_view(pool_type& ref) ENTT_NOEXCEPT + : pool{ &ref } + {} 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_common_type::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_common_type::reverse_iterator; - /*! @brief Iterable view type. */ - using iterable_view = iterable; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view_impl() 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_impl(storage_type& ref) ENTT_NOEXCEPT - : pools{ &ref }, - filter{} - {} + /*! @brief Input iterator type. */ + using iterator = typename sparse_set::iterator; /** * @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(); + size_type size() const ENTT_NOEXCEPT { + return pool->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(); + bool empty() const ENTT_NOEXCEPT { + return pool->empty(); } /** - * @brief Direct access to the raw representation offered by the storage. + * @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. + * + * @note + * There are no guarantees on the order of the components. Use `begin` and + * `end` if you want to iterate the view in the expected order. + * * @return A pointer to the array of components. */ - [[nodiscard]] auto raw() const ENTT_NOEXCEPT { - return std::get<0>(pools)->raw(); + raw_type* raw() const ENTT_NOEXCEPT { + return pool->raw(); } /** * @brief Direct access to the list of entities. * - * The returned pointer is such that range `[data(), data() + size())` is + * The returned pointer is such that range `[data(), data() + size()]` is * always a valid range, even if the container is empty. * + * @note + * There are no guarantees on the order of the entities. Use `begin` and + * `end` if you want to iterate the view in the expected order. + * * @return A pointer to the array of entities. */ - [[nodiscard]] auto data() const ENTT_NOEXCEPT { - return std::get<0>(pools)->data(); + const entity_type* data() const ENTT_NOEXCEPT { + return pool->data(); } /** - * @brief Returns an iterator to the first entity of the view. + * @brief Returns an iterator to the first entity that has the given + * component. * - * The returned iterator points to the first entity of the view. If the view - * is empty, the returned iterator will be equal to `end()`. + * The returned iterator points to the first entity that has the given + * component. If the view is empty, the returned iterator will be equal to + * `end()`. * - * @return An iterator to the first entity of the view. + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the first entity that has the given component. */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_common_type::begin(); + iterator begin() const ENTT_NOEXCEPT { + return pool->sparse_set::begin(); } /** - * @brief Returns an iterator that is past the last entity of the view. + * @brief Returns an iterator that is past the last entity that has the + * given component. * - * 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_common_type::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_common_type::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 + * The returned iterator points to the entity following the last entity that + * has the given component. Attempting to dereference the returned iterator * results in undefined behavior. * - * @return An iterator to the entity following the last entity of the - * reversed view. + * @note + * Input iterators stay true to the order imposed to the underlying data + * structures. + * + * @return An iterator to the entity following the last entity that has the + * given component. */ - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return std::get<0>(pools)->basic_common_type::rend(); + iterator end() const ENTT_NOEXCEPT { + return pool->sparse_set::end(); } /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. + * @brief Returns the first entity that has the given component, if any. + * @return The first entity that has the given component if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type front() const { + 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. + * @brief Returns the last entity that has the given component, if any. + * @return The last entity that has the given component if one exists, the + * null entity otherwise. */ - [[nodiscard]] entity_type back() const { - const auto it = rbegin(); - return it != rend() ? *it : null; + entity_type back() const { + const auto it = std::make_reverse_iterator(end()); + return it != std::make_reverse_iterator(begin()) ? *it : null; } /** @@ -18637,8 +7308,8 @@ namespace entt { * @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); + iterator find(const entity_type entt) const { + const auto it = pool->find(entt); return it != end() && *it == entt ? it : end(); } @@ -18647,25 +7318,17 @@ namespace entt { * @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 { + 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); + bool contains(const entity_type entt) const { + return pool->contains(entt); } /** @@ -18675,25 +7338,19 @@ namespace entt { * 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. + * Attempting to use an entity that doesn't belong to the view results in + * undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * view doesn't contain the given entity. * - * @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), "View does not contain entity"); - - 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); - } + template + decltype(auto) get(const entity_type entt) const { + static_assert(std::is_same_v); + ENTT_ASSERT(contains(entt)); + return pool->get(entt); } /** @@ -18720,111 +7377,46 @@ namespace entt { */ template void each(Func func) const { - if constexpr (std::is_void_v(pools)->get({})) > ) { + if constexpr (ENTT_IS_EMPTY(Component)) { if constexpr (std::is_invocable_v) { - for (auto pos = size(); pos; --pos) { + for (auto pos = pool->size(); pos; --pos) { func(); } } else { - for (auto entity : *this) { - func(entity); + for (const auto entt : *this) { + func(entt); } } } else { - if constexpr (is_applicable_v) { - for (const auto pack : each()) { - std::apply(func, pack); + if constexpr (std::is_invocable_v < Func, decltype(get({})) > ) { + for (auto&& component : *pool) { + func(component); } } else { - for (auto&& component : *std::get<0>(pools)) { - func(component); + auto raw = pool->begin(); + + for (const auto entt : *this) { + func(entt, *(raw++)); } } } } - /** - * @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) }; + /*! @copydoc each */ + template + [[deprecated("use ::each instead")]] + void less(Func func) const { + each(std::move(func)); } - /** - * @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; + pool_type* pool; }; - /** - * @brief View implementation dispatcher. - * @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 - struct basic_view, Component...> - : basic_view_impl>::in_place_delete...>, stable_storage_policy, packed_storage_policy>, Entity, exclude_t, Component...> - { - /*! @brief Most restrictive storage policy of all component types. */ - using storage_policy = std::conditional_t>::in_place_delete...>, stable_storage_policy, packed_storage_policy>; - using basic_view_impl, Component...>::basic_view_impl; - }; - - - /** - * @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)); - } - - } @@ -18847,16 +7439,92 @@ namespace entt { */ template class basic_registry { - using traits_type = entt_traits; - using poly_storage_type = typename poly_storage_traits::storage_type; - using basic_common_type = basic_sparse_set; + using traits_type = entt_traits>; template - using storage_type = constness_as_t>::storage_type, Component>; + struct pool_handler final : storage { + static_assert(std::is_same_v>); + std::size_t super{}; + + auto on_construct() ENTT_NOEXCEPT { + return sink{ construction }; + } + + auto on_update() ENTT_NOEXCEPT { + return sink{ update }; + } + + auto on_destroy() ENTT_NOEXCEPT { + return sink{ destruction }; + } + + template + decltype(auto) emplace(basic_registry& owner, const Entity entt, Args &&... args) { + storage::emplace(entt, std::forward(args)...); + construction.publish(owner, entt); + + if constexpr (!ENTT_IS_EMPTY(Component)) { + return this->get(entt); + } + } + + template + void insert(basic_registry& owner, It first, It last, Args &&... args) { + storage::insert(first, last, std::forward(args)...); + + if (!construction.empty()) { + while (first != last) { construction.publish(owner, *(first++)); } + } + } + + void remove(basic_registry& owner, const Entity entt) { + destruction.publish(owner, entt); + this->erase(entt); + } + + template + void remove(basic_registry& owner, It first, It last) { + if (std::distance(first, last) == std::distance(this->begin(), this->end())) { + if (!destruction.empty()) { + while (first != last) { destruction.publish(owner, *(first++)); } + } + + this->clear(); + } + else { + while (first != last) { this->remove(owner, *(first++)); } + } + } + + template + decltype(auto) patch(basic_registry& owner, const Entity entt, Func &&... func) { + (std::forward(func)(this->get(entt)), ...); + update.publish(owner, entt); + + if constexpr (!ENTT_IS_EMPTY(Component)) { + return this->get(entt); + } + } + + decltype(auto) replace(basic_registry& owner, const Entity entt, [[maybe_unused]] Component component) { + if constexpr (ENTT_IS_EMPTY(Component)) { + return patch(owner, entt); + } + else { + return patch(owner, entt, [&component](auto&& curr) { curr = std::move(component); }); + } + } + + private: + sigh construction{}; + sigh destruction{}; + sigh update{}; + }; struct pool_data { - poly_storage_type poly; - std::unique_ptr pool{}; + id_type type_id{}; + std::unique_ptr> pool{}; + void(*remove)(sparse_set&, basic_registry&, const Entity) {}; }; template @@ -18864,17 +7532,17 @@ namespace entt { template struct group_handler, get_t, Owned...> { - static_assert(!std::disjunction_v::in_place_delete...>, "Groups do not support in-place delete"); - static_assert(std::conjunction_v>..., std::is_same>..., std::is_same>...>, "One or more component types are invalid"); - std::conditional_t current{}; + static_assert(std::conjunction_v>..., std::is_same>..., std::is_same>...>); + 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()...); + static_assert(std::disjunction_v>..., std::is_same>..., std::is_same>...>); + [[maybe_unused]] const auto cpools = std::forward_as_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)) && ...); + 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)) { @@ -18882,21 +7550,23 @@ namespace entt { } } else { - if (is_valid && !(std::get<0>(cpools)->index(entt) < current)) { + if (is_valid && !(std::get<0>(cpools).index(entt) < current)) { const auto pos = current++; - (std::get*>(cpools)->swap(std::get*>(cpools)->data()[pos], entt), ...); + (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) { - current.remove(entt); + if (current.contains(entt)) { + current.erase(entt); + } } else { - if (const auto cpools = std::make_tuple(owner.assure()...); std::get<0>(cpools)->contains(entt) && (std::get<0>(cpools)->index(entt) < current)) { + if (const auto cpools = std::forward_as_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), ...); + (std::get&>(cpools).swap(std::get&>(cpools).data()[pos], entt), ...); } } } @@ -18910,47 +7580,55 @@ namespace entt { bool (*exclude)(const id_type) ENTT_NOEXCEPT; }; + struct variable_data { + id_type type_id; + std::unique_ptr value; + }; + template - [[nodiscard]] storage_type* assure() const { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - const auto index = type_seq::value(); + const pool_handler& assure() const { + static_assert(std::is_same_v>); - if (!(index < pools.size())) { - pools.resize(size_type(index) + 1u); + if constexpr (has_type_index_v) { + const auto index = type_index::value(); + + if (!(index < pools.size())) { + pools.resize(index + 1); + } + + if (auto&& pdata = pools[index]; !pdata.pool) { + pdata.type_id = type_info::id(); + pdata.pool.reset(new pool_handler()); + pdata.remove = [](sparse_set& cpool, basic_registry& owner, const entity_type entt) { + static_cast&>(cpool).remove(owner, entt); + }; + } + + return static_cast &>(*pools[index].pool); } + else { + sparse_set* candidate{ nullptr }; - if (auto&& pdata = pools[index]; !pdata.pool) { - pdata.pool.reset(new storage_type()); - pdata.poly.template emplace&>(*static_cast *>(pdata.pool.get())); + if (auto it = std::find_if(pools.begin(), pools.end(), [id = type_info::id()](const auto& pdata) { return id == pdata.type_id; }); it == pools.cend()) { + candidate = pools.emplace_back(pool_data{ + type_info::id(), + std::unique_ptr>{new pool_handler()}, + [](sparse_set& cpool, basic_registry& owner, const entity_type entt) { + static_cast&>(cpool).remove(owner, entt); + } + }).pool.get(); + } + else { + candidate = it->pool.get(); + } + + return static_cast &>(*candidate); } - - return static_cast *>(pools[index].pool.get()); } template - [[nodiscard]] const storage_type* pool_if_exists() const ENTT_NOEXCEPT { - 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()); - } - - auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT { - ENTT_ASSERT(pos < traits_type::to_integral(null), "No entities available"); - return traits_type::construct(static_cast(pos), {}); - } - - auto recycle_identifier() ENTT_NOEXCEPT { - ENTT_ASSERT(free_list != null, "No entities available"); - const auto curr = traits_type::to_entity(free_list); - free_list = (tombstone | entities[curr]); - return (entities[curr] = traits_type::construct(curr, traits_type::to_version(entities[curr]))); - } - - auto release_entity(const Entity entity, const typename traits_type::version_type version) { - const typename traits_type::version_type vers = version + (version == traits_type::to_version(tombstone)); - entities[traits_type::to_entity(entity)] = traits_type::construct(traits_type::to_entity(free_list), vers); - free_list = (tombstone | entity); - return vers; + pool_handler& assure() { + return const_cast &>(std::as_const(*this).template assure()); } public: @@ -18960,26 +7638,6 @@ namespace entt { 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 traits_type::construct(traits_type::to_entity(entity), {}); - } - - /** - * @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 traits_type::to_version(entity); - } /*! @brief Default constructor. */ basic_registry() = default; @@ -18996,25 +7654,7 @@ namespace entt { */ 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, "Storage not available"); - 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, "Storage not available"); - return pools[info.seq()].poly; + assure(); } /** @@ -19023,16 +7663,15 @@ namespace entt { * @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{}; + size_type size() const { + return assure().size(); } /** * @brief Returns the number of entities created so far. * @return Number of entities created so far. */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { + size_type size() const ENTT_NOEXCEPT { return entities.size(); } @@ -19040,11 +7679,12 @@ namespace entt { * @brief Returns the number of entities still in use. * @return Number of entities still in use. */ - [[nodiscard]] size_type alive() const { + size_type alive() const { auto sz = entities.size(); + auto curr = destroyed; - for (auto curr = free_list; curr != null; --sz) { - curr = entities[traits_type::to_entity(curr)]; + for (; curr != null; --sz) { + curr = entities[to_integral(curr) & traits_type::entity_mask]; } return sz; @@ -19069,28 +7709,18 @@ namespace entt { entities.reserve(cap); } else { - (assure()->reserve(cap), ...); + (assure().reserve(cap), ...); } } - /** - * @brief Reserves enough space to store `count` pools. - * @param count Number of pools to reserve space for. - */ - [[deprecated("No longer supported")]] - 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{}; + size_type capacity() const { + return assure().capacity(); } /** @@ -19098,7 +7728,7 @@ namespace entt { * allocated space for. * @return Capacity of the registry. */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { + size_type capacity() const ENTT_NOEXCEPT { return entities.capacity(); } @@ -19109,7 +7739,7 @@ namespace entt { */ template void shrink_to_fit() { - (assure()->shrink_to_fit(), ...); + (assure().shrink_to_fit(), ...); } /** @@ -19124,19 +7754,65 @@ namespace entt { * empty, false otherwise. */ template - [[nodiscard]] bool empty() const { + bool empty() const { if constexpr (sizeof...(Component) == 0) { return !alive(); } else { - return [](const auto *... cpool) { return ((!cpool || cpool->empty()) && ...); }(pool_if_exists()...); + return (assure().empty() && ...); } } + /** + * @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. + * + * There are no guarantees on the order of the components. Use a view if you + * want to iterate entities and components in the expected order. + * + * @note + * Empty components aren't explicitly instantiated. Therefore, this function + * isn't available for them. A compilation error will occur if invoked. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of components of the given type. + */ + template + const Component* raw() const { + return assure().raw(); + } + + /*! @copydoc raw */ + template + Component* raw() { + return const_cast(std::as_const(*this).template raw()); + } + + /** + * @brief Direct access to the list of entities of a given pool. + * + * The returned pointer is such that range + * `[data(), data() + size()]` is always a + * valid range, even if the container is empty. + * + * There are no guarantees on the order of the entities. Use a view if you + * want to iterate entities and components in the expected order. + * + * @tparam Component Type of component in which one is interested. + * @return A pointer to the array of entities. + */ + template + const entity_type* data() const { + return assure().data(); + } + /** * @brief Direct access to the list of entities of a registry. * - * The returned pointer is such that range `[data(), data() + size())` is + * The returned pointer is such that range `[data(), data() + size()]` is * always a valid range, even if the container is empty. * * @warning @@ -19145,53 +7821,55 @@ namespace entt { * * @return A pointer to the array of entities. */ - [[nodiscard]] const entity_type* data() const ENTT_NOEXCEPT { + const entity_type* data() const ENTT_NOEXCEPT { return entities.data(); } - /** - * @brief Returns the head of the list of released 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 released entities. - */ - [[nodiscard]] entity_type released() const ENTT_NOEXCEPT { - return free_list; - } - - /*! @copydoc released */ - [[deprecated("Use ::released instead")]] - [[nodiscard]] entity_type destroyed() const ENTT_NOEXCEPT { - return released(); - } - /** * @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(traits_type::to_entity(entity)); + 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 entity identifier without the version. + * @param entity An entity identifier, either valid or not. + * @return The entity identifier without the version. + */ + 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. + */ + static version_type version(const entity_type entity) ENTT_NOEXCEPT { + return version_type(to_integral(entity) >> traits_type::entity_shift); + } + /** * @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. + * been previously destroyed and/or recycled.
+ * An assertion will abort the execution at runtime in debug mode if the + * registry doesn't own the given entity. * * @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(traits_type::to_entity(entity)); - ENTT_ASSERT(pos < entities.size(), "Entity does not exist"); - return version(entities[pos]); + 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_type(to_integral(entities[pos]) >> traits_type::entity_shift); } /** @@ -19204,8 +7882,22 @@ namespace entt { * * @return A valid entity identifier. */ - [[nodiscard]] entity_type create() { - return (free_list == null) ? entities.emplace_back(generate_identifier(entities.size())) : recycle_identifier(); + entity_type create() { + entity_type entt; + + if (destroyed == null) { + entt = entities.emplace_back(entity_type(entities.size())); + // traits_type::entity_mask is reserved to allow for null identifiers + ENTT_ASSERT(to_integral(entt) < traits_type::entity_mask); + } + else { + const auto curr = to_integral(destroyed); + const auto version = to_integral(entities[curr]) & (traits_type::version_mask << traits_type::entity_shift); + destroyed = entity_type{ to_integral(entities[curr]) & traits_type::entity_mask }; + entt = entities[curr] = entity_type{ curr | version }; + } + + return entt; } /** @@ -19214,35 +7906,36 @@ namespace entt { * @sa create * * If the requested entity isn't in use, the suggested identifier is created - * and returned. Otherwise, a new identifier is generated. + * and returned. Otherwise, a new one will be generated for this purpose. * - * @param hint Required entity identifier. + * @param hint A desired entity identifier. * @return A valid entity identifier. */ - [[nodiscard]] entity_type create(const entity_type hint) { - const auto length = entities.size(); + entity_type create(const entity_type hint) { + ENTT_ASSERT(hint != null); + entity_type entt; - if (hint == null || hint == tombstone) { - return create(); - } - else if (const auto req = traits_type::to_entity(hint); !(req < length)) { - entities.resize(size_type(req) + 1u, null); + if (const auto req = (to_integral(hint) & traits_type::entity_mask); !(req < entities.size())) { + entities.reserve(req + 1); - for (auto pos = length; pos < req; ++pos) { - release_entity(generate_identifier(pos), {}); + for (auto pos = entities.size(); pos < req; ++pos) { + entities.emplace_back(destroyed); + destroyed = entity_type(pos); } - return (entities[req] = hint); + entt = entities.emplace_back(hint); } - else if (const auto curr = traits_type::to_entity(entities[req]); req == curr) { - return create(); + else if (const auto curr = (to_integral(entities[req]) & traits_type::entity_mask); req == curr) { + entt = create(); } else { - auto* it = &free_list; - for (; traits_type::to_entity(*it) != req; it = &entities[traits_type::to_entity(*it)]); - *it = traits_type::construct(curr, traits_type::to_version(*it)); - return (entities[req] = hint); + auto* it = &destroyed; + 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; } /** @@ -19256,133 +7949,74 @@ namespace entt { */ template void create(It first, It last) { - for (; free_list != null && first != last; ++first) { - *first = recycle_identifier(); - } - - const auto length = entities.size(); - entities.resize(length + std::distance(first, last), null); - - for (auto pos = length; first != last; ++first, ++pos) { - *first = entities[pos] = generate_identifier(pos); - } + std::generate(first, last, [this]() { return create(); }); } /** * @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. + * This function is intended for use in conjunction with `raw`.
+ * Don't try to inject ranges of randomly generated 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. + * An assertion will abort the execution at runtime in debug mode if all + * pools aren't empty. * * @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 still alive"); + void assign(It first, It last) { + ENTT_ASSERT(std::all_of(pools.cbegin(), pools.cend(), [](auto&& pdata) { return !pdata.pool || pdata.pool->empty(); })); entities.assign(first, last); - free_list = destroyed; - } + destroyed = null; - /** - * @brief Releases an entity identifier. - * - * The version is updated and the identifier can be recycled at any time. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @param entity A valid entity identifier. - * @return The version of the recycled entity. - */ - version_type release(const entity_type entity) { - return release(entity, version(entity) + 1u); - } - - /** - * @brief Releases an entity identifier. - * - * The suggested version or the valid version closest to the suggested one - * is used instead of the implicitly generated version. - * - * @sa release - * - * @param entity A valid entity identifier. - * @param version A desired version upon destruction. - * @return The version actually assigned to the entity. - */ - version_type release(const entity_type entity, const version_type version) { - ENTT_ASSERT(orphan(entity), "Non-orphan entity"); - return release_entity(entity, version); - } - - /** - * @brief Releases all entity identifiers in a range. - * - * @sa release - * - * @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 release(It first, It last) { - for (; first != last; ++first) { - release(*first, version(*first) + 1u); + for (std::size_t pos{}, end = entities.size(); pos < end; ++pos) { + if ((to_integral(entities[pos]) & traits_type::entity_mask) != pos) { + const auto version = to_integral(entities[pos]) & (traits_type::version_mask << traits_type::entity_shift); + entities[pos] = entity_type{ to_integral(destroyed) | version }; + destroyed = entity_type(pos); + } } } /** - * @brief Destroys an entity and releases its identifier. + * @brief Destroys an entity. * - * The version is updated and the identifier can be recycled at any time. + * When an entity is destroyed, its version is updated and the identifier + * can be recycled at any time. * - * @warning - * Adding or removing components to an entity that is being destroyed can - * result in undefined behavior. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. + * @sa remove_all * * @param entity A valid entity identifier. - * @return The version of the recycled entity. */ - version_type destroy(const entity_type entity) { - return destroy(entity, version(entity) + 1u); + void destroy(const entity_type entity) { + destroy(entity, (to_integral(entity) >> traits_type::entity_shift) + 1); } /** - * @brief Destroys an entity and releases its identifier. + * @brief Destroys an entity. * - * The suggested version or the valid version closest to the suggested one - * is used instead of the implicitly generated version. + * If the entity isn't already destroyed, the suggested version is used + * instead of the implicitly generated one. * - * @sa destroy + * @sa remove_all * * @param entity A valid entity identifier. * @param version A desired version upon destruction. - * @return The version actually assigned to the entity. */ - version_type destroy(const entity_type entity, const version_type version) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - - for (auto&& pdata : pools) { - pdata.pool&& pdata.pool->remove(entity, this); - } - - return release_entity(entity, version); + void destroy(const entity_type entity, const version_type version) { + remove_all(entity); + // lengthens the implicit list of destroyed entities + const auto entt = to_integral(entity) & traits_type::entity_mask; + entities[entt] = entity_type{ to_integral(destroyed) | (version << traits_type::entity_shift) }; + destroyed = entity_type{ entt }; } /** - * @brief Destroys all entities in a range and releases their identifiers. + * @brief Destroys all the entities in a range. * * @sa destroy * @@ -19392,18 +8026,7 @@ namespace entt { */ template void destroy(It first, It last) { - if constexpr (is_iterator_type_v) { - for (; first != last; ++first) { - destroy(*first, version(*first) + 1u); - } - } - else { - for (auto&& pdata : pools) { - pdata.pool&& pdata.pool->remove(first, last, this); - } - - release(first, last); - } + while (first != last) { destroy(*(first++)); } } /** @@ -19415,7 +8038,10 @@ namespace entt { * * @warning * Attempting to use an invalid entity or to assign a component to an entity - * that already owns it results in undefined behavior. + * that already owns it results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity or if the entity already owns an instance of the given + * component. * * @tparam Component Type of component to create. * @tparam Args Types of arguments to use to construct the component. @@ -19425,8 +8051,15 @@ namespace entt { */ template decltype(auto) emplace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - return assure()->emplace(*this, entity, std::forward(args)...); + ENTT_ASSERT(valid(entity)); + return assure().emplace(*this, entity, std::forward(args)...); + } + + /*! @copydoc emplace */ + template + [[deprecated("use ::emplace instead")]] + decltype(auto) assign(const entity_type entity, Args &&... args) { + return emplace(entity, std::forward(args)...); } /** @@ -19442,8 +8075,16 @@ namespace entt { */ template void insert(It first, It last, const Component& value = {}) { - ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); }), "Invalid entity"); - assure()->insert(*this, first, last, value); + ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); + assure().insert(*this, first, last, value); + } + + /*! @copydoc insert */ + template + [[deprecated("use ::insert instead")]] + std::enable_if_t::value_type, entity_type>, void> + assign(It first, It last, const Component& value = {}) { + return insert(std::move(first), std::move(last), value); } /** @@ -19457,12 +8098,21 @@ namespace entt { * @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::value_type>, Component>>> - void insert(EIt first, EIt last, CIt from) { - 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); }), "Invalid entity"); - assure()->insert(*this, first, last, from); + template + void insert(EIt first, EIt last, CIt from, CIt to) { + static_assert(std::is_constructible_v::value_type>); + ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); + assure().insert(*this, first, last, from, to); + } + + /*! @copydoc insert */ + template + [[deprecated("use ::insert instead")]] + std::enable_if_t::value_type, entity_type>, void> + assign(EIt first, EIt last, CIt value) { + return insert(std::move(first), std::move(last), value, value + std::distance(first, last)); } /** @@ -19471,13 +8121,15 @@ namespace entt { * Equivalent to the following snippet (pseudocode): * * @code{.cpp} - * auto &component = registry.all_of(entity) ? registry.replace(entity, args...) : registry.emplace(entity, args...); + * auto &component = registry.has(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. + * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity. * * @tparam Component Type of component to assign or replace. * @tparam Args Types of arguments to use to construct the component. @@ -19487,12 +8139,19 @@ namespace entt { */ template decltype(auto) emplace_or_replace(const entity_type entity, Args &&... args) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - auto* cpool = assure(); + 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)...); + return cpool.contains(entity) + ? cpool.replace(*this, entity, Component{ std::forward(args)... }) + : cpool.emplace(*this, entity, std::forward(args)...); + } + + /*! @copydoc emplace_or_replace */ + template + [[deprecated("use ::emplace_or_replace instead")]] + decltype(auto) assign_or_replace(const entity_type entity, Args &&... args) { + return emplace_or_replace(entity, std::forward(args)...); } /** @@ -19511,7 +8170,10 @@ namespace entt { * * @warning * Attempting to use an invalid entity or to patch a component of an entity - * that doesn't own it results in undefined behavior. + * that doesn't own it results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity or if the entity doesn't own an instance of the given + * component. * * @tparam Component Type of component to patch. * @tparam Func Types of the function objects to invoke. @@ -19521,8 +8183,16 @@ namespace entt { */ template decltype(auto) patch(const entity_type entity, Func &&... func) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - return assure()->patch(*this, entity, std::forward(func)...); + ENTT_ASSERT(valid(entity)); + return assure().patch(*this, entity, std::forward(func)...); + } + + /*! @copydoc patch */ + template + [[deprecated("use registry::patch instead")]] + auto replace(const entity_type entity, Func &&... func) + -> decltype((func(std::declval()), ...), assign(entity)) { + return patch(entity, std::forward(func)...); } /** @@ -19534,7 +8204,10 @@ namespace entt { * * @warning * Attempting to use an invalid entity or to replace a component of an - * entity that doesn't own it results in undefined behavior. + * entity that doesn't own it results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity or if the entity doesn't own an instance of the given + * component. * * @tparam Component Type of component to replace. * @tparam Args Types of arguments to use to construct the component. @@ -19543,114 +8216,74 @@ namespace entt { * @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)... }), ...); }); + auto replace(const entity_type entity, Args &&... args) + -> decltype(std::enable_if_t(), Component{ std::forward(args)... }, assure().get(entity)) { + return assure().replace(*this, entity, Component{ std::forward(args)... }); } /** * @brief Removes the given components from an entity. * * @warning - * Attempting to use an invalid entity results in undefined behavior. + * Attempting to use an invalid entity or to remove a component from an + * entity that doesn't own it results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity or if the entity doesn't own an instance of the given + * component. * * @tparam Component Types of components to remove. * @param entity A valid entity identifier. - * @return The number of components actually removed. */ template - size_type remove(const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - return (assure()->remove(entity, this) + ... + size_type{}); + void remove(const entity_type entity) { + ENTT_ASSERT(valid(entity)); + (assure().remove(*this, entity), ...); } /** * @brief Removes the given components from all the entities in a range. * - * @sa remove + * @see 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. - * @return The number of components actually removed. */ template - size_type remove(It first, It last) { - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - const auto cpools = std::make_tuple(assure()...); - size_type count{}; - - for (; first != last; ++first) { - const auto entity = *first; - ENTT_ASSERT(valid(entity), "Invalid entity"); - count += (std::get*>(cpools)->remove(entity, this) + ...); - } - - return count; + void remove(It first, It last) { + ENTT_ASSERT(std::all_of(first, last, [this](const auto entity) { return valid(entity); })); + (assure().remove(*this, first, last), ...); } /** - * @brief Erases the given components from an entity. + * @brief Removes the given components from an entity. + * + * Equivalent to the following snippet (pseudocode): + * + * @code{.cpp} + * if(registry.has(entity)) { registry.remove(entity) } + * @endcode + * + * Prefer this function anyway because it has slightly better performance. * * @warning - * Attempting to use an invalid entity or to erase a component from an - * entity that doesn't own it results in undefined behavior. + * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity. * - * @tparam Component Types of components to erase. + * @tparam Component Types of components to remove. * @param entity A valid entity identifier. */ template - void erase(const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - (assure()->erase(entity, this), ...); - } + void remove_if_exists(const entity_type entity) { + ENTT_ASSERT(valid(entity)); - /** - * @brief Erases the given components from all the entities in a range. - * - * @sa erase - * - * @tparam Component Types of components to erase. - * @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 erase(It first, It last) { - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - const auto cpools = std::make_tuple(assure()...); - - for (; first != last; ++first) { - const auto entity = *first; - ENTT_ASSERT(valid(entity), "Invalid entity"); - (std::get*>(cpools)->erase(entity, this), ...); - } - } - - /** - * @brief Removes all tombstones from a registry or only the pools for the - * given components. - * @tparam Component Types of components for which to clear all tombstones. - */ - template - void compact() { - if constexpr (sizeof...(Component) == 0) { - for (auto&& pdata : pools) { - pdata.pool && (pdata.pool->compact(), true); + ([this, entity](auto&& cpool) { + if (cpool.contains(entity)) { + cpool.remove(*this, entity); } - } - else { - (assure()->compact(), ...); - } - } - - /*! @copydoc remove */ - template - [[deprecated("Use ::remove instead")]] - size_type remove_if_exists(const entity_type entity) { - return remove(entity); + }(assure()), ...); } /** @@ -19660,19 +8293,23 @@ namespace entt { * 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. + * could lead to undefined behavior. An assertion will abort the execution + * at runtime in debug mode if a violation is detected. * * @warning - * Attempting to use an invalid entity results in undefined behavior. + * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity. * * @param entity A valid entity identifier. */ - [[deprecated("Use ::destroy(entity)/::create(entity) instead")]] void remove_all(const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); + ENTT_ASSERT(valid(entity)); - for (auto&& pdata : pools) { - pdata.pool&& pdata.pool->remove(entity, this); + for (auto pos = pools.size(); pos; --pos) { + if (auto& pdata = pools[pos - 1]; pdata.pool && pdata.pool->contains(entity)) { + pdata.remove(*pdata.pool, *this, entity); + } } } @@ -19680,23 +8317,27 @@ namespace entt { * @brief Checks if an entity has all the given components. * * @warning - * Attempting to use an invalid entity results in undefined behavior. + * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity. * * @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), "Invalid entity"); - return [entity](const auto *... cpool) { return ((cpool && cpool->contains(entity)) && ...); }(pool_if_exists()...); + bool has(const entity_type entity) const { + ENTT_ASSERT(valid(entity)); + return (assure().contains(entity) && ...); } /** * @brief Checks if an entity has at least one of the given components. * * @warning - * Attempting to use an invalid entity results in undefined behavior. + * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity. * * @tparam Component Components for which to perform the check. * @param entity A valid entity identifier. @@ -19704,9 +8345,9 @@ namespace entt { * false otherwise. */ template - [[nodiscard]] bool any_of(const entity_type entity) const { - ENTT_ASSERT(valid(entity), "Invalid entity"); - return [entity](const auto *... cpool) { return !((!cpool || !cpool->contains(entity)) && ...); }(pool_if_exists()...); + bool any(const entity_type entity) const { + ENTT_ASSERT(valid(entity)); + return (assure().contains(entity) || ...); } /** @@ -19714,20 +8355,21 @@ namespace entt { * * @warning * Attempting to use an invalid entity or to get a component from an entity - * that doesn't own it results in undefined behavior. + * that doesn't own it results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity or if the entity doesn't own an instance of the given + * component. * * @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), "Invalid entity"); + 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, "Storage not available"); - return cpool->get(entity); + return (assure().get(entity), ...); } else { return std::forward_as_tuple(get(entity)...); @@ -19736,11 +8378,11 @@ namespace entt { /*! @copydoc get */ template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); + decltype(auto) get([[maybe_unused]] const entity_type entity) { + ENTT_ASSERT(valid(entity)); if constexpr (sizeof...(Component) == 1) { - return (const_cast(assure>()->get(entity)), ...); + return (assure().get(entity), ...); } else { return std::forward_as_tuple(get(entity)...); @@ -19755,13 +8397,15 @@ namespace entt { * Equivalent to the following snippet (pseudocode): * * @code{.cpp} - * auto &component = registry.all_of(entity) ? registry.get(entity) : registry.emplace(entity, args...); + * auto &component = registry.has(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. + * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity. * * @tparam Component Type of component to get. * @tparam Args Types of arguments to use to construct the component. @@ -19770,32 +8414,37 @@ namespace entt { * @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), "Invalid entity"); - auto* cpool = assure(); - return cpool->contains(entity) ? cpool->get(entity) : cpool->emplace(*this, entity, std::forward(args)...); + 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)...); + } + + /*! @copydoc get_or_emplace */ + template + [[deprecated("use ::get_or_emplace instead")]] + decltype(auto) get_or_assign(const entity_type entity, Args &&... args) { + return get_or_emplace(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. + * Attempting to use an invalid entity results in undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid entity. * * @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), "Invalid entity"); + 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; + return (assure().try_get(entity), ...); } else { return std::make_tuple(try_get(entity)...); @@ -19804,11 +8453,11 @@ namespace entt { /*! @copydoc try_get */ template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); + 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)), ...); + return (assure().try_get(entity), ...); } else { return std::make_tuple(try_get(entity)...); @@ -19822,14 +8471,13 @@ namespace entt { template void clear() { if constexpr (sizeof...(Component) == 0) { - for (auto&& pdata : pools) { - pdata.pool && (pdata.pool->clear(this), true); - } - - each([this](const auto entity) { release_entity(entity, version(entity) + 1u); }); + // useless this-> used to suppress a warning with clang + each([this](const auto entity) { this->destroy(entity); }); } else { - (assure()->clear(this), ...); + ([this](auto&& cpool) { + cpool.remove(*this, cpool.sparse_set::begin(), cpool.sparse_set::end()); + }(assure()), ...); } } @@ -19852,15 +8500,17 @@ namespace entt { */ template void each(Func func) const { - if (free_list == null) { + static_assert(std::is_invocable_v); + + if (destroyed == 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]; traits_type::to_entity(entity) == (pos - 1)) { - func(entity); + if (const auto entt = entities[pos - 1]; (to_integral(entt) & traits_type::entity_mask) == (pos - 1)) { + func(entt); } } } @@ -19871,8 +8521,8 @@ namespace entt { * @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), "Invalid entity"); + 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); }); } @@ -19894,6 +8544,8 @@ namespace entt { */ template void orphans(Func func) const { + static_assert(std::is_invocable_v); + each([this, &func](const auto entity) { if (orphan(entity)) { func(entity); @@ -19904,13 +8556,15 @@ namespace entt { /** * @brief Returns a sink object for the given component. * + * A sink is an opaque object used to connect listeners to components.
* 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.
+ * an entity. + * * The function type for a listener is equivalent to: * * @code{.cpp} - * void(basic_registry &, Entity); + * void(registry &, Entity); * @endcode * * Listeners are invoked **after** the component has been assigned to the @@ -19922,19 +8576,21 @@ namespace entt { * @return A temporary sink object. */ template - [[nodiscard]] auto on_construct() { - return assure()->on_construct(); + auto on_construct() { + return assure().on_construct(); } /** * @brief Returns a sink object for the given component. * + * A sink is an opaque object used to connect listeners to components.
* The sink returned by this function can be used to receive notifications - * whenever an instance of the given component is explicitly updated.
+ * 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); + * void(registry &, Entity); * @endcode * * Listeners are invoked **after** the component has been updated. @@ -19945,20 +8601,29 @@ namespace entt { * @return A temporary sink object. */ template - [[nodiscard]] auto on_update() { - return assure()->on_update(); + auto on_update() { + return assure().on_update(); + } + + /*! @copydoc on_update */ + template + [[deprecated("use registry::on_update instead")]] + auto on_replace() { + return on_update(); } /** * @brief Returns a sink object for the given component. * + * A sink is an opaque object used to connect listeners to components.
* 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.
+ * thus destroyed. + * * The function type for a listener is equivalent to: * * @code{.cpp} - * void(basic_registry &, Entity); + * void(registry &, Entity); * @endcode * * Listeners are invoked **before** the component has been removed from the @@ -19970,289 +8635,8 @@ namespace entt { * @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, std::add_const_t...> view(exclude_t = {}) const { - static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - 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)); - }), "Conflicting groups"); - - 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...>, std::add_const_t...> group_if_exists(get_t, exclude_t = {}) const { - 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<>, std::add_const_t...> 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(); + auto on_destroy() { + return assure().on_destroy(); } /** @@ -20290,7 +8674,9 @@ namespace entt { * this member function. * * @warning - * Pools of components owned by a group cannot be sorted. + * Pools of components owned by a group cannot be sorted.
+ * An assertion will abort the execution at runtime in debug mode in case + * the pool is owned by a group. * * @tparam Component Type of components to sort. * @tparam Compare Type of comparison function object. @@ -20302,8 +8688,9 @@ namespace entt { */ template void sort(Compare compare, Sort algo = Sort{}, Args &&... args) { - ENTT_ASSERT(sortable(), "Cannot sort owned storage"); - assure()->sort(std::move(compare), std::move(algo), std::forward(args)...); + auto& cpool = assure(); + ENTT_ASSERT(!cpool.super); + cpool.sort(cpool.begin(), cpool.end(), std::move(compare), std::move(algo), std::forward(args)...); } /** @@ -20334,24 +8721,311 @@ namespace entt { * Any subsequent change to `B` won't affect the order in `A`. * * @warning - * Pools of components owned by a group cannot be sorted. + * Pools of components owned by a group cannot be sorted.
+ * An assertion will abort the execution at runtime in debug mode in case + * the pool is owned by a group. * * @tparam To Type of components to sort. * @tparam From Type of components to use to sort. */ template void sort() { - ENTT_ASSERT(sortable(), "Cannot sort owned storage"); - assure()->respect(*assure()); + auto& cpool = assure(); + ENTT_ASSERT(!cpool.super); + cpool.respect(assure()); } /** - * @brief Visits an entity and returns the type info for its components. + * @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 + entt::basic_view, Component...> view(exclude_t = {}) { + static_assert(sizeof...(Component) > 0); + return { assure>()..., assure()... }; + } + + /*! @copydoc view */ + template + entt::basic_view, Component...> view(exclude_t = {}) const { + static_assert(std::conjunction_v...>); + return const_cast(this)->view(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 + bool sortable() const { + return !(assure().super || ...); + } + + /** + * @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 + entt::basic_group, get_t, Owned...> group(get_t, exclude_t = {}) { + static_assert(sizeof...(Owned) + sizeof...(Get) > 0); + static_assert(sizeof...(Owned) + sizeof...(Get) + sizeof...(Exclude) > 1); + + using handler_type = group_handler, get_t...>, std::decay_t...>; + + const auto cpools = std::forward_as_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_info>::id()) && ...) + && (gdata.get(type_info>::id()) && ...) + && (gdata.exclude(type_info::id()) && ...); + }); 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_info>::id()) || ...); }, + []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_info>::id()) || ...); }, + []([[maybe_unused]] const id_type ctype) ENTT_NOEXCEPT { return ((ctype == type_info::id()) || ...); }, + }; + + 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_info>::id())); + const auto sz = overlapping + (0u + ... + gdata.get(type_info>::id())) + (0u + ... + gdata.exclude(type_info::id())); + 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_info>::id())) || (size > (gdata.size)); + }); + + const auto prev = std::find_if(std::make_reverse_iterator(next), groups.crend(), [](const auto& gdata) { + return (0u + ... + gdata.owned(type_info>::id())); + }); + + 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)); + } + + ((std::get>&>(cpools).super = std::max(std::get>&>(cpools).super, size)), ...); + + (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(entt::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); + } + } + } + + if constexpr (sizeof...(Owned) == 0) { + return { handler->current, std::get>&>(cpools)... }; + } + else { + return { std::get<0>(cpools).super, 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 + entt::basic_group, get_t, Owned...> group(get_t, exclude_t = {}) const { + static_assert(std::conjunction_v..., std::is_const...>); + return const_cast(this)->group(entt::get, exclude); + } + + /** + * @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 + entt::basic_group, get_t<>, Owned...> group(exclude_t = {}) { + return group(entt::get<>, exclude); + } + + /** + * @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 + entt::basic_group, get_t<>, Owned...> group(exclude_t = {}) const { + static_assert(std::conjunction_v...>); + return const_cast(this)->group(exclude); + } + + /** + * @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.
+ * This is particularly well suited to plugin systems and mods in general. + * + * @tparam It Type of input iterator. + * @param first An iterator to the first element of the range of components. + * @param last An iterator past the last element of the range of components. + * @return A newly created runtime view. + */ + template + entt::basic_runtime_view runtime_view(It first, It last) const { + std::vector*> selected(std::distance(first, last)); + + std::transform(first, last, selected.begin(), [this](const auto ctype) { + const auto it = std::find_if(pools.cbegin(), pools.cend(), [ctype](auto&& pdata) { return pdata.pool && pdata.type_id == ctype; }); + return it == pools.cend() ? nullptr : it->pool.get(); + }); + + return { std::move(selected) }; + } + + /** + * @brief Returns a temporary object to use to create snapshots. + * + * A snapshot is either a full or a partial dump of a registry.
+ * It can be used to save and restore its internal state or to keep two or + * more instances of this class in sync, as an example in a client-server + * architecture. + * + * @return A temporary object to use to take snasphosts. + */ + [[deprecated("basic_snapshot has now a constructor that accepts a reference to a registry")]] + entt::basic_snapshot snapshot() const { + return { *this }; + } + + /** + * @brief Returns a temporary object to use to load snapshots. + * + * A snapshot is either a full or a partial dump of a registry.
+ * It can be used to save and restore its internal state or to keep two or + * more instances of this class in sync, as an example in a client-server + * architecture. + * + * @note + * The loader returned by this function requires that the registry be empty. + * In case it isn't, all the data will be automatically deleted before to + * return. + * + * @return A temporary object to use to load snasphosts. + */ + [[deprecated("basic_snapshot_loader has now a constructor that accepts a reference to a registry")]] + basic_snapshot_loader loader() { + return { *this }; + } + + /** + * @brief Visits an entity and returns the types for its components. * * The signature of the function should be equivalent to the following: * * @code{.cpp} - * void(const type_info); + * void(const id_type); * @endcode * * Returned identifiers are those of the components owned by the entity. @@ -20370,18 +9044,18 @@ namespace entt { 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()); + func(pdata.type_id); } } } /** - * @brief Visits a registry and returns the type info for its components. + * @brief Visits a registry and returns the types for its components. * * The signature of the function should be equivalent to the following: * * @code{.cpp} - * void(const type_info); + * void(const id_type); * @endcode * * Returned identifiers are those of the components managed by the registry. @@ -20399,7 +9073,7 @@ namespace entt { 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()); + func(pdata.type_id); } } } @@ -20418,8 +9092,8 @@ namespace entt { template Type& set(Args &&... args) { unset(); - vars.emplace_back(std::in_place_type, std::forward(args)...); - return any_cast(vars.back()); + vars.push_back(variable_data{ type_info::id(), { new Type{std::forward(args)...}, [](void* instance) { delete static_cast(instance); } } }); + return *static_cast(vars.back().value.get()); } /** @@ -20428,7 +9102,9 @@ namespace entt { */ template void unset() { - vars.erase(std::remove_if(vars.begin(), vars.end(), [type = type_id()](auto&& var) { return var.type() == type; }), vars.end()); + vars.erase(std::remove_if(vars.begin(), vars.end(), [](auto&& var) { + return var.type_id == type_info::id(); + }), vars.end()); } /** @@ -20443,7 +9119,7 @@ namespace entt { * @return A reference to the object in the context of the registry. */ template - [[nodiscard]] Type& ctx_or_set(Args &&... args) { + Type& ctx_or_set(Args &&... args) { auto* value = try_ctx(); return value ? *value : set(std::forward(args)...); } @@ -20455,16 +9131,15 @@ namespace entt { * registry, a null pointer otherwise. */ template - [[nodiscard]] std::add_const_t* 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); + const Type* try_ctx() const { + auto it = std::find_if(vars.cbegin(), vars.cend(), [](auto&& var) { return var.type_id == type_info::id(); }); + return it == vars.cend() ? nullptr : static_cast(it->value.get()); } /*! @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); + Type* try_ctx() { + return const_cast(std::as_const(*this).template try_ctx()); } /** @@ -20472,34 +9147,33 @@ namespace entt { * * @warning * Attempting to get a context variable that doesn't exist results in - * undefined behavior. + * undefined behavior.
+ * An assertion will abort the execution at runtime in debug mode in case of + * invalid requests. * * @tparam Type Type of object to get. * @return A valid reference to the object in the context of the registry. */ template - [[nodiscard]] std::add_const_t& 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(), "Invalid instance"); - return any_cast&>(*it); + const Type& ctx() const { + const auto* instance = try_ctx(); + ENTT_ASSERT(instance); + return *instance; } /*! @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(), "Invalid instance"); - return any_cast(*it); + Type& ctx() { + return const_cast(std::as_const(*this).template ctx()); } /** - * @brief Visits a registry and returns the type info for its context - * variables. + * @brief Visits a registry and returns the types for its context variables. * * The signature of the function should be equivalent to the following: * * @code{.cpp} - * void(const type_info); + * void(const id_type); * @endcode * * Returned identifiers are those of the context variables currently set. @@ -20516,16 +9190,16 @@ namespace entt { template void ctx(Func func) const { for (auto pos = vars.size(); pos; --pos) { - func(vars[pos - 1].type()); + func(vars[pos - 1].type_id); } } private: - std::vector> vars{}; - mutable std::vector pools{}; std::vector groups{}; + mutable std::vector pools{}; std::vector entities{}; - entity_type free_list{ tombstone }; + std::vector vars{}; + entity_type destroyed{ null }; }; @@ -20534,351 +9208,211 @@ namespace entt { #endif +// #include "entity.hpp" + +// #include "fwd.hpp" + namespace entt { /** - * @brief Non-owning handle to an entity. + * @brief Dedicated to those who aren't confident with the + * entity-component-system architecture. * - * Tiny wrapper around a registry and an entity. + * Tiny wrapper around a registry, for all those users that aren't confident + * with entity-component-system architecture and prefer to iterate objects + * directly. * * @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 Type of registry accepted by the handle. */ - using registry_type = constness_as_t>, Entity>; + template + struct basic_actor { + /*! @brief Type of registry used internally. */ + using registry_type = basic_registry; /*! @brief Underlying entity identifier. */ - using entity_type = typename registry_type::entity_type; - /*! @brief Underlying version type. */ - using version_type = typename registry_type::version_type; - /*! @brief Unsigned integer type. */ - using size_type = typename registry_type::size_type; + using entity_type = Entity; - /*! @brief Constructs an invalid handle. */ - basic_handle() ENTT_NOEXCEPT - : reg{}, entt{ null } + basic_actor() ENTT_NOEXCEPT + : entt{ entt::null }, reg{ nullptr } {} /** - * @brief Constructs a handle from a given registry and entity. + * @brief Move constructor. + * + * After actor move construction, instances that have been moved from are + * placed in a valid but unspecified state. It's highly discouraged to + * continue using them. + * + * @param other The instance to move from. + */ + basic_actor(basic_actor&& other) ENTT_NOEXCEPT + : entt{ other.entt }, reg{ other.reg } + { + other.entt = null; + } + + /** + * @brief Constructs an actor from a given registry. * @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 } + explicit basic_actor(registry_type& ref) + : entt{ ref.create() }, reg{ &ref } {} /** - * @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. + * @brief Constructs an actor from a given entity. + * @param entity A valid entity identifier. + * @param ref An instance of the registry class. */ - template - [[nodiscard]] bool operator==(const basic_handle& other) const ENTT_NOEXCEPT { - return reg == other.registry() && entt == other.entity(); + explicit basic_actor(entity_type entity, registry_type& ref) ENTT_NOEXCEPT + : entt{ entity }, reg{ &ref } + { + ENTT_ASSERT(ref.valid(entity)); + } + + /*! @brief Default destructor. */ + virtual ~basic_actor() { + if (*this) { + reg->destroy(entt); + } } /** - * @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. + * @brief Move assignment operator. + * + * After actor move assignment, instances that have been moved from are + * placed in a valid but unspecified state. It's highly discouraged to + * continue using them. + * + * @param other The instance to move from. + * @return This actor. */ - 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" - ); + basic_actor& operator=(basic_actor&& other) ENTT_NOEXCEPT { + if (this != &other) { + auto tmp{ std::move(other) }; + std::swap(reg, tmp.reg); + std::swap(entt, tmp.entt); + } - return reg ? basic_handle{*reg, entt} : basic_handle{}; + return *this; } /** - * @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 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. + * @brief Assigns the given component to an actor. + * + * 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 actor.
+ * In case the actor already has a component of the given type, it's + * replaced with the new one. + * + * @tparam Component Type of the 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"); + decltype(auto) assign(Args &&... args) { 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. + * @brief Removes the given component from an actor. + * @tparam Component Type of the component to remove. */ - 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)...); + template + void remove() { + reg->template remove(entt); } /** - * @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. - * @return The number of components actually removed. - */ - template - size_type remove() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); - return reg->template remove(entt); - } - - /** - * @brief Erases the given components from a handle. - * @sa basic_registry::erase - * @tparam Component Types of components to erase. - */ - template - void erase() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); - reg->template erase(entt); - } - - /*! @copydoc remove */ - template - [[deprecated("Use ::remove instead")]] - size_type remove_if_exists() const { - return remove(); - } - - /** - * @brief Removes all the components from a handle and makes it orphaned. - * @sa basic_registry::remove_all - */ - [[deprecated("No longer supported")]] - 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 + * @brief Checks if an actor has the given components. * @tparam Component Components for which to perform the check. - * @return True if the handle has all the components, false otherwise. + * @return True if the actor has all the components, false otherwise. */ template - [[nodiscard]] decltype(auto) all_of() const { - return reg->template all_of(entt); + bool has() const { + return reg->template has(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 + * @brief Returns references to the given components for an actor. * @tparam Component Types of components to get. - * @return References to the components owned by the handle. + * @return References to the components owned by the actor. */ template - [[nodiscard]] decltype(auto) get() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); + decltype(auto) get() const { + return std::as_const(*reg).template get(entt); + } + + /*! @copydoc get */ + template + decltype(auto) get() { 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 + * @brief Returns pointers to the given components for an actor. * @tparam Component Types of components to get. - * @return Pointers to the components owned by the handle. + * @return Pointers to the components owned by the actor. */ template - [[nodiscard]] auto try_get() const { - static_assert(sizeof...(Type) == 0 || (type_list_contains_v, Component> && ...), "Invalid type"); + auto try_get() const { + return std::as_const(*reg).template try_get(entt); + } + + /*! @copydoc try_get */ + template + auto try_get() { 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. + * @brief Returns a reference to the underlying registry. + * @return A reference to the underlying registry. */ - [[nodiscard]] bool orphan() const { - return reg->orphan(entt); + const registry_type& backend() const ENTT_NOEXCEPT { + return *reg; + } + + /*! @copydoc backend */ + registry_type& backend() ENTT_NOEXCEPT { + return const_cast(std::as_const(*this).backend()); } /** - * @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. + * @brief Returns the entity associated with an actor. + * @return The entity associated with the actor. */ - template - void visit(Func&& func) const { - reg->visit(entt, std::forward(func)); + entity_type entity() const ENTT_NOEXCEPT { + return entt; + } + + /** + * @brief Checks if an actor refers to a valid entity or not. + * @return True if the actor refers to a valid entity, false otherwise. + */ + explicit operator bool() const { + return reg && reg->valid(entt); } private: - registry_type* reg; entity_type entt; + registry_type* reg; }; - /** - * @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/entity.hpp" + +// #include "entity/group.hpp" + // #include "entity/helper.hpp" #ifndef ENTT_ENTITY_HELPER_HPP #define ENTT_ENTITY_HELPER_HPP @@ -20887,382 +9421,9 @@ namespace entt { #include // #include "../config/config.h" -// #include "../core/fwd.hpp" - // #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), "Uninitialized delegate"); - 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" @@ -21275,14 +9436,13 @@ namespace entt { /** * @brief Converts a registry to a view. + * @tparam Const Constness of the accepted registry. * @tparam Entity A valid entity type (see entt_traits for more details). */ - template + 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>; + using registry_type = std::conditional_t, entt::basic_registry>; /** * @brief Constructs a converter for a given registry. @@ -21297,7 +9457,7 @@ namespace entt { * @return A newly created view. */ template - operator basic_view() const { + operator entt::basic_view() const { return reg.template view(Exclude{}); } @@ -21308,30 +9468,30 @@ namespace entt { /** * @brief Deduction guide. + * + * It allows to deduce the constness of a registry directly from the instance + * provided to the constructor. + * * @tparam Entity A valid entity type (see entt_traits for more details). */ template - as_view(basic_registry&)->as_view; + as_view(basic_registry&) ENTT_NOEXCEPT->as_view; - /** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ + /*! @copydoc as_view */ template - as_view(const basic_registry&)->as_view; + as_view(const basic_registry&) ENTT_NOEXCEPT->as_view; /** * @brief Converts a registry to a group. + * @tparam Const Constness of the accepted registry. * @tparam Entity A valid entity type (see entt_traits for more details). */ - template + 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>; + using registry_type = std::conditional_t, entt::basic_registry>; /** * @brief Constructs a converter for a given registry. @@ -21347,13 +9507,8 @@ namespace entt { * @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{}); - } + operator entt::basic_group() const { + return reg.template group(Get{}, Exclude{}); } private: @@ -21363,18 +9518,19 @@ namespace entt { /** * @brief Deduction guide. + * + * It allows to deduce the constness of a registry directly from the instance + * provided to the constructor. + * * @tparam Entity A valid entity type (see entt_traits for more details). */ template - as_group(basic_registry&)->as_group; + as_group(basic_registry&) ENTT_NOEXCEPT->as_group; - /** - * @brief Deduction guide. - * @tparam Entity A valid entity type (see entt_traits for more details). - */ + /*! @copydoc as_group */ template - as_group(const basic_registry&)->as_group; + as_group(const basic_registry&) ENTT_NOEXCEPT->as_group; @@ -21387,41 +9543,13 @@ namespace entt { */ template void invoke(basic_registry& reg, const Entity entt) { - static_assert(std::is_member_function_pointer_v, "Invalid pointer to non-static member function"); + static_assert(std::is_member_function_pointer_v); delegate&, const Entity)> func; func.template connect(reg.template get>(entt)); func(reg, entt); } - /** - * @brief Returns the entity associated with a given component. - * - * @warning - * Currently, this function only works correctly with the default pool as it - * makes assumptions about how the components are laid out. - * - * @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 instance A valid component instance. - * @return The entity associated with the given component. - */ - template - Entity to_entity(const basic_registry& reg, const Component& instance) { - const auto view = reg.template view(); - const auto* addr = std::addressof(instance); - - for (auto it = view.rbegin(), last = view.rend(); it < last; it += ENTT_PACKED_PAGE) { - if (const auto dist = (addr - std::addressof(view.template get(*it))); dist >= 0 && dist < ENTT_PACKED_PAGE) { - return *(it + dist); - } - } - - return entt::null; - } - - } @@ -21441,8 +9569,6 @@ namespace entt { // #include "../core/type_traits.hpp" -// #include "../signal/delegate.hpp" - // #include "registry.hpp" // #include "storage.hpp" @@ -21503,6 +9629,13 @@ namespace entt { static constexpr auto update() ENTT_NOEXCEPT { return basic_collector, type_list<>, AnyOf>>{}; } + + /*! @copydoc update */ + template + [[deprecated("use ::update instead")]] + static constexpr auto replace() ENTT_NOEXCEPT { + return update(); + } }; /** @@ -21539,6 +9672,14 @@ namespace entt { return basic_collector, type_list<>, AnyOf>, current_type, Other...>{}; } + /*! @copydoc update */ + template + [[deprecated("use ::update instead")]] + static constexpr auto replace() ENTT_NOEXCEPT { + return update(); + } + + /** * @brief Updates the filter of the last added matcher. * @tparam AllOf Types of components required by the matcher. @@ -21616,20 +9757,20 @@ namespace entt { template struct matcher_handler, type_list, AnyOf>> { template - static void maybe_valid_if(basic_observer& obs, basic_registry& reg, const Entity entt) { - if (reg.template all_of(entt) && !reg.template any_of(entt)) { - if (!obs.storage.contains(entt)) { - obs.storage.emplace(entt); + static void maybe_valid_if(basic_observer& obs, const basic_registry& reg, const Entity entt) { + if (reg.template has(entt) && !reg.template any(entt)) { + if (auto* comp = obs.view.try_get(entt); !comp) { + obs.view.emplace(entt); } - obs.storage.get(entt) |= (1 << Index); + obs.view.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.erase(entt); + static void discard_if(basic_observer& obs, const basic_registry&, const Entity entt) { + if (auto* value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) { + obs.view.erase(entt); } } @@ -21651,29 +9792,21 @@ namespace entt { template struct matcher_handler, type_list, type_list, AllOf...>> { - template - static void maybe_valid_if(basic_observer& obs, basic_registry& reg, 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); + template + static void maybe_valid_if(basic_observer& obs, const basic_registry& reg, const Entity entt) { + if (reg.template has(entt) && !reg.template any(entt)) { + if (auto* comp = obs.view.try_get(entt); !comp) { + obs.view.emplace(entt); } - obs.storage.get(entt) |= (1 << Index); + obs.view.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.erase(entt); + static void discard_if(basic_observer& obs, const basic_registry&, const Entity entt) { + if (auto* value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) { + obs.view.erase(entt); } } @@ -21682,7 +9815,7 @@ namespace entt { (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<&maybe_valid_if>(obs), ...); (reg.template on_destroy().template connect<&discard_if>(obs), ...); (reg.template on_construct().template connect<&discard_if>(obs), ...); } @@ -21698,15 +9831,15 @@ namespace entt { }; template - static void disconnect(basic_registry& reg, basic_observer& obs) { + static void disconnect(basic_observer& obs, basic_registry& reg) { (matcher_handler::disconnect(obs, reg), ...); } template void connect(basic_registry& reg, std::index_sequence) { - static_assert(sizeof...(Matcher) < std::numeric_limits::digits, "Too many matchers"); + static_assert(sizeof...(Matcher) < std::numeric_limits::digits); (matcher_handler::template connect(*this, reg), ...); - release.template connect<&basic_observer::disconnect>(reg); + release = &basic_observer::disconnect; } public: @@ -21714,13 +9847,12 @@ namespace entt { 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 Input iterator type. */ + using iterator = typename sparse_set::iterator; /*! @brief Default constructor. */ basic_observer() - : release{}, - storage{} + : target{}, release{}, view{} {} /*! @brief Default copy constructor, deleted on purpose. */ @@ -21735,7 +9867,9 @@ namespace entt { */ template basic_observer(basic_registry& reg, basic_collector) - : basic_observer{} + : target{ ® }, + release{}, + view{} { connect(reg, std::index_sequence_for{}); } @@ -21764,14 +9898,15 @@ namespace entt { void connect(basic_registry& reg, basic_collector) { disconnect(); connect(reg, std::index_sequence_for{}); - storage.clear(); + target = ® + view.clear(); } /*! @brief Disconnects an observer from the registry it keeps track of. */ void disconnect() { if (release) { - release(*this); - release.reset(); + release(*this, *target); + release = nullptr; } } @@ -21779,32 +9914,32 @@ namespace entt { * @brief Returns the number of elements in an observer. * @return Number of elements. */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { - return storage.size(); + size_type size() const ENTT_NOEXCEPT { + return view.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(); + bool empty() const ENTT_NOEXCEPT { + return view.empty(); } /** * @brief Direct access to the list of entities of the observer. * - * The returned pointer is such that range `[data(), data() + size())` is + * 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. + * There are no guarantees on the order of the entities. Use `begin` and + * `end` if you want to iterate the observer in the expected order. * * @return A pointer to the array of entities. */ - [[nodiscard]] const entity_type* data() const ENTT_NOEXCEPT { - return storage.data(); + const entity_type* data() const ENTT_NOEXCEPT { + return view.data(); } /** @@ -21815,8 +9950,8 @@ namespace entt { * * @return An iterator to the first entity of the observer. */ - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return storage.basic_sparse_set::begin(); + iterator begin() const ENTT_NOEXCEPT { + return view.sparse_set::begin(); } /** @@ -21829,13 +9964,13 @@ namespace entt { * @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(); + iterator end() const ENTT_NOEXCEPT { + return view.sparse_set::end(); } /*! @brief Clears the underlying container. */ void clear() ENTT_NOEXCEPT { - storage.clear(); + view.clear(); } /** @@ -21853,6 +9988,8 @@ namespace entt { */ template void each(Func func) const { + static_assert(std::is_invocable_v); + for (const auto entity : *this) { func(entity); } @@ -21874,771 +10011,9 @@ namespace entt { } 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/fwd.hpp" - -// #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& reg; - }; - - - /** - * @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& reg; - }; - - - /** - * @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& reg, 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. - * - * @warning - * Currently, this function only works correctly with the default pool as it - * makes assumptions about how the components are laid out. - * - * @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 instance A valid component instance. - * @return The entity associated with the given component. - */ - template - Entity to_entity(const basic_registry& reg, const Component& instance) { - const auto view = reg.template view(); - const auto* addr = std::addressof(instance); - - for (auto it = view.rbegin(), last = view.rend(); it < last; it += ENTT_PACKED_PAGE) { - if (const auto dist = (addr - std::addressof(view.template get(*it))); dist >= 0 && dist < ENTT_PACKED_PAGE) { - return *(it + dist); - } - } - - return entt::null; - } - - -} - - -#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& reg) { - 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& reg, 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& reg) 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& reg) { - 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& reg) { 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& reg) { - 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& reg) { - 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>; + basic_registry* target; + void(*release)(basic_observer&, basic_registry&); + storage view; }; @@ -22648,5655 +10023,18 @@ namespace entt { #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 "component.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; - using basic_common_type = basic_sparse_set; - - 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::disjunction_v::in_place_delete...>, "Groups do not support in-place delete"); - static_assert(std::conjunction_v>..., std::is_same>..., std::is_same>...>, "One or more component types are invalid"); - std::conditional_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) { - 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 ENTT_NOEXCEPT { - 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()); - } - - auto generate_identifier(const std::size_t pos) ENTT_NOEXCEPT { - ENTT_ASSERT(pos < traits_type::to_integral(null), "No entities available"); - return traits_type::construct(static_cast(pos), {}); - } - - auto recycle_identifier() ENTT_NOEXCEPT { - ENTT_ASSERT(free_list != null, "No entities available"); - const auto curr = traits_type::to_entity(free_list); - free_list = (tombstone | entities[curr]); - return (entities[curr] = traits_type::construct(curr, traits_type::to_version(entities[curr]))); - } - - auto release_entity(const Entity entity, const typename traits_type::version_type version) { - const typename traits_type::version_type vers = version + (version == traits_type::to_version(tombstone)); - entities[traits_type::to_entity(entity)] = traits_type::construct(traits_type::to_entity(free_list), vers); - free_list = (tombstone | entity); - return vers; - } - - 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 traits_type::construct(traits_type::to_entity(entity), {}); - } - - /** - * @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 traits_type::to_version(entity); - } - - /*! @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, "Storage not available"); - 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, "Storage not available"); - 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 = free_list; curr != null; --sz) { - curr = entities[traits_type::to_entity(curr)]; - } - - 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. - */ - [[deprecated("No longer supported")]] - 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 released 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 released entities. - */ - [[nodiscard]] entity_type released() const ENTT_NOEXCEPT { - return free_list; - } - - /*! @copydoc released */ - [[deprecated("Use ::released instead")]] - [[nodiscard]] entity_type destroyed() const ENTT_NOEXCEPT { - return released(); - } - - /** - * @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(traits_type::to_entity(entity)); - 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(traits_type::to_entity(entity)); - ENTT_ASSERT(pos < entities.size(), "Entity does not exist"); - 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. - */ - [[nodiscard]] entity_type create() { - return (free_list == null) ? entities.emplace_back(generate_identifier(entities.size())) : 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 identifier is generated. - * - * @param hint Required entity identifier. - * @return A valid entity identifier. - */ - [[nodiscard]] entity_type create(const entity_type hint) { - const auto length = entities.size(); - - if (hint == null || hint == tombstone) { - return create(); - } - else if (const auto req = traits_type::to_entity(hint); !(req < length)) { - entities.resize(size_type(req) + 1u, null); - - for (auto pos = length; pos < req; ++pos) { - release_entity(generate_identifier(pos), {}); - } - - return (entities[req] = hint); - } - else if (const auto curr = traits_type::to_entity(entities[req]); req == curr) { - return create(); - } - else { - auto* it = &free_list; - for (; traits_type::to_entity(*it) != req; it = &entities[traits_type::to_entity(*it)]); - *it = traits_type::construct(curr, traits_type::to_version(*it)); - return (entities[req] = hint); - } - } - - /** - * @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 (; free_list != null && first != last; ++first) { - *first = recycle_identifier(); - } - - const auto length = entities.size(); - entities.resize(length + std::distance(first, last), null); - - for (auto pos = length; first != last; ++first, ++pos) { - *first = entities[pos] = generate_identifier(pos); - } - } - - /** - * @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 still alive"); - entities.assign(first, last); - free_list = destroyed; - } - - /** - * @brief Releases an entity identifier. - * - * The version is updated and the identifier can be recycled at any time. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @param entity A valid entity identifier. - * @return The version of the recycled entity. - */ - version_type release(const entity_type entity) { - return release(entity, version(entity) + 1u); - } - - /** - * @brief Releases an entity identifier. - * - * The suggested version or the valid version closest to the suggested one - * is used instead of the implicitly generated version. - * - * @sa release - * - * @param entity A valid entity identifier. - * @param version A desired version upon destruction. - * @return The version actually assigned to the entity. - */ - version_type release(const entity_type entity, const version_type version) { - ENTT_ASSERT(orphan(entity), "Non-orphan entity"); - return release_entity(entity, version); - } - - /** - * @brief Releases all entity identifiers in a range. - * - * @sa release - * - * @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 release(It first, It last) { - for (; first != last; ++first) { - release(*first, version(*first) + 1u); - } - } - - /** - * @brief Destroys an entity and releases its identifier. - * - * The version is updated and the identifier can be recycled at any time. - * - * @warning - * Adding or removing components to an entity that is being destroyed can - * result in undefined behavior. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior. - * - * @param entity A valid entity identifier. - * @return The version of the recycled entity. - */ - version_type destroy(const entity_type entity) { - return destroy(entity, version(entity) + 1u); - } - - /** - * @brief Destroys an entity and releases its identifier. - * - * The suggested version or the valid version closest to the suggested one - * is used instead of the implicitly generated version. - * - * @sa destroy - * - * @param entity A valid entity identifier. - * @param version A desired version upon destruction. - * @return The version actually assigned to the entity. - */ - version_type destroy(const entity_type entity, const version_type version) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - - for (auto&& pdata : pools) { - pdata.pool&& pdata.pool->remove(entity, this); - } - - return release_entity(entity, version); - } - - /** - * @brief Destroys all entities in a range and releases their identifiers. - * - * @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) { - if constexpr (is_iterator_type_v) { - for (; first != last; ++first) { - destroy(*first, version(*first) + 1u); - } - } - else { - for (auto&& pdata : pools) { - pdata.pool&& pdata.pool->remove(first, last, this); - } - - release(first, last); - } - } - - /** - * @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), "Invalid 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); }), "Invalid 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. - */ - template::value_type>, Component>>> - void insert(EIt first, EIt last, CIt from) { - 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); }), "Invalid entity"); - assure()->insert(*this, first, last, from); - } - - /** - * @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), "Invalid 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), "Invalid 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 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(const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - return (assure()->remove(entity, this) + ... + size_type{}); - } - - /** - * @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. - * @return The number of components actually removed. - */ - template - size_type remove(It first, It last) { - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - const auto cpools = std::make_tuple(assure()...); - size_type count{}; - - for (; first != last; ++first) { - const auto entity = *first; - ENTT_ASSERT(valid(entity), "Invalid entity"); - count += (std::get*>(cpools)->remove(entity, this) + ...); - } - - return count; - } - - /** - * @brief Erases the given components from an entity. - * - * @warning - * Attempting to use an invalid entity or to erase a component from an - * entity that doesn't own it results in undefined behavior. - * - * @tparam Component Types of components to erase. - * @param entity A valid entity identifier. - */ - template - void erase(const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - (assure()->erase(entity, this), ...); - } - - /** - * @brief Erases the given components from all the entities in a range. - * - * @sa erase - * - * @tparam Component Types of components to erase. - * @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 erase(It first, It last) { - static_assert(sizeof...(Component) > 0, "Provide one or more component types"); - const auto cpools = std::make_tuple(assure()...); - - for (; first != last; ++first) { - const auto entity = *first; - ENTT_ASSERT(valid(entity), "Invalid entity"); - (std::get*>(cpools)->erase(entity, this), ...); - } - } - - /** - * @brief Removes all tombstones from a registry or only the pools for the - * given components. - * @tparam Component Types of components for which to clear all tombstones. - */ - template - void compact() { - if constexpr (sizeof...(Component) == 0) { - for (auto&& pdata : pools) { - pdata.pool && (pdata.pool->compact(), true); - } - } - else { - (assure()->compact(), ...); - } - } - - /*! @copydoc remove */ - template - [[deprecated("Use ::remove instead")]] - size_type remove_if_exists(const entity_type entity) { - return remove(entity); - } - - /** - * @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. - */ - [[deprecated("Use ::destroy(entity)/::create(entity) instead")]] - void remove_all(const entity_type entity) { - ENTT_ASSERT(valid(entity), "Invalid entity"); - - for (auto&& pdata : pools) { - pdata.pool&& pdata.pool->remove(entity, 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), "Invalid 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), "Invalid 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), "Invalid entity"); - - if constexpr (sizeof...(Component) == 1) { - const auto* cpool = pool_if_exists...>(); - ENTT_ASSERT(cpool, "Storage not available"); - 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), "Invalid 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), "Invalid 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), "Invalid 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), "Invalid 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&& pdata : pools) { - pdata.pool && (pdata.pool->clear(this), true); - } - - each([this](const auto entity) { release_entity(entity, version(entity) + 1u); }); - } - else { - (assure()->clear(this), ...); - } - } - - /** - * @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 (free_list == 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]; traits_type::to_entity(entity) == (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), "Invalid 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, std::add_const_t...> view(exclude_t = {}) const { - static_assert(sizeof...(Component) > 0, "Exclusion-only views are not supported"); - 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)); - }), "Conflicting groups"); - - 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...>, std::add_const_t...> group_if_exists(get_t, exclude_t = {}) const { - 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<>, std::add_const_t...> 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(), "Cannot sort owned storage"); - 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(), "Cannot sort owned storage"); - 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]] std::add_const_t* 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]] std::add_const_t& 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(), "Invalid instance"); - 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(), "Invalid instance"); - 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 free_list{ tombstone }; - }; - - -} - - -#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 "entity.hpp" - -// #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 basic_common_type = basic_sparse_set; - using underlying_iterator = typename basic_common_type::iterator; - - class view_iterator final { - [[nodiscard]] bool valid() const { - const auto entt = *it; - - return (!stable_storage || (entt != tombstone)) - && std::all_of(pools->begin()++, pools->end(), [entt](const auto* curr) { return curr->contains(entt); }) - && std::none_of(filter->cbegin(), filter->cend(), [entt](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(const std::vector& cpools, const std::vector& ignore, underlying_iterator curr) ENTT_NOEXCEPT - : pools{ &cpools }, - filter{ &ignore }, - it{ curr }, - stable_storage{ std::any_of(pools->cbegin(), pools->cend(), [](const basic_common_type* cpool) { return (cpool->policy() == deletion_policy::in_place); }) } - { - if (it != (*pools)[0]->end() && !valid()) { - ++(*this); - } - } - - 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; - bool stable_storage; - }; - - [[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) } - { - // brings the best candidate (if any) on front of the vector - std::rotate(pools.begin(), std::min_element(pools.begin(), pools.end(), [](const auto* lhs, const auto* rhs) { - return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size()); - }), 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->released()); - - 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, "Entity not available for use"); - 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, "Entity not available for use"); - 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(), "Registry must be 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->release(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(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 = traits_type::to_entity(entt); 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->release(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 "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "../core/fwd.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - - - -namespace entt { - - - /*! @brief Sparse set deletion policy. */ - enum class deletion_policy : std::uint8_t { - /*! @brief Swap-and-pop deletion policy. */ - swap_and_pop = 0u, - /*! @brief In-place deletion policy. */ - in_place = 1u - }; - - - /** - * @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). - * @tparam Allocator Type of allocator used to manage memory and elements. - */ - template - class basic_sparse_set { - static constexpr auto growth_factor = 1.5; - static constexpr auto sparse_page = ENTT_SPARSE_PAGE; - - using traits_type = entt_traits; - - using alloc_traits = typename std::allocator_traits::template rebind_traits; - using alloc_pointer = typename alloc_traits::pointer; - using alloc_const_pointer = typename alloc_traits::const_pointer; - - using bucket_alloc_traits = typename std::allocator_traits::template rebind_traits; - using bucket_alloc_pointer = typename bucket_alloc_traits::pointer; - - static_assert(alloc_traits::propagate_on_container_move_assignment::value); - static_assert(bucket_alloc_traits::propagate_on_container_move_assignment::value); - - struct sparse_set_iterator final { - using difference_type = typename traits_type::difference_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(const alloc_const_pointer* ref, const difference_type idx) ENTT_NOEXCEPT - : packed{ ref }, - index{ idx } - {} - - 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 std::addressof((*packed)[pos]); - } - - [[nodiscard]] reference operator*() const { - return *operator->(); - } - - private: - const alloc_const_pointer* packed; - difference_type index; - }; - - [[nodiscard]] static auto page(const Entity entt) ENTT_NOEXCEPT { - return size_type{ traits_type::to_entity(entt) / sparse_page }; - } - - [[nodiscard]] static auto offset(const Entity entt) ENTT_NOEXCEPT { - return size_type{ traits_type::to_entity(entt) & (sparse_page - 1) }; - } - - [[nodiscard]] auto assure_page(const std::size_t idx) { - if (!(idx < bucket)) { - const size_type sz = idx + 1u; - const auto mem = bucket_alloc_traits::allocate(bucket_allocator, sz); - - std::uninitialized_value_construct(mem + bucket, mem + sz); - std::uninitialized_copy(sparse, sparse + bucket, mem); - - std::destroy(sparse, sparse + bucket); - bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket); - - sparse = mem; - bucket = sz; - } - - if (!sparse[idx]) { - sparse[idx] = alloc_traits::allocate(allocator, sparse_page); - std::uninitialized_fill(sparse[idx], sparse[idx] + sparse_page, null); - } - - return sparse[idx]; - } - - void resize_packed(const std::size_t req) { - ENTT_ASSERT((req != reserved) && !(req < count), "Invalid request"); - const auto mem = alloc_traits::allocate(allocator, req); - - std::uninitialized_copy(packed, packed + count, mem); - std::uninitialized_fill(mem + count, mem + req, tombstone); - - std::destroy(packed, packed + reserved); - alloc_traits::deallocate(allocator, packed, reserved); - - packed = mem; - reserved = req; - } - - void release_memory() { - if (packed) { - for (size_type pos{}; pos < bucket; ++pos) { - if (sparse[pos]) { - std::destroy(sparse[pos], sparse[pos] + sparse_page); - alloc_traits::deallocate(allocator, sparse[pos], sparse_page); - } - } - - std::destroy(packed, packed + reserved); - std::destroy(sparse, sparse + bucket); - alloc_traits::deallocate(allocator, packed, reserved); - bucket_alloc_traits::deallocate(bucket_allocator, sparse, bucket); - } - } - - protected: - /** - * @brief Swaps two entities in the internal packed array. - * @param lhs A valid position of an entity within storage. - * @param rhs A valid position of an entity within storage. - */ - virtual void swap_at([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {} - - /** - * @brief Moves an entity in the internal packed array. - * @param from A valid position of an entity within storage. - * @param to A valid position of an entity within storage. - */ - virtual void move_and_pop([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) {} - - /** - * @brief Attempts to erase an entity from the internal packed array. - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - virtual void swap_and_pop(const Entity entt, [[maybe_unused]] void* ud) { - auto& ref = sparse[page(entt)][offset(entt)]; - const auto pos = size_type{ traits_type::to_entity(ref) }; - ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier"); - auto& last = packed[--count]; - - packed[pos] = last; - sparse[page(last)][offset(last)] = ref; - // lazy self-assignment guard - ref = null; - // unnecessary but it helps to detect nasty bugs - ENTT_ASSERT((last = tombstone, true), ""); - } - - /** - * @brief Attempts to erase an entity from the internal packed array. - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - virtual void in_place_pop(const Entity entt, [[maybe_unused]] void* ud) { - auto& ref = sparse[page(entt)][offset(entt)]; - const auto pos = size_type{ traits_type::to_entity(ref) }; - ENTT_ASSERT(packed[pos] == entt, "Invalid entity identifier"); - - packed[pos] = std::exchange(free_list, traits_type::construct(static_cast(pos))); - // lazy self-assignment guard - ref = null; - } - - public: - /*! @brief Allocator type. */ - using allocator_type = typename alloc_traits::allocator_type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Pointer type to contained entities. */ - using pointer = alloc_const_pointer; - /*! @brief Random access iterator type. */ - using iterator = sparse_set_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = std::reverse_iterator; - - /** - * @brief Constructs an empty container with the given policy and allocator. - * @param pol Type of deletion policy. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(deletion_policy pol, const allocator_type& alloc = {}) - : allocator{ alloc }, - bucket_allocator{ alloc }, - sparse{ bucket_alloc_traits::allocate(bucket_allocator, 0u) }, - packed{ alloc_traits::allocate(allocator, 0u) }, - bucket{ 0u }, - count{ 0u }, - reserved{ 0u }, - free_list{ tombstone }, - mode{ pol } - {} - - /** - * @brief Constructs an empty container with the given allocator. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(const allocator_type& alloc = {}) - : basic_sparse_set{ deletion_policy::swap_and_pop, alloc } - {} - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_sparse_set(basic_sparse_set&& other) ENTT_NOEXCEPT - : allocator{ std::move(other.allocator) }, - bucket_allocator{ std::move(other.bucket_allocator) }, - sparse{ std::exchange(other.sparse, bucket_alloc_pointer{}) }, - packed{ std::exchange(other.packed, alloc_pointer{}) }, - bucket{ std::exchange(other.bucket, 0u) }, - count{ std::exchange(other.count, 0u) }, - reserved{ std::exchange(other.reserved, 0u) }, - free_list{ std::exchange(other.free_list, tombstone) }, - mode{ other.mode } - {} - - /*! @brief Default destructor. */ - virtual ~basic_sparse_set() { - release_memory(); - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This sparse set. - */ - basic_sparse_set& operator=(basic_sparse_set&& other) ENTT_NOEXCEPT { - release_memory(); - - allocator = std::move(other.allocator); - bucket_allocator = std::move(other.bucket_allocator); - sparse = std::exchange(other.sparse, bucket_alloc_pointer{}); - packed = std::exchange(other.packed, alloc_pointer{}); - bucket = std::exchange(other.bucket, 0u); - count = std::exchange(other.count, 0u); - reserved = std::exchange(other.reserved, 0u); - free_list = std::exchange(other.free_list, tombstone); - mode = other.mode; - - return *this; - } - - /** - * @brief Returns the deletion policy of a sparse set. - * @return The deletion policy of the sparse set. - */ - [[nodiscard]] deletion_policy policy() const ENTT_NOEXCEPT { - return mode; - } - - /** - * @brief Returns the next slot available for insertion. - * @return The next slot available for insertion. - */ - [[nodiscard]] size_type slot() const ENTT_NOEXCEPT { - return free_list == null ? count : size_type{ traits_type::to_entity(free_list) }; - } - - /** - * @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) { - if (cap > reserved) { - resize_packed(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 reserved; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - if (count < reserved) { - resize_packed(count); - } - } - - /** - * @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 bucket * sparse_page; - } - - /** - * @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 count; - } - - /** - * @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 (count == size_type{}); - } - - /** - * @brief Direct access to the internal packed array. - * @return A pointer to the internal packed array. - */ - [[nodiscard]] pointer data() const ENTT_NOEXCEPT { - return packed; - } - - /** - * @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 { - return iterator{ std::addressof(packed), static_cast(count) }; - } - - /** - * @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{ std::addressof(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 std::make_reverse_iterator(end()); - } - - /** - * @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 std::make_reverse_iterator(begin()); - } - - /** - * @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 ENTT_NOEXCEPT { - 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 ENTT_NOEXCEPT { - ENTT_ASSERT(entt != tombstone && entt != null, "Invalid entity"); - const auto curr = page(entt); - // testing versions permits to avoid accessing the packed array - return (curr < bucket&& 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_NOEXCEPT { - ENTT_ASSERT(contains(entt), "Set does not contain entity"); - return size_type{ traits_type::to_entity(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 ENTT_NOEXCEPT { - return pos < count ? 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_NOEXCEPT { - ENTT_ASSERT(pos < count, "Position is out of bounds"); - return packed[pos]; - } - - /** - * @brief Appends 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. - * @return The slot used for insertion. - */ - size_type emplace_back(const entity_type entt) { - ENTT_ASSERT(!contains(entt), "Set already contains entity"); - - if (count == reserved) { - const size_type sz = static_cast(reserved * growth_factor); - resize_packed(sz + !(sz > reserved)); - } - - assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast(count)); - packed[count] = entt; - return count++; - } - - /** - * @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. - * @return The slot used for insertion. - */ - size_type emplace(const entity_type entt) { - if (free_list == null) { - return emplace_back(entt); - } - else { - ENTT_ASSERT(!contains(entt), "Set already contains entity"); - const auto pos = size_type{ traits_type::to_entity(free_list) }; - sparse[page(entt)][offset(entt)] = traits_type::construct(static_cast(pos)); - free_list = std::exchange(packed[pos], entt); - return pos; - } - } - - /** - * @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) { - reserve(count + std::distance(first, last)); - - for (; first != last; ++first) { - const auto entt = *first; - ENTT_ASSERT(!contains(entt), "Set already contains entity"); - assure_page(page(entt))[offset(entt)] = traits_type::construct(static_cast(count)); - packed[count++] = entt; - } - } - - /** - * @brief Erases an entity from a sparse set. - * - * @warning - * Attempting to erase 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 erase(const entity_type entt, void* ud = nullptr) { - ENTT_ASSERT(contains(entt), "Set does not contain entity"); - (mode == deletion_policy::in_place) ? in_place_pop(entt, ud) : swap_and_pop(entt, ud); - } - - /** - * @brief Erases entities from a set. - * - * @sa erase - * - * @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 erase(It first, It last, void* ud = nullptr) { - for (; first != last; ++first) { - erase(*first, ud); - } - } - - /** - * @brief Removes an entity from a sparse set if it exists. - * @param entt A valid entity identifier. - * @param ud Optional user data that are forwarded as-is to derived classes. - * @return True if the entity is actually removed, false otherwise. - */ - bool remove(const entity_type entt, void* ud = nullptr) { - return contains(entt) && (erase(entt, ud), true); - } - - /** - * @brief Removes entities from a sparse set if they exist. - * @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. - * @return The number of entities actually removed. - */ - template - size_type remove(It first, It last, void* ud = nullptr) { - size_type found{}; - - for (; first != last; ++first) { - found += remove(*first, ud); - } - - return found; - } - - /*! @brief Removes all tombstones from the packed array of a sparse set. */ - void compact() { - size_type next = count; - for (; next && packed[next - 1u] == tombstone; --next); - - for (auto* it = &free_list; *it != null && next; it = std::addressof(packed[traits_type::to_entity(*it)])) { - if (const size_type pos = traits_type::to_entity(*it); pos < next) { - --next; - move_and_pop(next, pos); - std::swap(packed[next], packed[pos]); - sparse[page(packed[pos])][offset(packed[pos])] = traits_type::construct(static_cast(pos)); - *it = traits_type::construct(static_cast(next)); - for (; next && packed[next - 1u] == tombstone; --next); - } - } - - free_list = tombstone; - count = next; - } - - /** - * @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) { - ENTT_ASSERT(contains(lhs), "Set does not contain entity"); - ENTT_ASSERT(contains(rhs), "Set does not contain entity"); - - auto& entt = sparse[page(lhs)][offset(lhs)]; - auto& other = sparse[page(rhs)][offset(rhs)]; - - const auto from = size_type{ traits_type::to_entity(entt) }; - const auto to = size_type{ traits_type::to_entity(other) }; - - // basic no-leak guarantee (with invalid state) if swapping throws - swap_at(from, to); - std::swap(entt, other); - std::swap(packed[from], packed[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 length 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 length, Compare compare, Sort algo = Sort{}, Args &&... args) { - // basic no-leak guarantee (with invalid state) if sorting throws - ENTT_ASSERT(!(length > count), "Length exceeds the number of elements"); - compact(); - - algo(std::make_reverse_iterator(packed + length), std::make_reverse_iterator(packed), std::move(compare), std::forward(args)...); - - for (size_type pos{}; pos < length; ++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)] = traits_type::construct(static_cast(curr)); - curr = std::exchange(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(count, 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) { - compact(); - - const auto to = other.end(); - auto from = other.begin(); - - for (size_type pos = count - 1; pos && from != to; ++from) { - if (contains(*from)) { - if (*from != packed[pos]) { - // basic no-leak guarantee (with invalid state) if swapping throws - swap(packed[pos], *from); - } - - --pos; - } - } - } - - /** - * @brief Clears a sparse set. - * @param ud Optional user data that are forwarded as-is to derived classes. - */ - void clear(void* ud = nullptr) { - for (auto&& entity : *this) { - if (entity != tombstone) { - in_place_pop(entity, ud); - } - } - - free_list = tombstone; - count = 0u; - } - - private: - typename alloc_traits::allocator_type allocator; - typename bucket_alloc_traits::allocator_type bucket_allocator; - bucket_alloc_pointer sparse; - alloc_pointer packed; - std::size_t bucket; - std::size_t count; - std::size_t reserved; - entity_type free_list; - deletion_policy mode; - }; - - -} - - -#endif // #include "entity/storage.hpp" -#ifndef ENTT_ENTITY_STORAGE_HPP -#define ENTT_ENTITY_STORAGE_HPP - - -#include -#include -#include -#include -#include -#include -// #include "../config/config.h" - -// #include "../core/algorithm.hpp" - -// #include "../core/fwd.hpp" - -// #include "../core/type_traits.hpp" - -// #include "../signal/sigh.hpp" - -// #include "component.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. - * - * @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. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ - template - class basic_storage_impl : public basic_sparse_set::template rebind_alloc> { - static constexpr auto packed_page = ENTT_PACKED_PAGE; - - using comp_traits = component_traits; - - using underlying_type = basic_sparse_set::template rebind_alloc>; - using difference_type = typename entt_traits::difference_type; - - using alloc_traits = typename std::allocator_traits::template rebind_traits; - using alloc_pointer = typename alloc_traits::pointer; - using alloc_const_pointer = typename alloc_traits::const_pointer; - - using bucket_alloc_traits = typename std::allocator_traits::template rebind_traits; - using bucket_alloc_pointer = typename bucket_alloc_traits::pointer; - - using bucket_alloc_const_type = typename std::allocator_traits::template rebind_alloc; - using bucket_alloc_const_pointer = typename std::allocator_traits::const_pointer; - - static_assert(alloc_traits::propagate_on_container_move_assignment::value); - static_assert(bucket_alloc_traits::propagate_on_container_move_assignment::value); - - template - struct storage_iterator final { - using difference_type = typename basic_storage_impl::difference_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(bucket_alloc_pointer const* ref, const typename basic_storage_impl::difference_type idx) ENTT_NOEXCEPT - : packed{ ref }, - index{ idx } - {} - - 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 (*packed)[page(pos)][offset(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 std::addressof((*packed)[page(pos)][offset(pos)]); - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return *operator->(); - } - - private: - bucket_alloc_pointer const* packed; - difference_type index; - }; - - [[nodiscard]] static auto page(const std::size_t pos) ENTT_NOEXCEPT { - return pos / packed_page; - } - - [[nodiscard]] static auto offset(const std::size_t pos) ENTT_NOEXCEPT { - return pos & (packed_page - 1); - } - - void release_memory() { - if (packed) { - // no-throw stable erase iteration - underlying_type::clear(); - - for (size_type pos{}; pos < bucket; ++pos) { - alloc_traits::deallocate(allocator, packed[pos], packed_page); - bucket_alloc_traits::destroy(bucket_allocator, std::addressof(packed[pos])); - } - - bucket_alloc_traits::deallocate(bucket_allocator, packed, bucket); - } - } - - void assure_at_least(const std::size_t last) { - if (const auto idx = page(last - 1u); !(idx < bucket)) { - const size_type sz = idx + 1u; - const auto mem = bucket_alloc_traits::allocate(bucket_allocator, sz); - std::uninitialized_copy(packed, packed + bucket, mem); - size_type pos{}; - - ENTT_TRY{ - for (pos = bucket; pos < sz; ++pos) { - auto pg = alloc_traits::allocate(allocator, packed_page); - bucket_alloc_traits::construct(bucket_allocator, std::addressof(mem[pos]), pg); - } - } ENTT_CATCH{ - for (auto next = bucket; next < pos; ++next) { - alloc_traits::deallocate(allocator, mem[next], packed_page); - } - - std::destroy(mem, mem + pos); - bucket_alloc_traits::deallocate(bucket_allocator, mem, sz); - ENTT_THROW; - } - - std::destroy(packed, packed + bucket); - bucket_alloc_traits::deallocate(bucket_allocator, packed, bucket); - - packed = mem; - bucket = sz; - } - } - - void release_unused_pages() { - if (const auto length = underlying_type::size() / packed_page; length < bucket) { - const auto mem = bucket_alloc_traits::allocate(bucket_allocator, length); - std::uninitialized_copy(packed, packed + length, mem); - - for (auto pos = length; pos < bucket; ++pos) { - alloc_traits::deallocate(allocator, packed[pos], packed_page); - bucket_alloc_traits::destroy(bucket_allocator, std::addressof(packed[pos])); - } - - bucket_alloc_traits::deallocate(bucket_allocator, packed, bucket); - - packed = mem; - bucket = length; - } - } - - template - auto& push_at(const std::size_t pos, Args &&... args) { - ENTT_ASSERT(pos < (bucket* packed_page), "Out of bounds index"); - auto* instance = std::addressof(packed[page(pos)][offset(pos)]); - - if constexpr (std::is_aggregate_v) { - alloc_traits::construct(allocator, instance, Type{ std::forward(args)... }); - } - else { - alloc_traits::construct(allocator, instance, std::forward(args)...); - } - - return *instance; - } - - void pop_at(const std::size_t pos) { - alloc_traits::destroy(allocator, std::addressof(packed[page(pos)][offset(pos)])); - } - - protected: - /*! @copydoc basic_sparse_set::swap_at */ - void swap_at(const std::size_t lhs, const std::size_t rhs) final { - std::swap(packed[page(lhs)][offset(lhs)], packed[page(rhs)][offset(rhs)]); - } - - /*! @copydoc basic_sparse_set::move_and_pop */ - void move_and_pop(const std::size_t from, const std::size_t to) final { - push_at(to, std::move(packed[page(from)][offset(from)])); - pop_at(from); - } - - /*! @copydoc basic_sparse_set::swap_and_pop */ - void swap_and_pop(const Entity entt, void* ud) override { - const auto pos = underlying_type::index(entt); - const auto last = underlying_type::size() - 1u; - auto&& elem = packed[page(pos)][offset(pos)]; - - // support for nosy destructors - [[maybe_unused]] auto unused = std::move(elem); - elem = std::move(packed[page(last)][offset(last)]); - pop_at(last); - - underlying_type::swap_and_pop(entt, ud); - } - - /*! @copydoc basic_sparse_set::in_place_pop */ - void in_place_pop(const Entity entt, void* ud) override { - const auto pos = underlying_type::index(entt); - underlying_type::in_place_pop(entt, ud); - // support for nosy destructors - pop_at(pos); - } - - public: - /*! @brief Allocator type. */ - using allocator_type = typename alloc_traits::allocator_type; - /*! @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 Pointer type to contained elements. */ - using pointer = bucket_alloc_pointer; - /*! @brief Constant pointer type to contained elements. */ - using const_pointer = bucket_alloc_const_pointer; - /*! @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 = std::reverse_iterator; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = std::reverse_iterator; - - /** - * @brief Default constructor. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_storage_impl(const allocator_type& alloc = {}) - : underlying_type{ deletion_policy{comp_traits::in_place_delete::value}, alloc }, - allocator{ alloc }, - bucket_allocator{ alloc }, - packed{ bucket_alloc_traits::allocate(bucket_allocator, 0u) }, - bucket{} - {} - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_storage_impl(basic_storage_impl&& other) ENTT_NOEXCEPT - : underlying_type{ std::move(other) }, - allocator{ std::move(other.allocator) }, - bucket_allocator{ std::move(other.bucket_allocator) }, - packed{ std::exchange(other.packed, bucket_alloc_pointer{}) }, - bucket{ std::exchange(other.bucket, 0u) } - {} - - /*! @brief Default destructor. */ - ~basic_storage_impl() override { - release_memory(); - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This sparse set. - */ - basic_storage_impl& operator=(basic_storage_impl&& other) ENTT_NOEXCEPT { - release_memory(); - - underlying_type::operator=(std::move(other)); - - allocator = std::move(other.allocator); - bucket_allocator = std::move(other.bucket_allocator); - packed = std::exchange(other.packed, bucket_alloc_pointer{}); - bucket = std::exchange(other.bucket, 0u); - - return *this; - } - - /** - * @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); - - if (cap > underlying_type::size()) { - assure_at_least(cap); - } - } - - /** - * @brief Returns the number of elements that a storage has currently - * allocated space for. - * @return Capacity of the storage. - */ - [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT { - return bucket * packed_page; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - underlying_type::shrink_to_fit(); - release_unused_pages(); - } - - /** - * @brief Direct access to the array of objects. - * @return A pointer to the array of objects. - */ - [[nodiscard]] const_pointer raw() const ENTT_NOEXCEPT { - return packed; - } - - /*! @copydoc raw */ - [[nodiscard]] pointer raw() ENTT_NOEXCEPT { - return packed; - } - - /** - * @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 difference_type pos = underlying_type::size(); - return const_iterator{ std::addressof(packed), pos }; - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() ENTT_NOEXCEPT { - const difference_type pos = underlying_type::size(); - return iterator{ std::addressof(packed), 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{ std::addressof(packed), {} }; - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const ENTT_NOEXCEPT { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() ENTT_NOEXCEPT { - return iterator{ std::addressof(packed), {} }; - } - - /** - * @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 std::make_reverse_iterator(cend()); - } - - /*! @copydoc crbegin */ - [[nodiscard]] const_reverse_iterator rbegin() const ENTT_NOEXCEPT { - return crbegin(); - } - - /*! @copydoc rbegin */ - [[nodiscard]] reverse_iterator rbegin() ENTT_NOEXCEPT { - return std::make_reverse_iterator(end()); - } - - /** - * @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 std::make_reverse_iterator(cbegin()); - } - - /*! @copydoc crend */ - [[nodiscard]] const_reverse_iterator rend() const ENTT_NOEXCEPT { - return crend(); - } - - /*! @copydoc rend */ - [[nodiscard]] reverse_iterator rend() ENTT_NOEXCEPT { - return std::make_reverse_iterator(begin()); - } - - /** - * @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 ENTT_NOEXCEPT { - const auto idx = underlying_type::index(entt); - return packed[page(idx)][offset(idx)]; - } - - /*! @copydoc get */ - [[nodiscard]] value_type& get(const entity_type entt) ENTT_NOEXCEPT { - 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) { - const auto pos = underlying_type::slot(); - assure_at_least(pos + 1u); - - auto& value = push_at(pos, std::forward(args)...); - - ENTT_TRY{ - [[maybe_unused]] const auto curr = underlying_type::emplace(entt); - ENTT_ASSERT(pos == curr, "Misplaced component"); - } ENTT_CATCH{ - pop_at(pos); - ENTT_THROW; - } - - return value; - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid entity identifier. - * @param func Valid function objects. - * @return A reference to the updated instance. - */ - template - decltype(auto) patch(const entity_type entt, Func &&... func) { - const auto idx = underlying_type::index(entt); - auto&& elem = packed[page(idx)][offset(idx)]; - (std::forward(func)(elem), ...); - return elem; - } - - /** - * @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 = {}) { - const auto cap = underlying_type::size() + std::distance(first, last); - underlying_type::reserve(cap); - assure_at_least(cap); - - for (; first != last; ++first) { - push_at(underlying_type::size(), value); - - ENTT_TRY{ - underlying_type::emplace_back(*first); - } ENTT_CATCH{ - pop_at(underlying_type::size()); - ENTT_THROW; - } - } - } - - /** - * @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. - */ - template::value_type>, value_type>>> - void insert(EIt first, EIt last, CIt from) { - const auto cap = underlying_type::size() + std::distance(first, last); - underlying_type::reserve(cap); - assure_at_least(cap); - - for (; first != last; ++first, ++from) { - push_at(underlying_type::size(), *from); - - ENTT_TRY{ - underlying_type::emplace_back(*first); - } ENTT_CATCH{ - pop_at(underlying_type::size()); - ENTT_THROW; - } - } - } - - /** - * @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 length 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 length, Compare compare, Sort algo = Sort{}, Args &&... args) { - if constexpr (std::is_invocable_v) { - underlying_type::sort_n(length, [this, compare = std::move(compare)](const auto lhs, const auto rhs) { - const auto ilhs = underlying_type::index(lhs), irhs = underlying_type::index(rhs); - return compare(std::as_const(packed[page(ilhs)][offset(ilhs)]), std::as_const(packed[page(irhs)][offset(irhs)])); - }, std::move(algo), std::forward(args)...); - } - else { - underlying_type::sort_n(length, 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(underlying_type::size(), std::move(compare), std::move(algo), std::forward(args)...); - } - - private: - typename alloc_traits::allocator_type allocator; - typename bucket_alloc_traits::allocator_type bucket_allocator; - bucket_alloc_pointer packed; - size_type bucket; - }; - - - /*! @copydoc basic_storage_impl */ - template - class basic_storage_impl::ignore_if_empty::value&& std::is_empty_v>> - : public basic_sparse_set::template rebind_alloc> - { - using comp_traits = component_traits; - using underlying_type = basic_sparse_set::template rebind_alloc>; - using alloc_traits = typename std::allocator_traits::template rebind_traits; - - public: - /*! @brief Allocator type. */ - using allocator_type = typename alloc_traits::allocator_type; - /*! @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 Default constructor. - * @param alloc Allocator to use (possibly default-constructed). - */ - explicit basic_storage_impl(const allocator_type& alloc = {}) - : underlying_type{ deletion_policy{comp_traits::in_place_delete::value}, alloc } - {} - - /** - * @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_NOEXCEPT { - ENTT_ASSERT(underlying_type::contains(entt), "Storage does not contain entity"); - } - - /** - * @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 entt A valid entity identifier. - * @param func Valid function objects. - */ - template - void patch([[maybe_unused]] const entity_type entt, Func &&... func) { - ENTT_ASSERT(underlying_type::contains(entt), "Storage does not contain 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 Inherited constructors. */ - using Type::Type; - - /** - * @brief Assigns entities to a storage. - * @tparam Args Types of arguments to use to construct the object. - * @param entt 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 entt, Args &&... args) { - return Type::emplace(entt, 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 entt 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 entt, Func &&... func) { - return Type::patch(entt, 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 { - /*! @copydoc basic_sparse_set::swap_and_pop */ - void swap_and_pop(const typename Type::entity_type entt, void* ud) final { - ENTT_ASSERT(ud != nullptr, "Invalid pointer to registry"); - destruction.publish(*static_cast *>(ud), entt); - Type::swap_and_pop(entt, ud); - } - - /*! @copydoc basic_sparse_set::in_place_pop */ - void in_place_pop(const typename Type::entity_type entt, void* ud) final { - ENTT_ASSERT(ud != nullptr, "Invalid pointer to registry"); - destruction.publish(*static_cast *>(ud), entt); - Type::in_place_pop(entt, 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 Inherited constructors. */ - using Type::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 entt 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 entt, Args &&... args) { - Type::emplace(entt, std::forward(args)...); - construction.publish(owner, entt); - return this->get(entt); - } - - /** - * @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 entt 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 entt, Func &&... func) { - Type::patch(entt, std::forward(func)...); - update.publish(owner, entt); - return this->get(entt); - } - - private: - sigh&, const entity_type)> construction{}; - sigh&, const entity_type)> destruction{}; - sigh&, const entity_type)> update{}; - }; - - - /** - * @brief Storage implementation dispatcher. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects assigned to the entities. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ - template - struct basic_storage : basic_storage_impl { - using basic_storage_impl::basic_storage_impl; - }; - - - /** - * @brief Provides a common way to access certain properties of storage types. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects managed by the storage class. - */ - 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 entt 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 entt) { - 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(entt)); - } - } - - -} - - -#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 "component.hpp" - -// #include "entity.hpp" - -// #include "fwd.hpp" - -// #include "sparse_set.hpp" - -// #include "storage.hpp" - -// #include "utility.hpp" - - - -namespace entt { - - - /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - - namespace internal { - - - template - class view_iterator final { - using basic_common_type = basic_sparse_set::value_type>; - - [[nodiscard]] bool valid() const { - const auto entt = *it; - return Policy::accept(entt) - && std::apply([entt](const auto *... curr) { return (curr->contains(entt) && ...); }, pools) - && std::apply([entt](const auto *... curr) { return (!curr->contains(entt) && ...); }, filter); - } - - public: - using iterator_type = It; - 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 - : first{}, - last{}, - it{}, - pools{}, - filter{} - {} - - view_iterator(It from, It to, It curr, std::array all_of, std::array none_of) ENTT_NOEXCEPT - : first{ from }, - last{ to }, - it{ curr }, - pools{ all_of }, - filter{ none_of } - { - if (it != last && !valid()) { - ++(*this); - } - } - - 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; - std::array pools; - std::array filter; - }; - - - } - - - /** - * Internal details not to be documented. - * @endcond - */ - - - /*! @brief Stable storage policy, aimed at pointer stability. */ - struct stable_storage_policy { - /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - template - [[nodiscard]] static constexpr bool accept(const Entity entity) ENTT_NOEXCEPT { - return entity != tombstone; - } - /** - * Internal details not to be documented. - * @endcond - */ - }; - - - /*! @brief Packed storage policy, aimed at faster linear iteration. */ - struct packed_storage_policy { - /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - template - [[nodiscard]] static constexpr bool accept(const Entity) ENTT_NOEXCEPT { - return true; - } - /** - * Internal details not to be documented. - * @endcond - */ - }; - - - /** - * @brief View implementation. - * - * 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_impl; - - - /*! @brief View implementation dispatcher. */ - template - struct 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 Policy Common (stricter) storage policy. - * @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_impl, Component...> { - using basic_common_type = basic_sparse_set; - - template - using storage_type = constness_as_t>::storage_type, Comp>; - - class iterable final { - template - struct iterable_iterator final { - 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_iterator(It from, const basic_view_impl* parent) ENTT_NOEXCEPT - : it{ from }, - view{ parent } - {} - - iterable_iterator& operator++() ENTT_NOEXCEPT { - return ++it, * this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_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_iterator& other) const ENTT_NOEXCEPT { - return other.it == it; - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - It it; - const basic_view_impl* view; - }; - - public: - using iterator = iterable_iterator>; - using reverse_iterator = iterable_iterator>; - - iterable(const basic_view_impl& parent) - : view{ parent } - {} - - [[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_impl view; - }; - - [[nodiscard]] const auto* candidate() const ENTT_NOEXCEPT { - return (std::min)({ static_cast(std::get*>(pools))... }, [](const auto* lhs, const auto* rhs) { - return lhs->size() < rhs->size(); - }); - } - - [[nodiscard]] auto pools_to_unchecked_array() const ENTT_NOEXCEPT { - std::size_t pos{}; - std::array other{}; - (static_cast(std::get*>(pools) == view ? void() : void(other[pos++] = std::get*>(pools))), ...); - return other; - } - - [[nodiscard]] auto filter_to_array() const ENTT_NOEXCEPT { - return std::array{std::get*>(filter)...}; - } - - 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 (Policy::accept(entt) && ((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && (!std::get *>(filter)->contains(entt) && ...)) - { - if constexpr (is_applicable_v < Func, decltype(std::tuple_cat(std::tuple{}, 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 (Policy::accept(entt) && ((std::is_same_v || std::get *>(pools)->contains(entt)) && ...) - && (!std::get *>(filter)->contains(entt) && ...)) - { - if constexpr (is_applicable_v < Func, decltype(std::tuple_cat(std::tuple{}, 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 = internal::view_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = internal::view_iterator; - /*! @brief Iterable view type. */ - using iterable_view = iterable; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view_impl() 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_impl(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(), pools_to_unchecked_array(), filter_to_array() }; - } - - /** - * @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(), pools_to_unchecked_array(), filter_to_array() }; - } - - /** - * @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(), pools_to_unchecked_array(), filter_to_array() }; - } - - /** - * @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(), pools_to_unchecked_array(), filter_to_array() }; - } - - /** - * @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), pools_to_unchecked_array(), filter_to_array() }; - 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), "View does not contain entity"); - - 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. - * - * @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. - * - * @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_common_type* 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_impl, Component> { - using basic_common_type = basic_sparse_set; - using storage_type = constness_as_t>::storage_type, Component>; - - class iterable final { - template - struct iterable_iterator final { - 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; - - template - iterable_iterator(It... from, Discard...) ENTT_NOEXCEPT - : it{ from... } - {} - - iterable_iterator& operator++() ENTT_NOEXCEPT { - return (++std::get(it), ...), * this; - } - - iterable_iterator operator++(int) ENTT_NOEXCEPT { - iterable_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return { *std::get(it)... }; - } - - [[nodiscard]] bool operator==(const iterable_iterator& other) const ENTT_NOEXCEPT { - return std::get<0>(other.it) == std::get<0>(it); - } - - [[nodiscard]] bool operator!=(const iterable_iterator& other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - private: - std::tuple it; - }; - - public: - using iterator = std::conditional_t < - std::is_void_v().get({})) > , - iterable_iterator, - iterable_iterator().begin())> - > ; - using reverse_iterator = std::conditional_t < - std::is_void_v().get({})) > , - iterable_iterator, - iterable_iterator().rbegin())> - > ; - - iterable(storage_type& ref) - : pool{ &ref } - {} - - [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return iterator{ pool->basic_common_type::begin(), pool->begin() }; - } - - [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return iterator{ pool->basic_common_type::end(), pool->end() }; - } - - [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return reverse_iterator{ pool->basic_common_type::rbegin(), pool->rbegin() }; - } - - [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return reverse_iterator{ pool->basic_common_type::rend(), pool->rend() }; - } - - private: - storage_type* const pool; - }; - - 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_common_type::iterator; - /*! @brief Reversed iterator type. */ - using reverse_iterator = typename basic_common_type::reverse_iterator; - /*! @brief Iterable view type. */ - using iterable_view = iterable; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view_impl() 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_impl(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 raw representation offered by the storage. - * @return A pointer to the array of components. - */ - [[nodiscard]] auto 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]] auto 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_common_type::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_common_type::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_common_type::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_common_type::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), "View does not contain entity"); - - 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 View implementation dispatcher. - * @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 - struct basic_view, Component...> - : basic_view_impl>::in_place_delete...>, stable_storage_policy, packed_storage_policy>, Entity, exclude_t, Component...> - { - /*! @brief Most restrictive storage policy of all component types. */ - using storage_policy = std::conditional_t>::in_place_delete...>, stable_storage_policy, packed_storage_policy>; - using basic_view_impl, Component...>::basic_view_impl; - }; - - - /** - * @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 @@ -28310,24 +10048,18 @@ namespace entt { #define ENTT_CONFIG_CONFIG_H -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) +#ifndef ENTT_NOEXCEPT # define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) #endif -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws #endif @@ -28345,47 +10077,37 @@ namespace entt { #endif -#ifdef ENTT_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 #endif -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT +#ifndef ENTT_ASSERT # include -# define ENTT_ASSERT(condition, ...) assert(condition) +# define ENTT_ASSERT(condition) assert(condition) #endif -#ifdef ENTT_NO_ETO +#ifndef ENTT_NO_ETO # include -# define ENTT_IGNORE_IF_EMPTY std::false_type +# define ENTT_IS_EMPTY(Type) std::is_empty_v #else # include -# define ENTT_IGNORE_IF_EMPTY std::true_type +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) #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 '>' +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ # endif #endif @@ -28422,7 +10144,7 @@ namespace entt { * @brief Tests if a valid service implementation is set. * @return True if the service is set, false otherwise. */ - [[nodiscard]] static bool empty() ENTT_NOEXCEPT { + static bool empty() ENTT_NOEXCEPT { return !static_cast(service); } @@ -28436,7 +10158,7 @@ namespace entt { * * @return A reference to the service implementation currently set, if any. */ - [[nodiscard]] static std::weak_ptr get() ENTT_NOEXCEPT { + static std::weak_ptr get() ENTT_NOEXCEPT { return service; } @@ -28454,7 +10176,7 @@ namespace entt { * * @return A reference to the service implementation currently set, if any. */ - [[nodiscard]] static Service& ref() ENTT_NOEXCEPT { + static Service& ref() ENTT_NOEXCEPT { return *service; } @@ -28474,7 +10196,7 @@ namespace entt { * @param ptr Service to use to replace the current one. */ static void set(std::shared_ptr ptr) { - ENTT_ASSERT(static_cast(ptr), "Null service not allowed"); + ENTT_ASSERT(static_cast(ptr)); service = std::move(ptr); } @@ -28495,1545 +10217,6 @@ namespace entt { } -#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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 -// #include "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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" @@ -30041,37 +10224,168 @@ namespace entt { #define ENTT_META_FACTORY_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_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws +#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 + + +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 +#endif + + +#ifndef ENTT_ASSERT +# include +# define ENTT_ASSERT(condition) assert(condition) +#endif + + +#ifndef ENTT_NO_ETO +# include +# define ENTT_IS_EMPTY(Type) std::is_empty_v +#else +# include +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) +#endif + + +#ifndef ENTT_STANDARD_CPP +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ +# 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_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws +#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 + + +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 +#endif + + +#ifndef ENTT_ASSERT +# include +# define ENTT_ASSERT(condition) assert(condition) +#endif + + +#ifndef ENTT_NO_ETO +# include +# define ENTT_IS_EMPTY(Type) std::is_empty_v +#else +# include +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) +#endif + + +#ifndef ENTT_STANDARD_CPP +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ +# 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<>; - - } @@ -30082,8 +10396,6 @@ namespace entt { #define ENTT_CORE_TYPE_INFO_HPP -#include -#include // #include "../config/config.h" // #include "../core/attribute.h" @@ -30171,7 +10483,7 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ @@ -30197,7 +10509,7 @@ namespace entt { }; // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { + static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { auto value = traits_type::offset; while (*curr != 0) { @@ -30213,18 +10525,6 @@ namespace entt { /*! @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. * @@ -30241,7 +10541,7 @@ namespace entt { * @return The numeric representation of the string. */ template - [[nodiscard]] static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { + static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { return helper(str); } @@ -30250,10 +10550,22 @@ namespace entt { * @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 { + static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { return helper(wrapper.str); } + /** + * @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. + */ + static 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 Constructs an empty hashed string. */ constexpr basic_hashed_string() ENTT_NOEXCEPT : str{ nullptr }, hash{} @@ -30291,7 +10603,7 @@ namespace entt { * @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 { + constexpr const value_type* data() const ENTT_NOEXCEPT { return str; } @@ -30299,25 +10611,25 @@ namespace entt { * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the instance. */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { + constexpr hash_type value() const ENTT_NOEXCEPT { return hash; } /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type* () const ENTT_NOEXCEPT { return data(); } + 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(); } + 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 { + constexpr bool operator==(const basic_hashed_string& other) const ENTT_NOEXCEPT { return hash == other.hash; } @@ -30338,7 +10650,7 @@ namespace entt { * @param str Human-readable identifer. */ template - basic_hashed_string(const Char(&str)[N]) + basic_hashed_string(const Char(&str)[N]) ENTT_NOEXCEPT ->basic_hashed_string; @@ -30350,7 +10662,7 @@ namespace entt { * @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 { + constexpr bool operator!=(const basic_hashed_string& lhs, const basic_hashed_string& rhs) ENTT_NOEXCEPT { return !(lhs == rhs); } @@ -30363,32 +10675,26 @@ namespace entt { 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 }; - } - - - } +/** + * @brief User defined literal for hashed strings. + * @param str The literal without its suffix. + * @return A properly initialized hashed string. + */ +constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(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. + */ +constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t* str, std::size_t) ENTT_NOEXCEPT { + return entt::hashed_wstring{ str }; } @@ -30410,456 +10716,82 @@ namespace entt { namespace internal { - struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { + struct ENTT_API type_index { + 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 + * @endcond TURN_OFF_DOXYGEN */ /** - * @brief Type sequential identifier. + * @brief Type index. * @tparam Type Type for which to generate a sequential identifier. */ template - struct ENTT_API type_seq final { + struct ENTT_API type_index { /** * @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(); + static id_type value() ENTT_NOEXCEPT { + static const id_type value = internal::type_index::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. + * @brief Provides the member constant `value` to true if a given type is + * indexable, false otherwise. + * @tparam Type Potentially indexable type. + */ + template + struct has_type_index : std::false_type {}; + + + /*! @brief has_type_index */ + template + struct has_type_index::value())>> : std::true_type {}; + + + /** + * @brief Helper variable template. + * @tparam Type Potentially indexable type. + */ + template + inline constexpr bool has_type_index_v = has_type_index::value; + + + /** + * @brief Type info. + * @tparam Type Type for which to generate information. */ template - struct type_hash final { + struct ENTT_API type_info { /** * @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); + static ENTT_PRETTY_FUNCTION_CONSTEXPR() id_type id() ENTT_NOEXCEPT { + ENTT_PRETTY_FUNCTION_CONSTEXPR(static const) auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION); + return value; + } #else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); -#endif + static id_type id() ENTT_NOEXCEPT { + return type_index::value(); } - - /*! @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 "../config/config.h" - -// #include "../core/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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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; }; @@ -30868,19 +10800,16 @@ namespace entt { #endif -// #include "fwd.hpp" - -// #include "type_info.hpp" -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP +// #include "../core/type_traits.hpp" +#ifndef ENTT_CORE_TYPE_TRAITS_HPP +#define ENTT_CORE_TYPE_TRAITS_HPP -#include +#include +#include #include // #include "../config/config.h" -// #include "../core/attribute.h" - // #include "hashed_string.hpp" // #include "fwd.hpp" @@ -30891,267 +10820,19 @@ namespace entt { /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. + * @brief Wraps a static constant. + * @tparam Value A static constant. */ - - - 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; - } - - - } + template + using integral_constant = std::integral_constant; /** - * Internal details not to be documented. - * @endcond + * @brief Alias template to ease the creation of named values. + * @tparam Value A constant value at least convertible to `id_type`. */ - - - /** - * @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 -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { + template + using tag = integral_constant; /** @@ -31163,7 +10844,7 @@ namespace entt { // Unfortunately, doxygen cannot parse such a construct. /*! @cond TURN_OFF_DOXYGEN */ : choice_t - /*! @endcond */ + /*! @endcond TURN_OFF_DOXYGEN */ {}; @@ -31180,146 +10861,32 @@ namespace entt { 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 A class to use to push around lists of types, nothing more. */ + template + struct type_list {}; + + + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_size; /** - * @brief Helper type. - * @tparam Type A type. + * @brief Compile-time number of elements in a type list. + * @tparam Type Types provided by the type list. */ - 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 + template + struct type_list_size> + : std::integral_constant {}; /** * @brief Helper variable template. - * @tparam Type The type of which to return the size. + * @tparam List Type list. */ - template - inline constexpr std::size_t 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 {}; } + template + inline constexpr auto type_list_size_v = type_list_size::value; /*! @brief Primary template isn't defined on purpose. */ @@ -31405,396 +10972,25 @@ namespace entt { /** - * @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. + * @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 type_list_contains; + template> + struct is_equality_comparable : std::false_type {}; - /** - * @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...> {}; + /*! @copydoc is_equality_comparable */ + template + struct is_equality_comparable() == std::declval())>> : std::true_type {}; /** * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ - template - inline constexpr bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. + * @tparam Type Potentially equality comparable type. */ template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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; + inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; /** @@ -31803,7 +10999,7 @@ namespace entt { */ template class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); + static_assert(std::is_member_pointer_v); template static Class* clazz(Ret(Class::*)(Args...)); @@ -31831,463 +11027,23 @@ namespace entt { } -#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 : std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE }; - enum class policy : std::uint8_t { OWNER, REF, CREF }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void* (const operation, const basic_any&, 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 constexpr policy type_to_policy() { - if constexpr (std::is_lvalue_reference_v) { - if constexpr (std::is_const_v>) { - return policy::CREF; - } - else { - return policy::REF; - } - } - else { - return policy::OWNER; - } - } - - 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 const void* basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any& from, [[maybe_unused]] void* to) { - static_assert(std::is_same_v>, Type>, "Invalid type"); - - if constexpr (!std::is_void_v) { - const Type* instance = (in_situ && from.mode == policy::OWNER) - ? ENTT_LAUNDER(reinterpret_cast(&from.storage)) - : static_cast(from.instance); - - switch (op) { - case operation::COPY: - if constexpr (std::is_copy_constructible_v) { - static_cast(to)->emplace(*instance); - } - break; - case operation::MOVE: - if constexpr (in_situ) { - if (from.mode == policy::OWNER) { - return new (&static_cast(to)->storage) Type{ std::move(*const_cast(instance)) }; - } - } - - return (static_cast(to)->instance = std::exchange(const_cast(from).instance, nullptr)); - case operation::DTOR: - if (from.mode == policy::OWNER) { - if constexpr (in_situ) { - instance->~Type(); - } - else if constexpr (std::is_array_v) { - delete[] instance; - } - else { - delete instance; - } - } - break; - case operation::COMP: - return compare(instance, (*static_cast(to))->data()) ? to : nullptr; - case operation::ADDR: - if (from.mode == policy::CREF) { - return nullptr; - } - [[fallthrough]]; - case operation::CADDR: - return instance; - case operation::TYPE: - *static_cast(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 (sizeof...(Args) != 0u && std::is_aggregate_v) { - new (&storage) Type{ std::forward(args)... }; - } - else { - new (&storage) Type(std::forward(args)...); - } - } - else { - if constexpr (sizeof...(Args) != 0u && std::is_aggregate_v) { - instance = new Type{ std::forward(args)... }; - } - else { - instance = new Type(std::forward(args)...); - } - } - } - } - - basic_any(const basic_any& other, const policy pol) ENTT_NOEXCEPT - : instance{ other.data() }, - vtable{ other.vtable }, - mode{ pol } - {} - - public: - /*! @brief Size of the internal storage. */ - static constexpr auto length = Len; - /*! @brief Alignment requirement. */ - static constexpr auto alignment = Align; - - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - {} - - /** - * @brief Constructs a wrapper 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>> }, - mode{ type_to_policy() } - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs a wrapper 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{} - { - // invokes deprecated assignment operator (and avoids issues with vs2017) - *this = value; - } - - /** - * @brief Constructs a wrapper 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) - : instance{}, - vtable{ &basic_vtable> }, - mode{ policy::OWNER } - { - initialize>(std::forward(value)); - } - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any& other) - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any&& other) ENTT_NOEXCEPT - : instance{}, - vtable{ other.vtable }, - mode{ other.mode } - { - 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) { - reset(); - 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) ENTT_NOEXCEPT { - std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - mode = other.mode; - 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 - [[deprecated("Use std::in_place_type, entt::make_any, emplace or forward_as_any instead")]] - 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); - mode = type_to_policy(); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - mode = policy::OWNER; - } - - /** - * @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 { - const basic_any* trampoline = &other; - return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data()); - } - - /** - * @brief Aliasing constructor. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - return basic_any{ *this, (mode == policy::CREF ? policy::CREF : policy::REF) }; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - return basic_any{ *this, policy::CREF }; - } - - /** - * @brief Returns true if a wrapper owns its object, false otherwise. - * @return True if the wrapper owns its object, false otherwise. - */ - [[nodiscard]] bool owner() const ENTT_NOEXCEPT { - return (mode == policy::OWNER); - } - - private: - union { const void* instance; storage_type storage; }; - vtable_type* vtable; - policy mode; - }; - - - /** - * @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, "Invalid 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, "Invalid 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, "Invalid 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); - } - - - /** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - * @return A properly initialized wrapper for an object of the given type. - */ - template::length, std::size_t Align = basic_any::alignment, typename... Args> - basic_any make_any(Args &&... args) { - return basic_any{std::in_place_type, std::forward(args)...}; - } - - - /** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ - template::length, std::size_t Align = basic_any::alignment, typename Type> - basic_any forward_as_any(Type&& value) { - return basic_any{std::in_place_type, std::decay_t, Type>>, std::forward(value)}; - } - - -} +/** + * @brief Defines an enum class to use for opaque identifiers and a dedicate + * `to_integer` function to convert the identifiers to their underlying type. + * @param clazz The name to use for the enum class. + * @param type The underlying type for the enum class. + */ +#define ENTT_OPAQUE_TYPE(clazz, type)\ + enum class clazz: type {};\ + constexpr auto to_integral(const clazz id) ENTT_NOEXCEPT {\ + return static_cast>(id);\ + }\ + static_assert(true) #endif -// #include "../core/fwd.hpp" - -// #include "../core/utility.hpp" + // #include "../core/utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP @@ -32309,7 +11065,7 @@ namespace entt { * @return The submitted value as-is. */ template - [[nodiscard]] constexpr Type&& operator()(Type&& value) const ENTT_NOEXCEPT { + constexpr Type&& operator()(Type&& value) const ENTT_NOEXCEPT { return std::forward(value); } }; @@ -32323,7 +11079,7 @@ namespace entt { * @return Pointer to the member. */ template - [[nodiscard]] constexpr auto overload(Type Class::* member) ENTT_NOEXCEPT { return member; } + constexpr auto overload(Type Class::* member) ENTT_NOEXCEPT { return member; } /** @@ -32333,7 +11089,7 @@ namespace entt { * @return Pointer to the function. */ template - [[nodiscard]] constexpr auto overload(Func* func) ENTT_NOEXCEPT { return func; } + constexpr auto overload(Func* func) ENTT_NOEXCEPT { return func; } /** @@ -32351,8 +11107,7 @@ namespace entt { * @tparam Func Types of function objects. */ template - overloaded(Func...) - ->overloaded; + overloaded(Func...)->overloaded; /** @@ -32396,144 +11151,23 @@ namespace entt { #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 "meta.hpp" +#ifndef ENTT_META_META_HPP +#define ENTT_META_META_HPP #include +#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 { @@ -32541,7 +11175,6 @@ namespace entt { class meta_any; class meta_type; - struct meta_handle; /** @@ -32558,8 +11191,8 @@ namespace entt { struct meta_prop_node { meta_prop_node* next; - const meta_any& id; - meta_any& value; + meta_any(* const key)(); + meta_any(* const value)(); }; @@ -32567,7 +11200,7 @@ namespace entt { meta_type_node* const parent; meta_base_node* next; meta_type_node* (* const type)() ENTT_NOEXCEPT; - const void* (* const cast)(const void*) ENTT_NOEXCEPT; + void* (* const cast)(void*) ENTT_NOEXCEPT; }; @@ -32584,12 +11217,18 @@ namespace entt { 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; + const size_type size; + meta_type_node* (* const arg)(size_type) ENTT_NOEXCEPT; meta_any(* const invoke)(meta_any* const); }; + struct meta_dtor_node { + meta_type_node* const parent; + void(* const invoke)(void*); + }; + + struct meta_data_node { id_type id; meta_type_node* const parent; @@ -32598,8 +11237,8 @@ namespace entt { 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); + bool(* const set)(meta_any, meta_any, meta_any); + meta_any(* const get)(meta_any, meta_any); }; @@ -32609,31 +11248,21 @@ namespace entt { meta_type_node* const parent; meta_func_node* next; meta_prop_node* prop; - const size_type arity; + const size_type size; 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; + meta_type_node* (* const arg)(size_type) ENTT_NOEXCEPT; + meta_any(* const invoke)(meta_any, meta_any*); }; struct meta_type_node { using size_type = std::size_t; - const type_info info; + const id_type type_id; 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; @@ -32645,102 +11274,110 @@ namespace entt { 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; + const size_type extent; + bool(* const compare)(const void*, const void*); 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_ctor_node* ctor{ nullptr }; + meta_dtor_node* dtor{ 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; - } + template + void visit(Op& op, Node* node) { + while (node) { + op(Type{ node }); + node = node->next; } - - 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 + void visit(Op& op, const internal::meta_type_node* node) { + if (node) { + internal::visit(op, node->*Member); + auto* next = node->base; + + while (next) { + visit(op, next->type()); + next = next->next; + } + } + } + + + template + auto find_if(const Op& op, Node* node) { + while (node && !op(node)) { + node = node->next; + } + + return node; + } + + + template + auto find_if(const Op& op, const meta_type_node* node) + -> decltype(find_if(op, node->*Member)) { + decltype(find_if(op, node->*Member)) ret = nullptr; + + if (node) { + ret = find_if(op, node->*Member); + auto* next = node->base; + + while (next && !ret) { + ret = find_if(op, next->type()); + next = next->next; + } + } + + return ret; + } 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; + 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; + } + } - [[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; + struct ENTT_API meta_context { + inline static meta_type_node* local = nullptr; + inline static meta_type_node** global = &local; + + static void detach(const meta_type_node* node) ENTT_NOEXCEPT { + auto** it = global; + + while (*it && *it != node) { + it = &(*it)->next; } - else { - return nullptr; + + if (*it) { + *it = (*it)->next; } } + }; - [[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 { + template + struct ENTT_API meta_node { + static_assert(std::is_same_v>>); + + static meta_type_node* resolve() ENTT_NOEXCEPT { static meta_type_node node{ - type_id(), + type_info::id(), {}, nullptr, nullptr, - size_of_v, std::is_void_v, std::is_integral_v, std::is_floating_point_v, @@ -32752,16 +11389,10 @@ namespace entt { 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) + std::extent_v, + &compare, // workaround for an issue with VS2017 + &meta_node>>::resolve, + &meta_node>>::resolve }; return &node; @@ -32769,15 +11400,8 @@ namespace entt { }; - 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]; - } + template + struct meta_info : meta_node>...> {}; } @@ -32785,512 +11409,243 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ -} + /*! @brief Opaque container for a meta context. */ + struct meta_ctx { + /** + * @brief Binds the meta system to the 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; + } - -#endif - -// #include "range.hpp" -#ifndef ENTT_META_RANGE_HPP -#define ENTT_META_RANGE_HPP - - -#include -#include - - -namespace entt { + private: + internal::meta_type_node** ctx{ &internal::meta_context::local }; + }; /** - * @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. + * @brief Opaque container for values of any type. + * + * This class uses a technique called small buffer optimization (SBO) to get rid + * of memory allocations if possible. This should improve overall performance. */ - 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; + class meta_any { + using storage_type = std::aligned_storage_t; + using copy_fn_type = void(meta_any&, const meta_any&); + using steal_fn_type = void(meta_any&, meta_any&); + using destroy_fn_type = void(meta_any&); - range_iterator() ENTT_NOEXCEPT = default; - - range_iterator(node_type* head) ENTT_NOEXCEPT - : it{ head } - {} - - range_iterator& operator++() ENTT_NOEXCEPT { - return (it = it->next), * this; + template> + struct type_traits { + template + static void instance(meta_any& any, Args &&... args) { + any.instance = new Type{ std::forward(args)... }; + new (&any.storage) Type* { static_cast(any.instance) }; } - range_iterator operator++(int) ENTT_NOEXCEPT { - range_iterator orig = *this; - return ++(*this), orig; + static void destroy(meta_any& any) { + const auto* const node = internal::meta_info::resolve(); + if (node->dtor) { node->dtor->invoke(any.instance); } + delete static_cast(any.instance); } - [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return it; + static void copy(meta_any& to, const meta_any& from) { + auto* instance = new Type{ *static_cast(from.instance) }; + new (&to.storage) Type* { instance }; + to.instance = instance; } - [[nodiscard]] bool operator==(const range_iterator& other) const ENTT_NOEXCEPT { - return other.it == it; + static void steal(meta_any& to, meta_any& from) { + new (&to.storage) Type* { static_cast(from.instance) }; + to.instance = from.instance; } - - [[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, DEREF, SEQ, ASSOC }; - - using vtable_type = void(const operation, const any&, void*); - - template - static void basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any& from, [[maybe_unused]] void* to) { - static_assert(std::is_same_v>, Type>, "Invalid type"); - - if constexpr (!std::is_void_v) { - switch (op) { - case operation::DTOR: - if (auto* curr = static_cast(to); curr->dtor && from.owner()) { - curr->dtor(const_cast(from).data()); - } - break; - case operation::DEREF: - 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::element_type>, void>) { - using in_place_type = decltype(adl_meta_pointer_like::dereference(any_cast(from))); - static_cast(to)->emplace(adl_meta_pointer_like::dereference(any_cast(from))); - } - } - case operation::SEQ: - if constexpr (is_complete_v>) { - *static_cast(to) = { std::in_place_type, std::move(const_cast(from)) }; - } - break; - case operation::ASSOC: - if constexpr (is_complete_v>) { - *static_cast(to) = { std::in_place_type, std::move(const_cast(from)) }; - } - break; - } + struct type_traits>> { + template + static void instance(meta_any& any, Args &&... args) { + any.instance = new (&any.storage) Type{ std::forward(args)... }; } - } - meta_any(const meta_any& other, any ref) ENTT_NOEXCEPT - : storage{ std::move(ref) }, - node{ storage ? other.node : nullptr }, - vtable{ storage ? other.vtable : &basic_vtable } - {} + static void destroy(meta_any& any) { + const auto* const node = internal::meta_info::resolve(); + if (node->dtor) { node->dtor->invoke(any.instance); } + static_cast(any.instance)->~Type(); + } + + static void copy(meta_any& to, const meta_any& from) { + to.instance = new (&to.storage) Type{ *static_cast(from.instance) }; + } + + static void steal(meta_any& to, meta_any& from) { + to.instance = new (&to.storage) Type{ std::move(*static_cast(from.instance)) }; + destroy(from); + } + }; + + meta_any(const internal::meta_type_node* curr, void* ref) ENTT_NOEXCEPT + : meta_any{} + { + node = curr; + instance = ref; + } public: /*! @brief Default constructor. */ meta_any() ENTT_NOEXCEPT : storage{}, + instance{}, node{}, - vtable{ &basic_vtable } + destroy_fn{}, + copy_fn{}, + steal_fn{} {} /** - * @brief Constructs a wrapper by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. + * @brief Constructs a meta any by directly initializing the new object. + * @tparam Type Type of object to use to initialize the container. * @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 wrapper 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) + explicit meta_any(std::in_place_type_t, [[maybe_unused]] Args &&... args) : meta_any{} { - // invokes deprecated assignment operator (and avoids issues with vs2017) - *this = value; + node = internal::meta_info::resolve(); + + if constexpr (!std::is_void_v) { + using traits_type = type_traits>>; + traits_type::instance(*this, std::forward(args)...); + destroy_fn = &traits_type::destroy; + copy_fn = &traits_type::copy; + steal_fn = &traits_type::steal; + } } /** - * @brief Constructs a wrapper 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. + * @brief Constructs a meta any that holds an unmanaged object. + * @tparam Type Type of object to use to initialize the container. + * @param value An instance of an object to use to initialize the container. */ - template, meta_any>>> + template + meta_any(std::reference_wrapper value) + : meta_any{ internal::meta_info::resolve(), &value.get() } + {} + + /** + * @brief Constructs a meta any from a given value. + * @tparam Type Type of object to use to initialize the container. + * @param value An instance of an object to use to initialize the container. + */ + template>, meta_any>>> meta_any(Type&& value) - : storage{ std::forward(value) }, - node{ internal::meta_info>::resolve() }, - vtable{ &basic_vtable> } + : 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; + meta_any(const meta_any& other) + : meta_any{} + { + node = other.node; + (other.copy_fn ? other.copy_fn : [](meta_any& to, const meta_any& from) { to.instance = from.instance; })(*this, other); + destroy_fn = other.destroy_fn; + copy_fn = other.copy_fn; + steal_fn = other.steal_fn; + } /** * @brief Move constructor. + * + * After move construction, instances that have been moved from are placed + * in a valid but unspecified state. + * * @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) } - {} + meta_any(meta_any&& other) + : meta_any{} + { + swap(*this, other); + } /*! @brief Frees the internal storage, whatever it means. */ ~meta_any() { - vtable(operation::DTOR, storage, node); + if (destroy_fn) { + destroy_fn(*this); + } } /** - * @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) ENTT_NOEXCEPT { - 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. + * @brief Assignment operator. + * @tparam Type Type of object to use to initialize the container. + * @param value An instance of an object to use to initialize the container. * @return This meta any object. */ template - [[deprecated("Use std::in_place_type, entt::make_meta, emplace or forward_as_meta instead")]] - meta_any& operator=(std::reference_wrapper value) { - emplace(value.get()); - return *this; + meta_any& operator=(Type&& value) { + return (*this = meta_any{ std::forward(value) }); } /** - * @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. + * @brief Assignment operator. + * @param other The instance to assign from. * @return This meta any object. */ - template - std::enable_if_t, meta_any>, meta_any&> - operator=(Type&& value) { - emplace>(std::forward(value)); + meta_any& operator=(meta_any other) { + swap(other, *this); return *this; } /** - * @brief Returns the type of the underlying object. - * @return The type of the underlying object, if any. + * @brief Returns the meta type of the underlying object. + * @return The meta type of the underlying object, if any. */ - [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT; + 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(); + const void* data() const ENTT_NOEXCEPT { + return instance; } /*! @copydoc data */ - [[nodiscard]] void* data() ENTT_NOEXCEPT { - return storage.data(); + void* data() ENTT_NOEXCEPT { + return const_cast(std::as_const(*this).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 wrapper 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 wrapper 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())); - } + const Type* try_cast() const { + void* ret = nullptr; + + if (const auto type_id = internal::meta_info::resolve()->type_id; node && node->type_id == type_id) { + ret = instance; + } + else if (const auto* base = internal::find_if<&internal::meta_type_node::base>([type_id](const auto* curr) { return curr->type()->type_id == type_id; }, node); base) { + ret = base->cast(instance); } - return nullptr; + return static_cast(ret); } /*! @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; + Type* try_cast() { + return const_cast(std::as_const(*this).try_cast()); } /** @@ -33299,272 +11654,184 @@ namespace entt { * The type of the instance must be such that the cast is possible. * * @warning - * Attempting to perform an invalid cast results in undefined behavior. + * Attempting to perform a cast that isn't viable results in undefined + * behavior.
+ * An assertion will abort the execution at runtime in debug mode in case + * the cast is not feasible. * * @tparam Type Type to which to cast the instance. * @return A reference to the contained instance. */ template - [[nodiscard]] Type cast() const { - auto* const instance = try_cast>(); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); + const Type& cast() const { + auto* const actual = try_cast(); + ENTT_ASSERT(actual); + return *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, "Invalid instance"); - return static_cast(*instance); + Type& cast() { + return const_cast(std::as_const(*this).cast()); } /** - * @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. + * @brief Tries to convert an instance to a given type and returns it. + * @tparam Type Type to which to convert the instance. + * @return A valid meta any object if the conversion is possible, an invalid + * one otherwise. */ template - [[nodiscard]] meta_any allow_cast() const { - if (try_cast>() != nullptr) { - return as_ref(); + meta_any convert() const { + meta_any any{}; + + if (const auto type_id = internal::meta_info::resolve()->type_id; node && node->type_id == type_id) { + any = *this; } - 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()); + else if (const auto* const conv = internal::find_if<&internal::meta_type_node::conv>([type_id](const auto* curr) { return curr->type()->type_id == type_id; }, node); conv) { + any = conv->conv(instance); + } + + return any; + } + + /** + * @brief Tries to convert an instance to a given type. + * @tparam Type Type to which to convert the instance. + * @return True if the conversion is possible, false otherwise. + */ + template + bool convert() { + bool valid = (node && node->type_id == internal::meta_info::resolve()->type_id); + + if (!valid) { + if (auto any = std::as_const(*this).convert(); any) { + swap(any, *this); + valid = true; } } - return {}; + return valid; } /** - * @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. + * @brief Replaces the contained object by initializing a new instance + * directly. + * @tparam Type Type of object to use to initialize the container. * @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.as_ref(), &proxy); - return proxy; - } - - /*! @copydoc as_sequence_container */ - [[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT { - meta_sequence_container proxy; - vtable(operation::SEQ, storage.as_ref(), &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.as_ref(), &proxy); - return proxy; - } - - /*! @copydoc as_associative_container */ - [[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT { - meta_associative_container proxy; - vtable(operation::ASSOC, storage.as_ref(), &proxy); - return proxy; - } - - /** - * @brief Indirection operator for dereferencing opaque objects. - * @return A wrapper that shares a reference to an unmanaged object if the - * wrapped element is dereferenceable, an invalid meta any otherwise. - */ - [[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT { - meta_any ret{}; - vtable(operation::DEREF, 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); + *this = meta_any{ std::in_place_type_t{}, std::forward(args)... }; } /** * @brief Aliasing constructor. - * @return A wrapper that shares a reference to an unmanaged object. + * @return A meta any that shares a reference to an unmanaged object. */ - [[nodiscard]] meta_any as_ref() ENTT_NOEXCEPT { - return meta_any{ *this, storage.as_ref() }; + meta_any ref() const ENTT_NOEXCEPT { + return meta_any{ node, instance }; } - /*! @copydoc as_ref */ - [[nodiscard]] meta_any as_ref() const ENTT_NOEXCEPT { - return meta_any{ *this, storage.as_ref() }; + /** + * @brief Indirection operator for aliasing construction. + * @return A meta any that shares a reference to an unmanaged object. + */ + meta_any operator *() const ENTT_NOEXCEPT { + return ref(); + } + + /** + * @brief Returns false if a container is empty, true otherwise. + * @return False if the container is empty, true otherwise. + */ + explicit operator bool() const ENTT_NOEXCEPT { + return !(node == nullptr); + } + + /** + * @brief Checks if two containers differ in their content. + * @param other Container with which to compare. + * @return False if the two containers differ in their content, true + * otherwise. + */ + bool operator==(const meta_any& other) const { + return (!node && !other.node) || (node && other.node && node->type_id == other.node->type_id && node->compare(instance, other.instance)); + } + + /** + * @brief Swaps two meta any objects. + * @param lhs A valid meta any object. + * @param rhs A valid meta any object. + */ + friend void swap(meta_any& lhs, meta_any& rhs) { + if (lhs.steal_fn && rhs.steal_fn) { + meta_any buffer{}; + lhs.steal_fn(buffer, lhs); + rhs.steal_fn(lhs, rhs); + lhs.steal_fn(rhs, buffer); + } + else if (lhs.steal_fn) { + lhs.steal_fn(rhs, lhs); + } + else if (rhs.steal_fn) { + rhs.steal_fn(lhs, rhs); + } + else { + std::swap(lhs.instance, rhs.instance); + } + + std::swap(lhs.node, rhs.node); + std::swap(lhs.destroy_fn, rhs.destroy_fn); + std::swap(lhs.copy_fn, rhs.copy_fn); + std::swap(lhs.steal_fn, rhs.steal_fn); } private: - any storage; - internal::meta_type_node* node; - vtable_type* vtable; + storage_type storage; + void* instance; + const internal::meta_type_node* node; + destroy_fn_type* destroy_fn; + copy_fn_type* copy_fn; + steal_fn_type* steal_fn; }; - /** - * @brief Checks if two wrappers differ in their content. - * @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. - */ - [[nodiscard]] inline bool operator!=(const meta_any& lhs, const meta_any& rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); - } - - - /** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @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. - * @return A properly initialized wrapper for an object of the given type. - */ - template - meta_any make_meta(Args &&... args) { - return meta_any{ std::in_place_type, std::forward(args)... }; - } - - - /** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ - template - meta_any forward_as_meta(Type&& value) { - return meta_any{ std::in_place_type, std::decay_t, Type>>, std::forward(value) }; - } - - /** * @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. + * Handles are used to generate meta 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; + meta_handle() + : any{} + {} /** * @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. + * @tparam Type Type of object to use to initialize the container. + * @param value An instance of an object to use to initialize the container. */ - template, meta_handle>>> - meta_handle(Type& value) ENTT_NOEXCEPT + template + meta_handle(Type&& value) ENTT_NOEXCEPT : meta_handle{} { - if constexpr (std::is_same_v, meta_any>) { - any = value.as_ref(); + if constexpr (std::is_same_v>, meta_any>) { + any = *value; } else { - any.emplace(value); + static_assert(std::is_lvalue_reference_v); + any = std::ref(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 wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any* operator->() { - return &any; - } - - /*! @copydoc operator-> */ - [[nodiscard]] const meta_any* operator->() const { - return &any; + /*! @copydoc meta_any::operator* */ + meta_any operator *() const { + return any; } private: @@ -33572,116 +11839,188 @@ namespace entt { }; - /*! @brief Opaque wrapper for properties of any type. */ - struct meta_prop { - /*! @brief Node type. */ - using node_type = internal::meta_prop_node; + /** + * @brief Checks if two containers 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 containers differ in their content, false otherwise. + */ + inline bool operator!=(const meta_any& lhs, const meta_any& rhs) ENTT_NOEXCEPT { + return !(lhs == rhs); + } + + /*! @brief Opaque container for meta properties of any type. */ + struct meta_prop { /** * @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 + meta_prop(const internal::meta_prop_node* curr = nullptr) ENTT_NOEXCEPT : node{ curr } {} /** - * @brief Returns the stored key as a const reference. - * @return A wrapper containing the key stored with the property. + * @brief Returns the stored key. + * @return A meta any containing the key stored with the given property. */ - [[nodiscard]] meta_any key() const { - return node->id.as_ref(); + meta_any key() const { + return node->key(); } /** - * @brief Returns the stored value by copy. - * @return A wrapper containing the value stored with the property. + * @brief Returns the stored value. + * @return A meta any containing the value stored with the given property. */ - [[nodiscard]] meta_any value() const { - return node->value; + 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. + * @brief Returns true if a meta object is valid, false otherwise. + * @return True if the meta object is valid, false otherwise. */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { + explicit operator bool() const ENTT_NOEXCEPT { return !(node == nullptr); } private: - const node_type* node; + const internal::meta_prop_node* 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; - + /*! @brief Opaque container for meta base classes. */ + struct meta_base { /*! @copydoc meta_prop::meta_prop */ - meta_ctor(const node_type* curr = nullptr) ENTT_NOEXCEPT + meta_base(const internal::meta_base_node* curr = nullptr) ENTT_NOEXCEPT : node{ curr } {} /** - * @brief Returns the type to which an object belongs. - * @return The type to which the object belongs. + * @brief Returns the meta type to which a meta object belongs. + * @return The meta type to which the meta object belongs. */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; + inline meta_type parent() const ENTT_NOEXCEPT; + + /*! @copydoc meta_any::type */ + inline meta_type type() const ENTT_NOEXCEPT; /** - * @brief Returns the number of arguments accepted by a constructor. - * @return The number of arguments accepted by the constructor. + * @brief Casts an instance from a parent type to a base type. + * @param instance The instance to cast. + * @return An opaque pointer to the base type. */ - [[nodiscard]] size_type arity() const ENTT_NOEXCEPT { - return node->arity; + void* cast(void* instance) const ENTT_NOEXCEPT { + return node->cast(instance); } /** - * @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. + * @brief Returns true if a meta object is valid, false otherwise. + * @return True if the meta object is valid, false otherwise. */ - [[nodiscard]] meta_type arg(size_type index) const ENTT_NOEXCEPT; + explicit operator bool() const ENTT_NOEXCEPT { + return !(node == nullptr); + } + + private: + const internal::meta_base_node* node; + }; + + + /*! @brief Opaque container for meta conversion functions. */ + struct meta_conv { + /*! @copydoc meta_prop::meta_prop */ + meta_conv(const internal::meta_conv_node* curr = nullptr) ENTT_NOEXCEPT + : node{ curr } + {} + + /*! @copydoc meta_base::parent */ + inline meta_type parent() const ENTT_NOEXCEPT; + + /*! @copydoc meta_any::type */ + inline meta_type type() const ENTT_NOEXCEPT; + + /** + * @brief Converts an instance to a given type. + * @param instance The instance to convert. + * @return An opaque pointer to the instance to convert. + */ + meta_any convert(const void* instance) const { + return node->conv(instance); + } + + /** + * @brief Returns true if a meta object is valid, false otherwise. + * @return True if the meta object is valid, false otherwise. + */ + explicit operator bool() const ENTT_NOEXCEPT { + return !(node == nullptr); + } + + private: + const internal::meta_conv_node* node; + }; + + + /*! @brief Opaque container for meta constructors. */ + struct meta_ctor { + /*! @brief Unsigned integer type. */ + using size_type = typename internal::meta_ctor_node::size_type; + + /*! @copydoc meta_prop::meta_prop */ + meta_ctor(const internal::meta_ctor_node* curr = nullptr) ENTT_NOEXCEPT + : node{ curr } + {} + + /*! @copydoc meta_base::parent */ + inline meta_type parent() const ENTT_NOEXCEPT; + + /** + * @brief Returns the number of arguments accepted by a meta constructor. + * @return The number of arguments accepted by the meta constructor. + */ + size_type size() const ENTT_NOEXCEPT { + return node->size; + } + + /** + * @brief Returns the meta type of the i-th argument of a meta constructor. + * @param index The index of the argument of which to return the meta type. + * @return The meta type of the i-th argument of a meta constructor, if any. + */ + 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 wrapper 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 + * To create a valid instance, the parameters must be such that a cast or + * conversion to the required types is possible. Otherwise, an empty and + * thus invalid container is returned. * * @tparam Args Types of arguments to use to construct the instance. * @param args Parameters to use to construct the instance. - * @return A wrapper containing the new instance, if any. + * @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)); + meta_any invoke([[maybe_unused]] Args &&... args) const { + if constexpr (sizeof...(Args) == 0) { + return sizeof...(Args) == size() ? node->invoke(nullptr) : meta_any{}; + } + else { + meta_any arguments[]{ std::forward(args)... }; + return sizeof...(Args) == size() ? node->invoke(arguments) : meta_any{}; + } } /** - * @brief Returns a range to use to visit all properties. - * @return An iterable range to use to visit all properties. + * @brief Iterates all the properties assigned to a meta constructor. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; + template + std::enable_if_t, void> + prop(Op op) const { + internal::visit(op, node->prop); } /** @@ -33689,65 +12028,70 @@ namespace entt { * @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); + meta_prop prop(meta_any key) const { + return internal::find_if([key = std::move(key)](const auto* curr) { + return curr->key() == key; + }, node->prop); } /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. + * @brief Returns true if a meta object is valid, false otherwise. + * @return True if the meta object is valid, false otherwise. */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { + explicit operator bool() const ENTT_NOEXCEPT { return !(node == nullptr); } private: - const node_type* node; + const internal::meta_ctor_node* node; }; - /*! @brief Opaque wrapper for data members. */ + /*! @brief Opaque container for meta data. */ 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 + meta_data(const internal::meta_data_node* curr = nullptr) ENTT_NOEXCEPT : node{ curr } {} /*! @copydoc meta_type::id */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { + id_type id() const ENTT_NOEXCEPT { return node->id; } - /*! @copydoc meta_ctor::parent */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; + /*! @copydoc id */ + [[deprecated("use ::id instead")]] + id_type alias() const ENTT_NOEXCEPT { + return id(); + } + + /*! @copydoc meta_base::parent */ + 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. + * @brief Indicates whether a given meta data is constant or not. + * @return True if the meta data is constant, false otherwise. */ - [[nodiscard]] bool is_const() const ENTT_NOEXCEPT { + 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. + * @brief Indicates whether a given meta data is static or not. + * @return True if the meta data is static, false otherwise. */ - [[nodiscard]] bool is_static() const ENTT_NOEXCEPT { + bool is_static() const ENTT_NOEXCEPT { return node->is_static; } /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const ENTT_NOEXCEPT; + inline meta_type type() const ENTT_NOEXCEPT; /** - * @brief Sets the value of a given variable. + * @brief Sets the value of the variable enclosed by a given meta type. * - * It must be possible to cast the instance to the parent type of the data - * member. Otherwise, invoking the setter results in an undefined + * It must be possible to cast the instance to the parent type of the meta + * data. 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. @@ -33759,25 +12103,67 @@ namespace entt { */ template bool set(meta_handle instance, Type&& value) const { - return node->set && node->set(std::move(instance), std::forward(value)); + return node->set(*instance, {}, std::forward(value)); } /** - * @brief Gets the value of a given variable. + * @brief Sets the i-th element of an array enclosed by a given meta type. * - * 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. + * It must be possible to cast the instance to the parent type of the meta + * data. Otherwise, invoking the setter results in an undefined + * behavior.
+ * The type of the value must be such that a cast or conversion to the array + * type is possible. Otherwise, invoking the setter does nothing. * + * @tparam Type Type of value to assign. * @param instance An opaque instance of the underlying type. - * @return A wrapper containing the value of the underlying variable. + * @param index Position of the underlying element to set. + * @param value Parameter to use to set the underlying element. + * @return True in case of success, false otherwise. */ - [[nodiscard]] meta_any get(meta_handle instance) const { - return node->get(std::move(instance)); + template + bool set(meta_handle instance, std::size_t index, Type&& value) const { + ENTT_ASSERT(index < node->type()->extent); + return node->set(*instance, index, std::forward(value)); } - /*! @copydoc meta_ctor::prop */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; + /** + * @brief Gets the value of the variable enclosed by a given meta type. + * + * It must be possible to cast the instance to the parent type of the meta + * data. 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. + */ + meta_any get(meta_handle instance) const { + return node->get(*instance, {}); + } + + /** + * @brief Gets the i-th element of an array enclosed by a given meta type. + * + * It must be possible to cast the instance to the parent type of the meta + * data. Otherwise, invoking the getter results in an undefined behavior. + * + * @param instance An opaque instance of the underlying type. + * @param index Position of the underlying element to get. + * @return A meta any containing the value of the underlying element. + */ + meta_any get(meta_handle instance, std::size_t index) const { + ENTT_ASSERT(index < node->type()->extent); + return node->get(*instance, index); + } + + /** + * @brief Iterates all the properties assigned to a meta data. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. + */ + template + std::enable_if_t, void> + prop(Op op) const { + internal::visit(op, node->prop); } /** @@ -33785,118 +12171,116 @@ namespace entt { * @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); + meta_prop prop(meta_any key) const { + return internal::find_if([key = std::move(key)](const auto* curr) { + return curr->key() == key; + }, node->prop); } /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. + * @brief Returns true if a meta object is valid, false otherwise. + * @return True if the meta object is valid, false otherwise. */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { + explicit operator bool() const ENTT_NOEXCEPT { return !(node == nullptr); } private: - const node_type* node; + const internal::meta_data_node* node; }; - /*! @brief Opaque wrapper for member functions. */ + /*! @brief Opaque container for meta 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; + using size_type = typename internal::meta_func_node::size_type; /*! @copydoc meta_prop::meta_prop */ - meta_func(const node_type* curr = nullptr) ENTT_NOEXCEPT + meta_func(const internal::meta_func_node* curr = nullptr) ENTT_NOEXCEPT : node{ curr } {} /*! @copydoc meta_type::id */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { + id_type id() const ENTT_NOEXCEPT { return node->id; } - /*! @copydoc meta_ctor::parent */ - [[nodiscard]] inline meta_type parent() const ENTT_NOEXCEPT; + /*! @copydoc id */ + [[deprecated("use ::id instead")]] + id_type alias() const ENTT_NOEXCEPT { + return id(); + } + + /*! @copydoc meta_base::parent */ + 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. + * @brief Returns the number of arguments accepted by a meta function. + * @return The number of arguments accepted by the meta function. */ - [[nodiscard]] size_type arity() const ENTT_NOEXCEPT { - return node->arity; + size_type size() const ENTT_NOEXCEPT { + return node->size; } /** - * @brief Indicates whether a member function is constant or not. - * @return True if the member function is constant, false otherwise. + * @brief Indicates whether a given meta function is constant or not. + * @return True if the meta function is constant, false otherwise. */ - [[nodiscard]] bool is_const() const ENTT_NOEXCEPT { + 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. + * @brief Indicates whether a given meta function is static or not. + * @return True if the meta function is static, false otherwise. */ - [[nodiscard]] bool is_static() const ENTT_NOEXCEPT { + 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. + * @brief Returns the meta type of the return type of a meta function. + * @return The meta type of the return type of the meta function. */ - [[nodiscard]] inline meta_type ret() const ENTT_NOEXCEPT; + 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. + * @brief Returns the meta type of the i-th argument of a meta function. + * @param index The index of the argument of which to return the meta type. + * @return The meta type of the i-th argument of a meta function, if any. */ - [[nodiscard]] inline meta_type arg(size_type index) const ENTT_NOEXCEPT; + 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 + * To invoke a meta 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 + * thus invalid container is returned.
+ * It must be possible to cast the instance to the parent type of the meta * 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 wrapper 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 wrapper containing the new instance, if any. + * @return A meta any containing the returned value, 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)); + meta_any arguments[]{ *instance, std::forward(args)... }; + return sizeof...(Args) == size() ? node->invoke(arguments[0], &arguments[sizeof...(Args) != 0]) : meta_any{}; } - /*! @copydoc meta_ctor::prop */ - [[nodiscard]] meta_range prop() const ENTT_NOEXCEPT { - return node->prop; + /** + * @brief Iterates all the properties assigned to a meta function. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. + */ + template + std::enable_if_t, void> + prop(Op op) const { + internal::visit(op, node->prop); } /** @@ -33904,1207 +12288,472 @@ namespace entt { * @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); + meta_prop prop(meta_any key) const { + return internal::find_if([key = std::move(key)](const auto* curr) { + return curr->key() == key; + }, node->prop); } /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. + * @brief Returns true if a meta object is valid, false otherwise. + * @return True if the meta object is valid, false otherwise. */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { + explicit operator bool() const ENTT_NOEXCEPT { return !(node == nullptr); } private: - const node_type* node; + const internal::meta_func_node* node; }; - /*! @brief Opaque wrapper for types. */ + /*! @brief Opaque container for meta 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; - } - - template - void unregister_all(Node** curr) { - while (*curr) { - (unregister_all(&((*curr)->*Member)), ...); - *curr = std::exchange((*curr)->next, nullptr); - } + template + auto ctor(std::index_sequence) const { + return internal::find_if([](const auto* candidate) { + return candidate->size == sizeof...(Args) && ([](auto* from, auto* to) { + return (from->type_id == to->type_id) + || internal::find_if<&internal::meta_type_node::base>([to](const auto* curr) { return curr->type()->type_id == to->type_id; }, from) + || internal::find_if<&internal::meta_type_node::conv>([to](const auto* curr) { return curr->type()->type_id == to->type_id; }, from); + }(internal::meta_info::resolve(), candidate->arg(Indexes)) && ...); + }, node->ctor); } 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; + using size_type = typename internal::meta_type_node::size_type; /*! @copydoc meta_prop::meta_prop */ - meta_type(node_type* curr = nullptr) ENTT_NOEXCEPT + meta_type(const internal::meta_type_node* 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. + * @brief Returns the type id of the underlying type. + * @return The type id of the underlying type. */ - 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; + id_type type_id() const ENTT_NOEXCEPT { + return node->type_id; } /** - * @brief Returns the identifier assigned to a type. - * @return The identifier assigned to the type. + * @brief Returns the identifier assigned to a given meta object. + * @return The identifier assigned to the meta object. */ - [[nodiscard]] id_type id() const ENTT_NOEXCEPT { + 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; + /*! @copydoc id */ + [[deprecated("use ::id instead")]] + id_type alias() const ENTT_NOEXCEPT { + return id(); } /** - * @brief Checks whether a type refers to void or not. + * @brief Indicates whether a given meta type refers to void or not. * @return True if the underlying type is void, false otherwise. */ - [[nodiscard]] bool is_void() const ENTT_NOEXCEPT { + bool is_void() const ENTT_NOEXCEPT { return node->is_void; } /** - * @brief Checks whether a type refers to an integral type or not. + * @brief Indicates whether a given meta 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 { + bool is_integral() const ENTT_NOEXCEPT { return node->is_integral; } /** - * @brief Checks whether a type refers to a floating-point type or not. + * @brief Indicates whether a given meta 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 { + bool is_floating_point() const ENTT_NOEXCEPT { return node->is_floating_point; } /** - * @brief Checks whether a type refers to an array type or not. + * @brief Indicates whether a given meta 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 { + bool is_array() const ENTT_NOEXCEPT { return node->is_array; } /** - * @brief Checks whether a type refers to an enum or not. + * @brief Indicates whether a given meta 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 { + bool is_enum() const ENTT_NOEXCEPT { return node->is_enum; } /** - * @brief Checks whether a type refers to an union or not. + * @brief Indicates whether a given meta 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 { + bool is_union() const ENTT_NOEXCEPT { return node->is_union; } /** - * @brief Checks whether a type refers to a class or not. + * @brief Indicates whether a given meta 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 { + bool is_class() const ENTT_NOEXCEPT { return node->is_class; } /** - * @brief Checks whether a type refers to a pointer or not. + * @brief Indicates whether a given meta 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 { + bool is_pointer() const ENTT_NOEXCEPT { return node->is_pointer; } /** - * @brief Checks whether a type refers to a function pointer or not. + * @brief Indicates whether a given meta 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 { + 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. + * @brief Indicates whether a given meta 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 { + 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. + * @brief Indicates whether a given meta 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 { + 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. + * @brief If a given meta type refers to an array type, provides the number + * of elements of the array. + * @return The number of elements of the array if the underlying type is an + * array type, 0 otherwise. */ - [[nodiscard]] bool is_pointer_like() const ENTT_NOEXCEPT { - return node->is_pointer_like; + size_type extent() const ENTT_NOEXCEPT { + return node->extent; } /** - * @brief Checks whether a type refers to a sequence container or not. - * @return True if the type is a sequence container, false otherwise. + * @brief Provides the meta type for which the pointer is defined. + * @return The meta type for which the pointer is defined or this meta type + * if it doesn't refer to a pointer type. */ - [[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 { + 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. + * @brief Provides the meta type for which the array is defined. + * @return The meta type for which the array is defined or this meta type + * if it doesn't refer to an array type. */ - [[nodiscard]] meta_type remove_extent() const ENTT_NOEXCEPT { + 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. + * @brief Iterates all the meta bases of a meta type. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. */ - [[nodiscard]] meta_range base() const ENTT_NOEXCEPT { - return node->base; + template + std::enable_if_t, void> + base(Op op) const { + internal::visit<&internal::meta_type_node::base, meta_base>(op, node); } /** - * @brief Returns the base meta type associated with a given identifier. + * @brief Returns the meta base associated with a given identifier. * @param id Unique identifier. - * @return The base meta type associated with the given identifier, if any. + * @return The meta base 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); + meta_base base(const id_type id) const { + return internal::find_if<&internal::meta_type_node::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. + * @brief Iterates all the meta conversion functions of a meta type. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. */ - [[nodiscard]] meta_range ctor() const ENTT_NOEXCEPT { - return node->ctor; + template + void conv(Op op) const { + internal::visit<&internal::meta_type_node::conv, meta_conv>(op, node); } /** - * @brief Returns a constructor for a given list of types of arguments. - * @tparam Args Constructor arguments. - * @return The requested constructor, if any. + * @brief Returns the meta conversion function associated with a given type. + * @tparam Type The type to use to search for a meta conversion function. + * @return The meta conversion function associated with the given type, if + * any. + */ + template + meta_conv conv() const { + return internal::find_if<&internal::meta_type_node::conv>([type_id = internal::meta_info::resolve()->type_id](const auto* curr) { + return curr->type()->type_id == type_id; + }, node); + } + + /** + * @brief Iterates all the meta constructors of a meta type. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. + */ + template + void ctor(Op op) const { + internal::visit(op, node->ctor); + } + + /** + * @brief Returns the meta constructor that accepts a given list of types of + * arguments. + * @return The requested meta constructor, if any. */ template - [[nodiscard]] meta_ctor ctor() const { - return ctor(node->ctor, std::make_index_sequence{}); + meta_ctor ctor() const { + return ctor(std::index_sequence_for{}); } /** - * @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. + * @brief Iterates all the meta data of a meta type. * - * The data of the base classes will also be visited, if any. + * The meta data of the base classes will also be returned, if any. + * + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. + */ + template + std::enable_if_t, void> + data(Op op) const { + internal::visit<&internal::meta_type_node::data, meta_data>(op, node); + } + + /** + * @brief Returns the meta data associated with a given identifier. + * + * The meta 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. + * @return The meta 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); + meta_data data(const id_type id) const { + return internal::find_if<&internal::meta_type_node::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. + * @brief Iterates all the meta functions of a meta type. * - * 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. + * The meta functions of the base classes will also be returned, if any. + * + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. + */ + template + std::enable_if_t, void> + func(Op op) const { + internal::visit<&internal::meta_type_node::func, meta_func>(op, node); + } + + /** + * @brief Returns the meta function associated with a given identifier. + * + * The meta functions of the base classes will also be visited, if any. * * @param id Unique identifier. - * @return The function associated with the given identifier, if any. + * @return The meta 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); + meta_func func(const id_type id) const { + return internal::find_if<&internal::meta_type_node::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 wrapper 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 + * To create a valid instance, the parameters must be such that a cast or + * conversion to the required types is possible. Otherwise, an empty and + * thus invalid container is returned. * * @tparam Args Types of arguments to use to construct the instance. * @param args Parameters to use to construct the instance. - * @return A wrapper containing the new instance, if any. + * @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)); - } + meta_any construct(Args &&... args) const { + auto construct_if = [this](meta_any* params) { + meta_any any{}; - /** - * @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 wrapper 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{}; + internal::find_if<&internal::meta_type_node::ctor>([params, &any](const auto* curr) { + return (curr->size == sizeof...(args)) && (any = curr->invoke(params)); + }, node); - 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{}; + return any; + }; - 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; - } - } + if constexpr (sizeof...(Args) == 0) { + return construct_if(nullptr); + } + else { + meta_any arguments[]{ std::forward(args)... }; + return construct_if(arguments); } - - return (candidate && !ambiguous) ? candidate->invoke(std::move(instance), args) : meta_any{}; } /** - * @copybrief invoke + * @brief Iterates all the properties assigned to a meta type. * - * @sa invoke + * The properties of the base classes will also be returned, if any. * - * @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 wrapper containing the new instance, if any. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. */ - 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 { - const auto candidate = data(id); - return candidate && candidate.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 id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @return A wrapper containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(const id_type id, meta_handle instance) const { - const auto 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; + template + std::enable_if_t, void> + prop(Op op) const { + internal::visit<&internal::meta_type_node::prop, meta_prop>(op, node); } /** * @brief Returns the property associated with a given key. * - * Properties of the base classes will also be visited, if any. + * The 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); + meta_prop prop(meta_any key) const { + return internal::find_if<&internal::meta_type_node::prop>([key = std::move(key)](const auto* curr) { + return curr->key() == key; + }, node); } /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. + * @brief Returns true if a meta object is valid, false otherwise. + * @return True if the meta object is valid, false otherwise. */ - [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT { + 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. + * @brief Checks if two meta objects refer to the same type. + * @param other The meta object with which to compare. + * @return True if the two meta 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); + bool operator==(const meta_type& other) const ENTT_NOEXCEPT { + return (!node && !other.node) || (node && other.node && node->type_id == other.node->type_id); } - /** - * @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 { - for (auto** it = internal::meta_context::global(); *it; it = &(*it)->next) { - if (*it == node) { - *it = (*it)->next; - break; - } - } - - unregister_all(&node->prop); - unregister_all(&node->base); - unregister_all(&node->conv); - unregister_all<&internal::meta_ctor_node::prop>(&node->ctor); - unregister_all<&internal::meta_data_node::prop>(&node->data); - unregister_all<&internal::meta_func_node::prop>(&node->func); - - node->id = {}; - node->ctor = node->def_ctor; - node->dtor = nullptr; + /*! @brief Removes a meta object from the list of searchable types. */ + void detach() ENTT_NOEXCEPT { + internal::meta_context::detach(node); } private: - node_type* node; + const internal::meta_type_node* 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. + * @brief Checks if two meta objects refer to the same type. + * @param lhs A meta object, either valid or not. + * @param rhs A meta object, either valid or not. + * @return False if the two meta objects refer to the same node, true otherwise. */ - [[nodiscard]] inline bool operator!=(const meta_type& lhs, const meta_type& rhs) ENTT_NOEXCEPT { + 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 { + 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 { + inline meta_type meta_base::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 { + inline meta_type meta_base::type() const ENTT_NOEXCEPT { return node->type(); } - [[nodiscard]] inline meta_type meta_func::parent() const ENTT_NOEXCEPT { + inline meta_type meta_conv::parent() const ENTT_NOEXCEPT { return node->parent; } - [[nodiscard]] inline meta_type meta_func::ret() const ENTT_NOEXCEPT { + inline meta_type meta_conv::type() const ENTT_NOEXCEPT { + return node->type(); + } + + + inline meta_type meta_ctor::parent() const ENTT_NOEXCEPT { + return node->parent; + } + + + inline meta_type meta_ctor::arg(size_type index) const ENTT_NOEXCEPT { + return index < size() ? node->arg(index) : nullptr; + } + + + inline meta_type meta_data::parent() const ENTT_NOEXCEPT { + return node->parent; + } + + + inline meta_type meta_data::type() const ENTT_NOEXCEPT { + return node->type(); + } + + + inline meta_type meta_func::parent() const ENTT_NOEXCEPT { + return node->parent; + } + + + 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); - } - - [[nodiscard]] static bool clear(any& container) { - auto* const cont = any_cast(&container); - return cont && traits_type::clear(*cont); - } - - [[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: - const auto& it = any_cast(from); - if constexpr (KeyOnly) { - static_cast*>(to)->first.emplace(*it); - } - else { - static_cast*>(to)->first.emplacefirst))>(it->first); - static_cast*>(to)->second.emplacesecond))>(it->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); - } - - [[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 { - return value.allow_cast() - && 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); + inline meta_type meta_func::arg(size_type index) const ENTT_NOEXCEPT { + return index < size() ? node->arg(index) : nullptr; } @@ -35113,8 +12762,6 @@ namespace entt { #endif -// #include "node.hpp" - // #include "policy.hpp" #ifndef ENTT_META_POLICY_HPP #define ENTT_META_POLICY_HPP @@ -35127,8 +12774,17 @@ namespace entt { struct as_ref_t {}; - /*! @brief Empty class type used to request the _as cref_ policy. */ - struct as_cref_t {}; + /*! @brief Disambiguation tag. */ + inline constexpr as_ref_t as_ref; + + + /*! @copydoc as_ref_t */ + using as_alias_t [[deprecated("use as_ref_t instead")]] = as_ref_t; + + + /*! @copydoc as_ref */ + [[deprecated("use as_ref instead")]] + inline constexpr as_ref_t as_alias; /*! @brief Empty class type used to request the _as-is_ policy. */ @@ -35142,364 +12798,6 @@ namespace entt { } -#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>>) { - using data_type = type_list_element_t<1u, typename meta_function_helper_t::args_type>; - - if (auto* const clazz = instance->try_cast(); clazz && value.allow_cast()) { - Data(*clazz, value.cast()); - return true; - } - } - else if constexpr (std::is_member_function_pointer_v) { - using data_type = type_list_element_t<0u, typename meta_function_helper_t::args_type>; - - if (auto* const clazz = instance->try_cast(); clazz && value.allow_cast()) { - (clazz->*Data)(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 && value.allow_cast()) { - clazz->*Data = 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 Wraps a value depending on the given policy. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Type Type of value to wrap. - * @param value Value to wrap. - * @return A meta any containing the returned value. - */ - template - meta_any meta_dispatch(Type&& 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::in_place_type, std::forward(value) }; - } - else if constexpr (std::is_same_v) { - static_assert(std::is_lvalue_reference_v, "Invalid type"); - return meta_any{ std::in_place_type&>, std::as_const(value) }; - } - else { - static_assert(std::is_same_v, "Policy not supported"); - return meta_any{ std::forward(value) }; - } - } - - - /** - * @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) { - if constexpr (std::is_function_v>>) { - auto* const clazz = instance->try_cast, const Type, Type>>(); - return clazz ? meta_dispatch(Data(*clazz)) : meta_any{}; - } - else if constexpr (std::is_member_function_pointer_v) { - auto* const clazz = instance->try_cast, const Type, Type>>(); - return clazz ? meta_dispatch((clazz->*Data)()) : meta_any{}; - } - else if constexpr (std::is_member_object_pointer_v) { - if constexpr (!std::is_array_v().*Data)>>>) { - if (auto* clazz = instance->try_cast(); clazz) { - return meta_dispatch(clazz->*Data); - } - else if (auto* fallback = instance->try_cast(); fallback) { - return meta_dispatch(fallback->*Data); - } - } - - return meta_any{}; - } - else if constexpr (std::is_pointer_v) { - if constexpr (std::is_array_v>) { - return meta_any{}; - } - else { - return meta_dispatch(*Data); - } - } - else { - return meta_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]] std::enable_if_t, meta_any> meta_invoke([[maybe_unused]] meta_handle instance, meta_any* args, std::index_sequence) { - using descriptor = meta_function_helper_t; - - const auto invoke = [](auto&& maybe_clazz, auto &&... other) { - if constexpr (std::is_member_function_pointer_v) { - if constexpr (std::is_void_v) { - (std::forward(maybe_clazz).*Candidate)(std::forward(other)...); - return meta_any{ std::in_place_type }; - } - else { - return meta_dispatch((std::forward(maybe_clazz).*Candidate)(std::forward(other)...)); - } - } - else { - if constexpr (std::is_void_v) { - Candidate(std::forward(maybe_clazz), std::forward(other)...); - return meta_any{ std::in_place_type }; - } - else { - return meta_dispatch(Candidate(std::forward(maybe_clazz), std::forward(other)...)); - } - } - }; - - if constexpr (std::is_invocable_v...>) { - if (const auto* const clazz = instance->try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { - return invoke(*clazz, (args + Index)->cast>()...); - } - } - else if constexpr (std::is_invocable_v...>) { - if (auto* const clazz = instance->try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { - return invoke(*clazz, (args + Index)->cast>()...); - } - } - else { - if (((args + Index)->allow_cast>() && ...)) { - return invoke((args + Index)->cast>()...); - } - } - - return meta_any{}; - } - - - /** - * @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. - * @return A meta any containing the returned value, if any. - */ - template - [[nodiscard]] std::enable_if_t, meta_any> meta_invoke(meta_handle, meta_any*, std::index_sequence) { - if constexpr (std::is_void_v) { - Candidate(); - return meta_any{ std::in_place_type }; - } - else { - return meta_dispatch(Candidate()); - } - } - - -} - - #endif @@ -35516,19 +12814,216 @@ namespace entt { 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 + struct meta_function_helper; + + + template + struct meta_function_helper { + using return_type = std::remove_cv_t>; + using args_type = std::tuple>...>; + + static constexpr std::index_sequence_for index_sequence{}; + static constexpr auto is_const = false; + + static auto arg(typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT { + return std::array{ {meta_info::resolve()...}} [index] ; + } + }; + + + template + struct meta_function_helper : meta_function_helper { + static constexpr auto is_const = true; + }; + + + template + constexpr meta_function_helper + to_meta_function_helper(Ret(Class::*)(Args...)); + + + template + constexpr meta_function_helper + to_meta_function_helper(Ret(Class::*)(Args...) const); + + + template + constexpr meta_function_helper + to_meta_function_helper(Ret(*)(Args...)); + + + constexpr void to_meta_function_helper(...); + + + template + using meta_function_helper_t = decltype(to_meta_function_helper(std::declval())); + + + template + meta_any construct(meta_any* const args, std::index_sequence) { + [[maybe_unused]] auto direct = std::make_tuple((args + Indexes)->try_cast()...); + meta_any any{}; + + if (((std::get(direct) || (args + Indexes)->convert()) && ...)) { + any = Type{ (std::get(direct) ? *std::get(direct) : (args + Indexes)->cast())... }; + } + + return any; } - 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)); + template + bool setter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index, [[maybe_unused]] meta_any value) { + bool accepted = false; + + if constexpr (!Const) { + if constexpr (std::is_function_v>> || std::is_member_function_pointer_v) { + using helper_type = meta_function_helper_t; + using data_type = std::tuple_element_t, typename helper_type::args_type>; + static_assert(std::is_invocable_v); + auto* const clazz = instance.try_cast(); + auto* const direct = value.try_cast(); + + if (clazz && (direct || value.convert())) { + std::invoke(Data, *clazz, direct ? *direct : value.cast()); + accepted = true; + } + } + else if constexpr (std::is_member_object_pointer_v) { + using data_type = std::remove_cv_t().*Data)>>; + static_assert(std::is_invocable_v); + auto* const clazz = instance.try_cast(); + + if constexpr (std::is_array_v) { + using underlying_type = std::remove_extent_t; + auto* const direct = value.try_cast(); + auto* const idx = index.try_cast(); + + if (clazz && idx && (direct || value.convert())) { + std::invoke(Data, clazz)[*idx] = direct ? *direct : value.cast(); + accepted = true; + } + } + else { + auto* const direct = value.try_cast(); + + if (clazz && (direct || value.convert())) { + std::invoke(Data, clazz) = (direct ? *direct : value.cast()); + accepted = true; + } + } + } + else { + static_assert(std::is_pointer_v); + using data_type = std::remove_cv_t>; + + if constexpr (std::is_array_v) { + using underlying_type = std::remove_extent_t; + auto* const direct = value.try_cast(); + auto* const idx = index.try_cast(); + + if (idx && (direct || value.convert())) { + (*Data)[*idx] = (direct ? *direct : value.cast()); + accepted = true; + } + } + else { + auto* const direct = value.try_cast(); + + if (direct || value.convert()) { + *Data = (direct ? *direct : value.cast()); + accepted = true; + } + } + } + } + + return accepted; + } + + + template + meta_any getter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index) { + 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::ref(std::forward(value)) }; + } + else { + static_assert(std::is_same_v); + return meta_any{ std::forward(value) }; + } + }; + + if constexpr (std::is_function_v>> || std::is_member_function_pointer_v) { + static_assert(std::is_invocable_v); + auto* const clazz = instance.try_cast(); + return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{}; + } + else if constexpr (std::is_member_object_pointer_v) { + using data_type = std::remove_cv_t().*Data)>>; + static_assert(std::is_invocable_v); + auto* const clazz = instance.try_cast(); + + if constexpr (std::is_array_v) { + auto* const idx = index.try_cast(); + return (clazz && idx) ? dispatch(std::invoke(Data, clazz)[*idx]) : meta_any{}; + } + else { + return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{}; + } } else { - return node && ((node->id == id && node != owner) || find_if_not(id, node->next, owner)); + static_assert(std::is_pointer_v>); + + if constexpr (std::is_array_v>) { + auto* const idx = index.try_cast(); + return idx ? dispatch((*Data)[*idx]) : meta_any{}; + } + else { + return dispatch(*Data); + } + } + } + + + template + meta_any invoke([[maybe_unused]] meta_any instance, meta_any* args, std::index_sequence) { + using helper_type = meta_function_helper_t; + + auto dispatch = [](auto *... params) { + if constexpr (std::is_void_v || std::is_same_v) { + std::invoke(Candidate, *params...); + return meta_any{ std::in_place_type }; + } + else if constexpr (std::is_same_v) { + return meta_any{ std::ref(std::invoke(Candidate, *params...)) }; + } + else { + static_assert(std::is_same_v); + return meta_any{ std::invoke(Candidate, *params...) }; + } + }; + + [[maybe_unused]] const auto direct = std::make_tuple([](meta_any* any, auto* value) { + using arg_type = std::remove_reference_t; + + if (!value && any->convert()) { + value = any->try_cast(); + } + + return value; + }(args + Indexes, (args + Indexes)->try_cast>())...); + + if constexpr (std::is_function_v>>) { + return (std::get(direct) && ...) ? dispatch(std::get(direct)...) : meta_any{}; + } + else { + auto* const clazz = instance.try_cast(); + return (clazz && (std::get(direct) && ...)) ? dispatch(clazz, std::get(direct)...) : meta_any{}; } } @@ -35538,7 +13033,7 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ @@ -35551,7 +13046,7 @@ namespace entt { * there are no subtle errors at runtime. */ template - struct meta_factory; + class meta_factory; /** @@ -35560,8 +13055,11 @@ namespace entt { * @tparam Spec Property specialization pack used to disambiguate overloads. */ template - struct meta_factory : public meta_factory { - private: + class meta_factory : public meta_factory { + bool exists(const meta_any& key, const internal::meta_prop_node* node) ENTT_NOEXCEPT { + return node && (node->key() == key || exists(key, node->next)); + } + template void unpack(std::index_sequence, std::tuple property, Other &&... other) { unroll(choice<3>, std::move(std::get(property))..., std::forward(other)...); @@ -35593,25 +13091,28 @@ namespace entt { template void unroll(choice_t<0>) {} - template - void assign(Key&& key, meta_any value = {}) { - static meta_any property[2u]{}; + template + void assign(Key&& key, Value &&... value) { + static const auto property{ std::make_tuple(std::forward(key), std::forward(value)...) }; static internal::meta_prop_node node{ nullptr, - property[0u], - property[1u] + []() -> meta_any { + return std::get<0>(property); + }, + []() -> meta_any { + if constexpr (sizeof...(Value) == 0) { + return {}; + } + else { + return std::get<1>(property); + } +} }; - entt::meta_any instance{ std::forward(key) }; - ENTT_ASSERT(!internal::find_if_not(&instance, *curr, &node), "Duplicate key"); - property[0u] = std::move(instance); - property[1u] = std::move(value); - - if (!internal::find_if(&node, *curr)) { - node.next = *curr; - *curr = &node; - } + ENTT_ASSERT(!exists(node.key(), *curr)); + node.next = *curr; + *curr = &node; } public: @@ -35619,7 +13120,7 @@ namespace entt { * @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 + meta_factory(entt::internal::meta_prop_node** target) ENTT_NOEXCEPT : curr{ target } {} @@ -35663,7 +13164,7 @@ namespace entt { } private: - internal::meta_prop_node** curr; + entt::internal::meta_prop_node** curr; }; @@ -35672,26 +13173,41 @@ namespace entt { * @tparam Type Reflected type for which the factory was created. */ template - struct meta_factory { + class meta_factory { + template + bool exists(const Node* candidate, const Node* node) ENTT_NOEXCEPT { + return node && (node == candidate || exists(candidate, node->next)); + } + + template + bool exists(const id_type id, const Node* node) ENTT_NOEXCEPT { + return node && (node->id == id || exists(id, node->next)); + } + + public: /** * @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 type(const id_type id = type_info::id()) { auto* const node = internal::meta_info::resolve(); - ENTT_ASSERT(!internal::find_if_not(id, *internal::meta_context::global(), node), "Duplicate identifier"); + ENTT_ASSERT(!exists(id, *internal::meta_context::global)); + ENTT_ASSERT(!exists(node, *internal::meta_context::global)); node->id = id; - - if (!internal::find_if(node, *internal::meta_context::global())) { - node->next = *internal::meta_context::global(); - *internal::meta_context::global() = node; - } + node->next = *internal::meta_context::global; + *internal::meta_context::global = node; return meta_factory{&node->prop}; } + /*! @copydoc type */ + [[deprecated("use ::type instead")]] + auto alias(const id_type id) ENTT_NOEXCEPT { + return type(id); + } + /** * @brief Assigns a meta base to a meta type. * @@ -35702,22 +13218,51 @@ namespace entt { */ template auto base() ENTT_NOEXCEPT { - static_assert(std::is_base_of_v, "Invalid base type"); + static_assert(std::is_base_of_v); 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)); + [](void* instance) ENTT_NOEXCEPT -> void* { + return static_cast(static_cast(instance)); } }; - if (!internal::find_if(&node, type->base)) { - node.next = type->base; - type->base = &node; - } + ENTT_ASSERT(!exists(&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); + 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)); + } + }; + + ENTT_ASSERT(!exists(&node, type->conv)); + node.next = type->conv; + type->conv = &node; return meta_factory{}; } @@ -35735,77 +13280,22 @@ namespace entt { * @return A meta factory for the parent type. */ template - std::enable_if_t, meta_factory> 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 (static_cast(instance)->*Candidate)(); - } - }; - - if (!internal::find_if(&node, type->conv)) { - node.next = type->conv; - type->conv = &node; - } - - return meta_factory{}; - } - - /*! @copydoc conv */ - template - std::enable_if_t, meta_factory> 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 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 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"); + 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, + &internal::meta_info::resolve, [](const void* instance) -> meta_any { - return static_cast(*static_cast(instance)); + return std::invoke(Candidate, *static_cast(instance)); } }; - if (!internal::find_if(&node, type->conv)) { - node.next = type->conv; - type->conv = &node; - } + ENTT_ASSERT(!exists(&node, type->conv)); + node.next = type->conv; + type->conv = &node; return meta_factory{}; } @@ -35813,41 +13303,38 @@ namespace entt { /** * @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.
+ * Free functions 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. + * type is a built-in one or a free function. * - * @tparam Candidate The actual function to use as a constructor. + * @tparam Func 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 + 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"); + using helper_type = internal::meta_function_helper_t; + static_assert(std::is_same_v); 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{}); + helper_type::index_sequence.size(), + &helper_type::arg, + [](meta_any* const any) { + return internal::invoke({}, any, helper_type::index_sequence); } }; - if (!internal::find_if(&node, type->ctor)) { - node.next = type->ctor; - type->ctor = &node; - } + ENTT_ASSERT(!exists(&node, type->ctor)); + node.next = type->ctor; + type->ctor = &node; - return meta_factory>{&node.prop}; + return meta_factory>{&node.prop}; } /** @@ -35862,26 +13349,23 @@ namespace entt { */ template auto ctor() ENTT_NOEXCEPT { - using descriptor = meta_function_helper_t; + using helper_type = internal::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{}); + helper_type::index_sequence.size(), + &helper_type::arg, + [](meta_any* const any) { + return internal::construct>...>(any, helper_type::index_sequence); } }; - if (!internal::find_if(&node, type->ctor)) { - node.next = type->ctor; - type->ctor = &node; - } + ENTT_ASSERT(!exists(&node, type->ctor)); + node.next = type->ctor; + type->ctor = &node; return meta_factory{&node.prop}; } @@ -35904,13 +13388,21 @@ namespace entt { */ template auto dtor() ENTT_NOEXCEPT { - static_assert(std::is_invocable_v, "The function doesn't accept an object of the type provided"); + static_assert(std::is_invocable_v); auto* const type = internal::meta_info::resolve(); - type->dtor = [](void* instance) { - Func(*static_cast(instance)); + static internal::meta_dtor_node node{ + type, + [](void* instance) { + if (instance) { + std::invoke(Func, *static_cast(instance)); + } + } }; + ENTT_ASSERT(!type->dtor); + type->dtor = &node; + return meta_factory{}; } @@ -35929,35 +13421,69 @@ namespace entt { */ 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(); + auto* const type = internal::meta_info::resolve(); + internal::meta_data_node* curr = nullptr; + + if constexpr (std::is_same_v) { + static_assert(std::is_same_v); 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 + true, + &internal::meta_info::resolve, + [](meta_any, meta_any, meta_any) { return false; }, + [](meta_any, meta_any) -> meta_any { return Data; } }; - ENTT_ASSERT(!internal::find_if_not(id, type->data, &node), "Duplicate identifier"); - node.id = id; - - if (!internal::find_if(&node, type->data)) { - node.next = type->data; - type->data = &node; - } - - return meta_factory>{&node.prop}; + curr = &node; } + else if constexpr (std::is_member_object_pointer_v) { + using data_type = std::remove_reference_t().*Data)>; + + static internal::meta_data_node node{ + {}, + type, + nullptr, + nullptr, + std::is_const_v, + !std::is_member_object_pointer_v, + &internal::meta_info::resolve, + &internal::setter, Type, Data>, + &internal::getter + }; + + curr = &node; + } + else { + static_assert(std::is_pointer_v>); + using data_type = std::remove_pointer_t>; + + static internal::meta_data_node node{ + {}, + type, + nullptr, + nullptr, + std::is_const_v, + !std::is_member_object_pointer_v, + &internal::meta_info::resolve, + &internal::setter, Type, Data>, + &internal::getter + }; + + curr = &node; + } + + ENTT_ASSERT(!exists(id, type->data)); + ENTT_ASSERT(!exists(curr, type->data)); + curr->id = id; + curr->next = type->data; + type->data = curr; + + return meta_factory>{&curr->prop}; } /** @@ -35982,7 +13508,8 @@ namespace entt { */ template auto data(const id_type id) ENTT_NOEXCEPT { - using underlying_type = std::remove_reference_t>; + using underlying_type = std::invoke_result_t; + static_assert(std::is_invocable_v); auto* const type = internal::meta_info::resolve(); static internal::meta_data_node node{ @@ -35990,20 +13517,18 @@ namespace entt { type, nullptr, nullptr, - std::is_same_v || (std::is_member_object_pointer_v && std::is_const_v), + false, false, &internal::meta_info::resolve, - &meta_setter, - &meta_getter + &internal::setter, + &internal::getter }; - ENTT_ASSERT(!internal::find_if_not(id, type->data, &node), "Duplicate identifier"); + ENTT_ASSERT(!exists(id, type->data)); + ENTT_ASSERT(!exists(&node, type->data)); node.id = id; - - if (!internal::find_if(&node, type->data)) { - node.next = type->data; - type->data = &node; - } + node.next = type->data; + type->data = &node; return meta_factory, std::integral_constant>{&node.prop}; } @@ -36023,7 +13548,7 @@ namespace entt { */ template auto func(const id_type id) ENTT_NOEXCEPT { - using descriptor = meta_function_helper_t; + using helper_type = internal::meta_function_helper_t; auto* const type = internal::meta_info::resolve(); static internal::meta_func_node node{ @@ -36031,35 +13556,64 @@ namespace entt { 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{}); + helper_type::index_sequence.size(), + helper_type::is_const, + !std::is_member_function_pointer_v, + &internal::meta_info, void, typename helper_type::return_type>>::resolve, + &helper_type::arg, + [](meta_any instance, meta_any* args) { + return internal::invoke(std::move(instance), args, helper_type::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); - + ENTT_ASSERT(!exists(id, type->func)); + ENTT_ASSERT(!exists(&node, type->func)); node.id = id; - node.next = *it; - *it = &node; + node.next = type->func; + type->func = &node; return meta_factory>{&node.prop}; } + + /** + * @brief Resets a meta type and all its parts. + * + * This function resets a meta 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. + * + * @return An extended meta factory for the given type. + */ + auto reset() ENTT_NOEXCEPT { + auto* const node = internal::meta_info::resolve(); + + internal::meta_context::detach(node); + + 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->next = nullptr; + node->dtor = nullptr; + + return meta_factory{&node->prop}; + } }; @@ -36072,10 +13626,10 @@ namespace entt { * dedicated factory. * * @tparam Type Type to reflect. - * @return A meta factory for the given type. + * @return An meta factory for the given type. */ template - [[nodiscard]] auto meta() ENTT_NOEXCEPT { + inline meta_factory 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}; @@ -36088,2743 +13642,15 @@ namespace entt { #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, DEREF, SEQ, ASSOC }; - - using vtable_type = void(const operation, const any&, void*); - - template - static void basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any& from, [[maybe_unused]] void* to) { - static_assert(std::is_same_v>, Type>, "Invalid type"); - - if constexpr (!std::is_void_v) { - switch (op) { - case operation::DTOR: - if (auto* curr = static_cast(to); curr->dtor && from.owner()) { - curr->dtor(const_cast(from).data()); - } - break; - case operation::DEREF: - 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::element_type>, void>) { - using in_place_type = decltype(adl_meta_pointer_like::dereference(any_cast(from))); - static_cast(to)->emplace(adl_meta_pointer_like::dereference(any_cast(from))); - } - } - case operation::SEQ: - if constexpr (is_complete_v>) { - *static_cast(to) = { std::in_place_type, std::move(const_cast(from)) }; - } - break; - case operation::ASSOC: - if constexpr (is_complete_v>) { - *static_cast(to) = { std::in_place_type, std::move(const_cast(from)) }; - } - break; - } - } - } - - meta_any(const meta_any& other, any ref) ENTT_NOEXCEPT - : storage{ std::move(ref) }, - node{ storage ? other.node : nullptr }, - vtable{ storage ? other.vtable : &basic_vtable } - {} - - public: - /*! @brief Default constructor. */ - meta_any() ENTT_NOEXCEPT - : storage{}, - node{}, - vtable{ &basic_vtable } - {} - - /** - * @brief Constructs a wrapper 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 wrapper 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{} - { - // invokes deprecated assignment operator (and avoids issues with vs2017) - *this = value; - } - - /** - * @brief Constructs a wrapper 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) - : storage{ std::forward(value) }, - node{ internal::meta_info>::resolve() }, - vtable{ &basic_vtable> } - {} - - /** - * @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) ENTT_NOEXCEPT { - 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 - [[deprecated("Use std::in_place_type, entt::make_meta, emplace or forward_as_meta instead")]] - 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 wrapper 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 wrapper 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 instance = try_cast>(); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); - } - - /*! @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, "Invalid 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.as_ref(), &proxy); - return proxy; - } - - /*! @copydoc as_sequence_container */ - [[nodiscard]] meta_sequence_container as_sequence_container() const ENTT_NOEXCEPT { - meta_sequence_container proxy; - vtable(operation::SEQ, storage.as_ref(), &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.as_ref(), &proxy); - return proxy; - } - - /*! @copydoc as_associative_container */ - [[nodiscard]] meta_associative_container as_associative_container() const ENTT_NOEXCEPT { - meta_associative_container proxy; - vtable(operation::ASSOC, storage.as_ref(), &proxy); - return proxy; - } - - /** - * @brief Indirection operator for dereferencing opaque objects. - * @return A wrapper that shares a reference to an unmanaged object if the - * wrapped element is dereferenceable, an invalid meta any otherwise. - */ - [[nodiscard]] meta_any operator*() const ENTT_NOEXCEPT { - meta_any ret{}; - vtable(operation::DEREF, 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 wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any as_ref() ENTT_NOEXCEPT { - return meta_any{ *this, storage.as_ref() }; - } - - /*! @copydoc as_ref */ - [[nodiscard]] meta_any as_ref() const ENTT_NOEXCEPT { - return meta_any{ *this, storage.as_ref() }; - } - - private: - any storage; - internal::meta_type_node* node; - vtable_type* vtable; - }; - - - /** - * @brief Checks if two wrappers differ in their content. - * @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. - */ - [[nodiscard]] inline bool operator!=(const meta_any& lhs, const meta_any& rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); - } - - - /** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @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. - * @return A properly initialized wrapper for an object of the given type. - */ - template - meta_any make_meta(Args &&... args) { - return meta_any{ std::in_place_type, std::forward(args)... }; - } - - - /** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ - template - meta_any forward_as_meta(Type&& value) { - return meta_any{ std::in_place_type, std::decay_t, Type>>, std::forward(value) }; - } - - - /** - * @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 wrapper 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 wrapper 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 wrapper 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 wrapper 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 wrapper 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 wrapper 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 wrapper 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 wrapper 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; - } - - template - void unregister_all(Node** curr) { - while (*curr) { - (unregister_all(&((*curr)->*Member)), ...); - *curr = std::exchange((*curr)->next, 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 wrapper 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 wrapper 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 wrapper 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 wrapper 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 { - const auto candidate = data(id); - return candidate && candidate.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 id Unique identifier. - * @param instance An opaque instance of the underlying type. - * @return A wrapper containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(const id_type id, meta_handle instance) const { - const auto 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 { - for (auto** it = internal::meta_context::global(); *it; it = &(*it)->next) { - if (*it == node) { - *it = (*it)->next; - break; - } - } - - unregister_all(&node->prop); - unregister_all(&node->base); - unregister_all(&node->conv); - unregister_all<&internal::meta_ctor_node::prop>(&node->ctor); - unregister_all<&internal::meta_data_node::prop>(&node->data); - unregister_all<&internal::meta_func_node::prop>(&node->func); - - 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); - } - - [[nodiscard]] static bool clear(any& container) { - auto* const cont = any_cast(&container); - return cont && traits_type::clear(*cont); - } - - [[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: - const auto& it = any_cast(from); - if constexpr (KeyOnly) { - static_cast*>(to)->first.emplace(*it); - } - else { - static_cast*>(to)->first.emplacefirst))>(it->first); - static_cast*>(to)->second.emplacesecond))>(it->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); - } - - [[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 { - return value.allow_cast() - && 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 // #include "meta.hpp" -// #include "node.hpp" - -// #include "range.hpp" - namespace entt { @@ -38836,17 +13662,22 @@ namespace entt { * @return The meta type associated with the given type, if any. */ template - [[nodiscard]] meta_type resolve() ENTT_NOEXCEPT { + inline 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. + * @brief Returns the first meta type that satisfies specific criteria, if any. + * @tparam Func Type of the unary predicate to use to test the meta types. + * @param func Unary predicate which returns true for the required element. + * @return The first meta type satisfying the condition, if any. */ - [[nodiscard]] inline meta_range resolve() { - return *internal::meta_context::global(); + template + inline meta_type resolve_if(Func func) ENTT_NOEXCEPT { + return internal::find_if([&func](const auto* curr) { + return func(meta_type{ curr }); + }, *internal::meta_context::global); } @@ -38855,31 +13686,37 @@ namespace entt { * @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 {}; + inline meta_type resolve_id(const id_type id) ENTT_NOEXCEPT { + return resolve_if([id](const auto type) { return type.id() == id; }); } /** - * @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. + * @brief Returns the meta type associated with a given type id, if any. + * @param id Unique identifier. + * @return The meta type associated with the given type id, 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; - } - } + inline meta_type resolve_type(const id_type id) ENTT_NOEXCEPT { + return resolve_if([id](const auto type) { return type.type_id() == id; }); + } - return {}; + + /*! @copydoc resolve_id */ + [[deprecated("use entt::resolve_id instead")]] + inline meta_type resolve(const id_type id) ENTT_NOEXCEPT { + return resolve_id(id); + } + + + /** + * @brief Iterates all the reflected types. + * @tparam Op Type of the function object to invoke. + * @param op A valid function object. + */ + template + inline std::enable_if_t, void> + resolve(Op op) { + internal::visit(op, *internal::meta_context::global); } @@ -38888,611 +13725,111 @@ namespace entt { #endif -// #include "meta/template.hpp" -#ifndef ENTT_META_TEMPLATE_HPP -#define ENTT_META_TEMPLATE_HPP +// #include "meta/policy.hpp" +// #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_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws +#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 + + +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 +#endif + + +#ifndef ENTT_ASSERT +# include +# define ENTT_ASSERT(condition) assert(condition) +#endif + + +#ifndef ENTT_NO_ETO +# include +# define ENTT_IS_EMPTY(Type) std::is_empty_v +#else +# include +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) +#endif + + +#ifndef ENTT_STANDARD_CPP +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ +# endif +#endif + + +#endif // #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 +#ifndef ENTT_CORE_TYPE_TRAITS_HPP +#define ENTT_CORE_TYPE_TRAITS_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>>) { - using data_type = type_list_element_t<1u, typename meta_function_helper_t::args_type>; - - if (auto* const clazz = instance->try_cast(); clazz && value.allow_cast()) { - Data(*clazz, value.cast()); - return true; - } - } - else if constexpr (std::is_member_function_pointer_v) { - using data_type = type_list_element_t<0u, typename meta_function_helper_t::args_type>; - - if (auto* const clazz = instance->try_cast(); clazz && value.allow_cast()) { - (clazz->*Data)(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 && value.allow_cast()) { - clazz->*Data = 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 Wraps a value depending on the given policy. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Type Type of value to wrap. - * @param value Value to wrap. - * @return A meta any containing the returned value. - */ - template - meta_any meta_dispatch(Type&& 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::in_place_type, std::forward(value) }; - } - else if constexpr (std::is_same_v) { - static_assert(std::is_lvalue_reference_v, "Invalid type"); - return meta_any{ std::in_place_type&>, std::as_const(value) }; - } - else { - static_assert(std::is_same_v, "Policy not supported"); - return meta_any{ std::forward(value) }; - } - } - - - /** - * @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) { - if constexpr (std::is_function_v>>) { - auto* const clazz = instance->try_cast, const Type, Type>>(); - return clazz ? meta_dispatch(Data(*clazz)) : meta_any{}; - } - else if constexpr (std::is_member_function_pointer_v) { - auto* const clazz = instance->try_cast, const Type, Type>>(); - return clazz ? meta_dispatch((clazz->*Data)()) : meta_any{}; - } - else if constexpr (std::is_member_object_pointer_v) { - if constexpr (!std::is_array_v().*Data)>>>) { - if (auto* clazz = instance->try_cast(); clazz) { - return meta_dispatch(clazz->*Data); - } - else if (auto* fallback = instance->try_cast(); fallback) { - return meta_dispatch(fallback->*Data); - } - } - - return meta_any{}; - } - else if constexpr (std::is_pointer_v) { - if constexpr (std::is_array_v>) { - return meta_any{}; - } - else { - return meta_dispatch(*Data); - } - } - else { - return meta_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]] std::enable_if_t, meta_any> meta_invoke([[maybe_unused]] meta_handle instance, meta_any* args, std::index_sequence) { - using descriptor = meta_function_helper_t; - - const auto invoke = [](auto&& maybe_clazz, auto &&... other) { - if constexpr (std::is_member_function_pointer_v) { - if constexpr (std::is_void_v) { - (std::forward(maybe_clazz).*Candidate)(std::forward(other)...); - return meta_any{ std::in_place_type }; - } - else { - return meta_dispatch((std::forward(maybe_clazz).*Candidate)(std::forward(other)...)); - } - } - else { - if constexpr (std::is_void_v) { - Candidate(std::forward(maybe_clazz), std::forward(other)...); - return meta_any{ std::in_place_type }; - } - else { - return meta_dispatch(Candidate(std::forward(maybe_clazz), std::forward(other)...)); - } - } - }; - - if constexpr (std::is_invocable_v...>) { - if (const auto* const clazz = instance->try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { - return invoke(*clazz, (args + Index)->cast>()...); - } - } - else if constexpr (std::is_invocable_v...>) { - if (auto* const clazz = instance->try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { - return invoke(*clazz, (args + Index)->cast>()...); - } - } - else { - if (((args + Index)->allow_cast>() && ...)) { - return invoke((args + Index)->cast>()...); - } - } - - return meta_any{}; - } - - - /** - * @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. - * @return A meta any containing the returned value, if any. - */ - template - [[nodiscard]] std::enable_if_t, meta_any> meta_invoke(meta_handle, meta_any*, std::index_sequence) { - if constexpr (std::is_void_v) { - Candidate(); - return meta_any{ std::in_place_type }; - } - else { - return meta_dispatch(Candidate()); - } - } - - -} - - -#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 -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) +#ifndef ENTT_NOEXCEPT # define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) #endif -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws #endif @@ -39510,412 +13847,37 @@ namespace std { #endif -#ifdef ENTT_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 #endif -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT +#ifndef ENTT_ASSERT # include -# define ENTT_ASSERT(condition, ...) assert(condition) +# define ENTT_ASSERT(condition) assert(condition) #endif -#ifdef ENTT_NO_ETO +#ifndef ENTT_NO_ETO # include -# define ENTT_IGNORE_IF_EMPTY std::false_type +# define ENTT_IS_EMPTY(Type) std::is_empty_v #else # include -# define ENTT_IGNORE_IF_EMPTY std::true_type +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) #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 "../config/config.h" -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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/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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 - -// #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 +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ # endif #endif @@ -39932,6 +13894,25 @@ namespace entt { // #include "../config/config.h" // #include "fwd.hpp" +#ifndef ENTT_CORE_FWD_HPP +#define ENTT_CORE_FWD_HPP + + +// #include "../config/config.h" + + + +namespace entt { + + + /*! @brief Alias declaration for type identifiers. */ + using id_type = ENTT_ID_TYPE; + + +} + + +#endif @@ -39972,7 +13953,7 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ @@ -39997,8 +13978,8 @@ namespace entt { const Char* str; }; - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { + // Fowler-Noll-Vo hash function v. 1a - the good + static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { auto value = traits_type::offset; while (*curr != 0) { @@ -40014,18 +13995,6 @@ namespace entt { /*! @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. * @@ -40042,7 +14011,7 @@ namespace entt { * @return The numeric representation of the string. */ template - [[nodiscard]] static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { + static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { return helper(str); } @@ -40051,10 +14020,22 @@ namespace entt { * @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 { + static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { return helper(wrapper.str); } + /** + * @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. + */ + static 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 Constructs an empty hashed string. */ constexpr basic_hashed_string() ENTT_NOEXCEPT : str{ nullptr }, hash{} @@ -40092,7 +14073,7 @@ namespace entt { * @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 { + constexpr const value_type* data() const ENTT_NOEXCEPT { return str; } @@ -40100,25 +14081,25 @@ namespace entt { * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the instance. */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { + constexpr hash_type value() const ENTT_NOEXCEPT { return hash; } /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type* () const ENTT_NOEXCEPT { return data(); } + 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(); } + 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 { + constexpr bool operator==(const basic_hashed_string& other) const ENTT_NOEXCEPT { return hash == other.hash; } @@ -40139,7 +14120,7 @@ namespace entt { * @param str Human-readable identifer. */ template - basic_hashed_string(const Char(&str)[N]) + basic_hashed_string(const Char(&str)[N]) ENTT_NOEXCEPT ->basic_hashed_string; @@ -40151,7 +14132,7 @@ namespace entt { * @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 { + constexpr bool operator!=(const basic_hashed_string& lhs, const basic_hashed_string& rhs) ENTT_NOEXCEPT { return !(lhs == rhs); } @@ -40164,32 +14145,26 @@ namespace entt { 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 }; - } - - - } +/** + * @brief User defined literal for hashed strings. + * @param str The literal without its suffix. + * @return A properly initialized hashed string. + */ +constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(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. + */ +constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t* str, std::size_t) ENTT_NOEXCEPT { + return entt::hashed_wstring{ str }; } @@ -40203,267 +14178,19 @@ namespace entt { /** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. + * @brief Wraps a static constant. + * @tparam Value A static constant. */ - - - 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; - } - - - } + template + using integral_constant = std::integral_constant; /** - * Internal details not to be documented. - * @endcond + * @brief Alias template to ease the creation of named values. + * @tparam Value A constant value at least convertible to `id_type`. */ - - - /** - * @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 -// #include "../config/config.h" - -// #include "fwd.hpp" - - - -namespace entt { + template + using tag = integral_constant; /** @@ -40475,7 +14202,7 @@ namespace entt { // Unfortunately, doxygen cannot parse such a construct. /*! @cond TURN_OFF_DOXYGEN */ : choice_t - /*! @endcond */ + /*! @endcond TURN_OFF_DOXYGEN */ {}; @@ -40492,146 +14219,32 @@ namespace entt { 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 A class to use to push around lists of types, nothing more. */ + template + struct type_list {}; + + + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_size; /** - * @brief Helper type. - * @tparam Type A type. + * @brief Compile-time number of elements in a type list. + * @tparam Type Types provided by the type list. */ - 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 + template + struct type_list_size> + : std::integral_constant {}; /** * @brief Helper variable template. - * @tparam Type The type of which to return the size. + * @tparam List Type list. */ - template - inline constexpr std::size_t 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 {}; } + template + inline constexpr auto type_list_size_v = type_list_size::value; /*! @brief Primary template isn't defined on purpose. */ @@ -40717,396 +14330,25 @@ namespace entt { /** - * @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. + * @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 type_list_contains; + template> + struct is_equality_comparable : std::false_type {}; - /** - * @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...> {}; + /*! @copydoc is_equality_comparable */ + template + struct is_equality_comparable() == std::declval())>> : std::true_type {}; /** * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ - template - inline constexpr bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. + * @tparam Type Potentially equality comparable type. */ template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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; + inline constexpr auto is_equality_comparable_v = is_equality_comparable::value; /** @@ -41115,7 +14357,7 @@ namespace entt { */ template class member_class { - static_assert(std::is_member_pointer_v, "Invalid pointer type to non-static member object or function"); + static_assert(std::is_member_pointer_v); template static Class* clazz(Ret(Class::*)(Args...)); @@ -41143,1871 +14385,18 @@ namespace entt { } -#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 : std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE }; - enum class policy : std::uint8_t { OWNER, REF, CREF }; - - using storage_type = std::aligned_storage_t; - using vtable_type = const void* (const operation, const basic_any&, 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 constexpr policy type_to_policy() { - if constexpr (std::is_lvalue_reference_v) { - if constexpr (std::is_const_v>) { - return policy::CREF; - } - else { - return policy::REF; - } - } - else { - return policy::OWNER; - } - } - - 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 const void* basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any& from, [[maybe_unused]] void* to) { - static_assert(std::is_same_v>, Type>, "Invalid type"); - - if constexpr (!std::is_void_v) { - const Type* instance = (in_situ && from.mode == policy::OWNER) - ? ENTT_LAUNDER(reinterpret_cast(&from.storage)) - : static_cast(from.instance); - - switch (op) { - case operation::COPY: - if constexpr (std::is_copy_constructible_v) { - static_cast(to)->emplace(*instance); - } - break; - case operation::MOVE: - if constexpr (in_situ) { - if (from.mode == policy::OWNER) { - return new (&static_cast(to)->storage) Type{ std::move(*const_cast(instance)) }; - } - } - - return (static_cast(to)->instance = std::exchange(const_cast(from).instance, nullptr)); - case operation::DTOR: - if (from.mode == policy::OWNER) { - if constexpr (in_situ) { - instance->~Type(); - } - else if constexpr (std::is_array_v) { - delete[] instance; - } - else { - delete instance; - } - } - break; - case operation::COMP: - return compare(instance, (*static_cast(to))->data()) ? to : nullptr; - case operation::ADDR: - if (from.mode == policy::CREF) { - return nullptr; - } - [[fallthrough]]; - case operation::CADDR: - return instance; - case operation::TYPE: - *static_cast(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 (sizeof...(Args) != 0u && std::is_aggregate_v) { - new (&storage) Type{ std::forward(args)... }; - } - else { - new (&storage) Type(std::forward(args)...); - } - } - else { - if constexpr (sizeof...(Args) != 0u && std::is_aggregate_v) { - instance = new Type{ std::forward(args)... }; - } - else { - instance = new Type(std::forward(args)...); - } - } - } - } - - basic_any(const basic_any& other, const policy pol) ENTT_NOEXCEPT - : instance{ other.data() }, - vtable{ other.vtable }, - mode{ pol } - {} - - public: - /*! @brief Size of the internal storage. */ - static constexpr auto length = Len; - /*! @brief Alignment requirement. */ - static constexpr auto alignment = Align; - - /*! @brief Default constructor. */ - basic_any() ENTT_NOEXCEPT - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - {} - - /** - * @brief Constructs a wrapper 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>> }, - mode{ type_to_policy() } - { - initialize(std::forward(args)...); - } - - /** - * @brief Constructs a wrapper 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{} - { - // invokes deprecated assignment operator (and avoids issues with vs2017) - *this = value; - } - - /** - * @brief Constructs a wrapper 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) - : instance{}, - vtable{ &basic_vtable> }, - mode{ policy::OWNER } - { - initialize>(std::forward(value)); - } - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any& other) - : instance{}, - vtable{ &basic_vtable }, - mode{ policy::OWNER } - { - other.vtable(operation::COPY, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any&& other) ENTT_NOEXCEPT - : instance{}, - vtable{ other.vtable }, - mode{ other.mode } - { - 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) { - reset(); - 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) ENTT_NOEXCEPT { - std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr); - other.vtable(operation::MOVE, other, this); - mode = other.mode; - 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 - [[deprecated("Use std::in_place_type, entt::make_any, emplace or forward_as_any instead")]] - 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); - mode = type_to_policy(); - initialize(std::forward(args)...); - } - - /*! @brief Destroys contained object */ - void reset() { - std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); - mode = policy::OWNER; - } - - /** - * @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 { - const basic_any* trampoline = &other; - return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data()); - } - - /** - * @brief Aliasing constructor. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT { - return basic_any{ *this, (mode == policy::CREF ? policy::CREF : policy::REF) }; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT { - return basic_any{ *this, policy::CREF }; - } - - /** - * @brief Returns true if a wrapper owns its object, false otherwise. - * @return True if the wrapper owns its object, false otherwise. - */ - [[nodiscard]] bool owner() const ENTT_NOEXCEPT { - return (mode == policy::OWNER); - } - - private: - union { const void* instance; storage_type storage; }; - vtable_type* vtable; - policy mode; - }; - - - /** - * @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, "Invalid 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, "Invalid 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, "Invalid 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); - } - - - /** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - * @return A properly initialized wrapper for an object of the given type. - */ - template::length, std::size_t Align = basic_any::alignment, typename... Args> - basic_any make_any(Args &&... args) { - return basic_any{std::in_place_type, std::forward(args)...}; - } - - - /** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ - template::length, std::size_t Align = basic_any::alignment, typename Type> - basic_any forward_as_any(Type&& value) { - return basic_any{std::in_place_type, std::decay_t, Type>>, std::forward(value)}; - } - - -} - - -#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 -// #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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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 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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 +/** + * @brief Defines an enum class to use for opaque identifiers and a dedicate + * `to_integer` function to convert the identifiers to their underlying type. + * @param clazz The name to use for the enum class. + * @param type The underlying type for the enum class. + */ +#define ENTT_OPAQUE_TYPE(clazz, type)\ + enum class clazz: type {};\ + constexpr auto to_integral(const clazz id) ENTT_NOEXCEPT {\ + return static_cast>(id);\ + }\ + static_assert(true) #endif @@ -43085,37 +14474,36 @@ namespace entt { SUCCEEDED, FAILED, ABORTED, - FINISHED, - REJECTED + FINISHED }; template - auto next(std::integral_constant) - -> decltype(std::declval().init(), void()) { + auto next(integral_constant) + -> decltype(std::declval().init()) { static_cast(this)->init(); } template - auto next(std::integral_constant, Delta delta, void* data) - -> decltype(std::declval().update(delta, data), void()) { + auto next(integral_constant, Delta delta, void* data) + -> decltype(std::declval().update(delta, data)) { static_cast(this)->update(delta, data); } template - auto next(std::integral_constant) - -> decltype(std::declval().succeeded(), void()) { + auto next(integral_constant) + -> decltype(std::declval().succeeded()) { static_cast(this)->succeeded(); } template - auto next(std::integral_constant) - -> decltype(std::declval().failed(), void()) { + auto next(integral_constant) + -> decltype(std::declval().failed()) { static_cast(this)->failed(); } template - auto next(std::integral_constant) - -> decltype(std::declval().aborted(), void()) { + auto next(integral_constant) + -> decltype(std::declval().aborted()) { static_cast(this)->aborted(); } @@ -43176,7 +14564,7 @@ namespace entt { /*! @brief Default destructor. */ virtual ~process() { - static_assert(std::is_base_of_v, "Incorrect use of the class template"); + static_assert(std::is_base_of_v); } /** @@ -43201,7 +14589,7 @@ namespace entt { * @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 { + bool alive() const ENTT_NOEXCEPT { return current == state::RUNNING || current == state::PAUSED; } @@ -43209,7 +14597,7 @@ namespace entt { * @brief Returns true if a process is already terminated. * @return True if the process is terminated, false otherwise. */ - [[nodiscard]] bool finished() const ENTT_NOEXCEPT { + bool dead() const ENTT_NOEXCEPT { return current == state::FINISHED; } @@ -43217,7 +14605,7 @@ namespace entt { * @brief Returns true if a process is currently paused. * @return True if the process is paused, false otherwise. */ - [[nodiscard]] bool paused() const ENTT_NOEXCEPT { + bool paused() const ENTT_NOEXCEPT { return current == state::PAUSED; } @@ -43225,8 +14613,8 @@ namespace entt { * @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; + bool rejected() const ENTT_NOEXCEPT { + return stopped; } /** @@ -43237,11 +14625,11 @@ namespace entt { void tick(const Delta delta, void* data = nullptr) { switch (current) { case state::UNINITIALIZED: - next(std::integral_constant{}); + next(integral_constant{}); current = state::RUNNING; break; case state::RUNNING: - next(std::integral_constant{}, delta, data); + next(integral_constant{}, delta, data); break; default: // suppress warnings @@ -43251,16 +14639,18 @@ namespace entt { // if it's dead, it must be notified and removed immediately switch (current) { case state::SUCCEEDED: - next(std::integral_constant{}); + next(integral_constant{}); current = state::FINISHED; break; case state::FAILED: - next(std::integral_constant{}); - current = state::REJECTED; + next(integral_constant{}); + current = state::FINISHED; + stopped = true; break; case state::ABORTED: - next(std::integral_constant{}); - current = state::REJECTED; + next(integral_constant{}); + current = state::FINISHED; + stopped = true; break; default: // suppress warnings @@ -43270,6 +14660,7 @@ namespace entt { private: state current{ state::UNINITIALIZED }; + bool stopped{ false }; }; @@ -43353,341 +14744,6 @@ namespace entt { // #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 finished() 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 @@ -43737,11 +14793,13 @@ namespace entt { 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"); + static_assert(std::is_base_of_v, Proc>); 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(); @@ -43758,24 +14816,24 @@ namespace entt { }; template - [[nodiscard]] static bool update(process_handler& handler, const Delta delta, void* data) { + 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->finished()) { - if (handler.next) { + auto dead = process->dead(); + + if (dead) { + if (handler.next && !process->rejected()) { handler = std::move(*handler.next); // forces the process to exit the uninitialized state - return handler.update(handler, {}, nullptr); + dead = handler.update(handler, {}, nullptr); + } + else { + handler.instance.reset(); } - - return true; } - return false; + return dead; } template @@ -43805,7 +14863,7 @@ namespace entt { * @brief Number of processes currently scheduled. * @return Number of processes currently scheduled. */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { + size_type size() const ENTT_NOEXCEPT { return handlers.size(); } @@ -43813,7 +14871,7 @@ namespace entt { * @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 { + bool empty() const ENTT_NOEXCEPT { return handlers.empty(); } @@ -43854,7 +14912,7 @@ namespace entt { */ template auto attach(Args &&... args) { - static_assert(std::is_base_of_v, Proc>, "Invalid process type"); + static_assert(std::is_base_of_v, Proc>); 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 @@ -43931,17 +14989,19 @@ namespace entt { * @param data Optional data. */ void update(const Delta delta, void* data = nullptr) { - auto sz = handlers.size(); + bool clean = false; 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]); - } + const bool dead = handler.update(handler, delta, data); + clean = clean || dead; } - handlers.erase(handlers.begin() + sz, handlers.end()); + if (clean) { + handlers.erase(std::remove_if(handlers.begin(), handlers.end(), [](auto& handler) { + return !handler.instance; + }), handlers.end()); + } } /** @@ -43981,6 +15041,7 @@ namespace entt { #define ENTT_RESOURCE_CACHE_HPP +#include #include #include #include @@ -43989,24 +15050,18 @@ namespace entt { #define ENTT_CONFIG_CONFIG_H -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) +#ifndef ENTT_NOEXCEPT # define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) #endif -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws #endif @@ -44024,47 +15079,37 @@ namespace entt { #endif -#ifdef ENTT_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 #endif -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT +#ifndef ENTT_ASSERT # include -# define ENTT_ASSERT(condition, ...) assert(condition) +# define ENTT_ASSERT(condition) assert(condition) #endif -#ifdef ENTT_NO_ETO +#ifndef ENTT_NO_ETO # include -# define ENTT_IGNORE_IF_EMPTY std::false_type +# define ENTT_IS_EMPTY(Type) std::is_empty_v #else # include -# define ENTT_IGNORE_IF_EMPTY std::true_type +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) #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 '>' +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ # endif #endif @@ -44076,30 +15121,23 @@ static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == #define ENTT_CORE_FWD_HPP -#include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) +#ifndef ENTT_NOEXCEPT # define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) #endif -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws #endif @@ -44117,47 +15155,37 @@ static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == #endif -#ifdef ENTT_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 #endif -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT +#ifndef ENTT_ASSERT # include -# define ENTT_ASSERT(condition, ...) assert(condition) +# define ENTT_ASSERT(condition) assert(condition) #endif -#ifdef ENTT_NO_ETO +#ifndef ENTT_NO_ETO # include -# define ENTT_IGNORE_IF_EMPTY std::false_type +# define ENTT_IS_EMPTY(Type) std::is_empty_v #else # include -# define ENTT_IGNORE_IF_EMPTY std::true_type +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) #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 '>' +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ # endif #endif @@ -44169,18 +15197,10 @@ static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 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<>; - - } @@ -44192,7 +15212,6 @@ namespace entt { #include -#include #include // #include "../config/config.h" @@ -44204,16 +15223,17 @@ namespace entt { namespace entt { + /*! @struct cache */ template - struct resource_cache; - + struct cache; + /*! @class handle */ template - class resource_handle; - + class handle; + /*! @class loader */ template - class resource_loader; + class loader; } @@ -44239,148 +15259,68 @@ namespace entt { * @tparam Resource Type of resource managed by a handle. */ template - class resource_handle { - /*! @brief Resource handles are friends with each other. */ - template - friend class resource_handle; + class handle { + /*! @brief Resource handles are friends of their caches. */ + friend struct cache; - public: - /*! @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 + handle(std::shared_ptr res) ENTT_NOEXCEPT : resource{ std::move(res) } {} - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - resource_handle(const resource_handle& other) ENTT_NOEXCEPT = default; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - resource_handle(resource_handle&& other) ENTT_NOEXCEPT = default; - - /** - * @brief Copy constructs a handle which shares ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - */ - template&& std::is_base_of_v>> - resource_handle(const resource_handle& other) ENTT_NOEXCEPT - : resource{ other.resource } - {} - - /** - * @brief Move constructs a handle which takes ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - */ - template&& std::is_base_of_v>> - resource_handle(resource_handle&& other) ENTT_NOEXCEPT - : resource{ std::move(other.resource) } - {} - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This resource handle. - */ - resource_handle& operator=(const resource_handle& other) ENTT_NOEXCEPT = default; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This resource handle. - */ - resource_handle& operator=(resource_handle&& other) ENTT_NOEXCEPT = default; - - /** - * @brief Copy assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - * @return This resource handle. - */ - template - std::enable_if_t&& std::is_base_of_v, resource_handle&> - operator=(const resource_handle& other) ENTT_NOEXCEPT { - resource = other.resource; - return *this; - } - - /** - * @brief Move assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - * @return This resource handle. - */ - template - std::enable_if_t&& std::is_base_of_v, resource_handle&> - operator=(resource_handle&& other) ENTT_NOEXCEPT { - resource = std::move(other.resource); - return *this; - } + public: + /*! @brief Default constructor. */ + handle() ENTT_NOEXCEPT = default; /** * @brief Gets a reference to the managed resource. * * @warning - * The behavior is undefined if the handle doesn't contain a resource. + * The behavior is undefined if the handle doesn't contain a resource.
+ * An assertion will abort the execution at runtime in debug mode if the + * handle is empty. * * @return A reference to the managed resource. */ - [[nodiscard]] const Resource& get() const ENTT_NOEXCEPT { - ENTT_ASSERT(static_cast(resource), "Invalid resource"); + const Resource& get() const ENTT_NOEXCEPT { + ENTT_ASSERT(static_cast(resource)); return *resource; } /*! @copydoc get */ - [[nodiscard]] Resource& get() ENTT_NOEXCEPT { + Resource& get() ENTT_NOEXCEPT { return const_cast(std::as_const(*this).get()); } /*! @copydoc get */ - [[nodiscard]] operator const Resource& () const ENTT_NOEXCEPT { - return get(); - } + operator const Resource& () const ENTT_NOEXCEPT { return get(); } /*! @copydoc get */ - [[nodiscard]] operator Resource& () ENTT_NOEXCEPT { - return get(); - } + operator Resource& () ENTT_NOEXCEPT { return get(); } /*! @copydoc get */ - [[nodiscard]] const Resource& operator *() const ENTT_NOEXCEPT { - return get(); - } + const Resource& operator *() const ENTT_NOEXCEPT { return get(); } /*! @copydoc get */ - [[nodiscard]] Resource& operator *() ENTT_NOEXCEPT { - return get(); - } + 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. + * The behavior is undefined if the handle doesn't contain a resource.
+ * An assertion will abort the execution at runtime in debug mode if the + * handle is empty. * * @return A pointer to the managed resource or `nullptr` if the handle * contains no resource at all. */ - [[nodiscard]] const Resource* operator->() const ENTT_NOEXCEPT { + const Resource* operator->() const ENTT_NOEXCEPT { + ENTT_ASSERT(static_cast(resource)); return resource.get(); } /*! @copydoc operator-> */ - [[nodiscard]] Resource* operator->() ENTT_NOEXCEPT { + Resource* operator->() ENTT_NOEXCEPT { return const_cast(std::as_const(*this).operator->()); } @@ -44388,7 +15328,7 @@ namespace entt { * @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 { + explicit operator bool() const ENTT_NOEXCEPT { return static_cast(resource); } @@ -44407,10 +15347,9 @@ namespace entt { #define ENTT_RESOURCE_LOADER_HPP +#include // #include "fwd.hpp" -// #include "handle.hpp" - namespace entt { @@ -44422,14 +15361,14 @@ namespace entt { * 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.
+ * a shared pointer 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 { + * struct my_loader: entt::loader { + * std::shared_ptr load(int) const { * // use the integer value somehow * return std::make_shared(); * } @@ -44449,10 +15388,9 @@ namespace entt { * @tparam Resource Type of resource for which to use the loader. */ template - class resource_loader { + class loader { /*! @brief Resource loaders are friends of their caches. */ - template - friend struct resource_cache; + friend struct cache; /** * @brief Loads the resource and returns it. @@ -44461,7 +15399,7 @@ namespace entt { * @return The resource just loaded or an empty pointer in case of errors. */ template - [[nodiscard]] resource_handle get(Args &&... args) const { + std::shared_ptr get(Args &&... args) const { return static_cast(this)->load(std::forward(args)...); } }; @@ -44490,26 +15428,26 @@ namespace entt { * @tparam Resource Type of resources managed by a cache. */ template - struct resource_cache { + struct 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; + cache() = default; /*! @brief Default move constructor. */ - resource_cache(resource_cache&&) = default; + cache(cache&&) = default; /*! @brief Default move assignment operator. @return This cache. */ - resource_cache& operator=(resource_cache&&) = default; + cache& operator=(cache&&) = default; /** * @brief Number of resources managed by a cache. * @return Number of resources currently stored. */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { + size_type size() const ENTT_NOEXCEPT { return resources.size(); } @@ -44517,7 +15455,7 @@ namespace entt { * @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 { + bool empty() const ENTT_NOEXCEPT { return resources.empty(); } @@ -44554,17 +15492,21 @@ namespace entt { * @return A handle for the given resource. */ template - resource_handle load(const id_type id, Args &&... args) { + entt::handle load(const id_type id, Args &&... args) { + static_assert(std::is_base_of_v, Loader>); + entt::handle resource{}; + if (auto it = resources.find(id); it == resources.cend()) { - if (auto handle = temp(std::forward(args)...); handle) { - return (resources[id] = std::move(handle)); + if (auto instance = Loader{}.get(std::forward(args)...); instance) { + resources[id] = instance; + resource = std::move(instance); } } else { - return it->second; + resource = it->second; } - return {}; + return resource; } /** @@ -44591,7 +15533,7 @@ namespace entt { * @return A handle for the given resource. */ template - resource_handle reload(const id_type id, Args &&... args) { + entt::handle reload(const id_type id, Args &&... args) { return (discard(id), load(id, std::forward(args)...)); } @@ -44608,8 +15550,8 @@ namespace entt { * @return A handle for the given resource. */ template - [[nodiscard]] resource_handle temp(Args &&... args) const { - return Loader{}.get(std::forward(args)...); + entt::handle temp(Args &&... args) const { + return { Loader{}.get(std::forward(args)...) }; } /** @@ -44620,17 +15562,14 @@ namespace entt { * cache contains the resource itself. Otherwise the returned handle is * uninitialized and accessing it results in undefined behavior. * - * @sa resource_handle + * @sa 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 {}; + entt::handle handle(const id_type id) const { + auto it = resources.find(id); + return { it == resources.end() ? nullptr : it->second }; } /** @@ -44638,7 +15577,7 @@ namespace entt { * @param id Unique resource identifier. * @return True if the cache contains the resource, false otherwise. */ - [[nodiscard]] bool contains(const id_type id) const { + bool contains(const id_type id) const { return (resources.find(id) != resources.cend()); } @@ -44665,9 +15604,9 @@ namespace entt { * forms: * * @code{.cpp} - * void(const entt::id_type); - * void(entt::resource_handle); - * void(const entt::id_type, entt::resource_handle); + * void(const id_type); + * void(handle); + * void(const id_type, handle); * @endcode * * @tparam Func Type of the function object to invoke. @@ -44684,17 +15623,17 @@ namespace entt { if constexpr (std::is_invocable_v) { func(curr->first); } - else if constexpr (std::is_invocable_v>) { - func(curr->second); + else if constexpr (std::is_invocable_v>) { + func(entt::handle{ curr->second }); } else { - func(curr->first, curr->second); + func(curr->first, entt::handle{ curr->second }); } } } private: - std::unordered_map> resources; + std::unordered_map> resources; }; @@ -44704,267 +15643,8 @@ namespace entt { #endif // #include "resource/handle.hpp" -#ifndef ENTT_RESOURCE_HANDLE_HPP -#define ENTT_RESOURCE_HANDLE_HPP - - -#include -#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 - class resource_handle { - /*! @brief Resource handles are friends with each other. */ - template - friend class resource_handle; - - public: - /*! @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 Copy constructor. - * @param other The instance to copy from. - */ - resource_handle(const resource_handle& other) ENTT_NOEXCEPT = default; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - resource_handle(resource_handle&& other) ENTT_NOEXCEPT = default; - - /** - * @brief Copy constructs a handle which shares ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - */ - template&& std::is_base_of_v>> - resource_handle(const resource_handle& other) ENTT_NOEXCEPT - : resource{ other.resource } - {} - - /** - * @brief Move constructs a handle which takes ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - */ - template&& std::is_base_of_v>> - resource_handle(resource_handle&& other) ENTT_NOEXCEPT - : resource{ std::move(other.resource) } - {} - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This resource handle. - */ - resource_handle& operator=(const resource_handle& other) ENTT_NOEXCEPT = default; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This resource handle. - */ - resource_handle& operator=(resource_handle&& other) ENTT_NOEXCEPT = default; - - /** - * @brief Copy assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - * @return This resource handle. - */ - template - std::enable_if_t&& std::is_base_of_v, resource_handle&> - operator=(const resource_handle& other) ENTT_NOEXCEPT { - resource = other.resource; - return *this; - } - - /** - * @brief Move assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - * @return This resource handle. - */ - template - std::enable_if_t&& std::is_base_of_v, resource_handle&> - operator=(resource_handle&& other) ENTT_NOEXCEPT { - resource = std::move(other.resource); - return *this; - } - - /** - * @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), "Invalid 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 { - 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. */ - template - 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 @@ -44976,38 +15656,23 @@ namespace entt { #include #include #include -// #include "../core/type_traits.hpp" -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - - -#include -#include -#include -#include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) +#ifndef ENTT_NOEXCEPT # define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) #endif -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr +#ifndef ENTT_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws #endif @@ -45025,848 +15690,37 @@ namespace entt { #endif -#ifdef ENTT_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 #endif -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#endif - - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(...) (void(0)) -#elif !defined ENTT_ASSERT +#ifndef ENTT_ASSERT # include -# define ENTT_ASSERT(condition, ...) assert(condition) +# define ENTT_ASSERT(condition) assert(condition) #endif -#ifdef ENTT_NO_ETO +#ifndef ENTT_NO_ETO # include -# define ENTT_IGNORE_IF_EMPTY std::false_type +# define ENTT_IS_EMPTY(Type) std::is_empty_v #else # include -# define ENTT_IGNORE_IF_EMPTY std::true_type +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) #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 std::size_t 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 bool 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()) { - if constexpr (std::is_same_v) { - return is_equality_comparable(choice<0>); - } - else { - 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 The type to test. - */ - template - struct is_equality_comparable : std::bool_constant(choice<2>)> {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool 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 bool 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 bool 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 The type to test. - */ - template - struct is_complete : std::false_type {}; - - - /*! @copydoc is_complete */ - template - struct is_complete> : std::true_type {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_complete_v = is_complete::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ - template - struct is_iterator : std::false_type {}; - - - /*! @copydoc is_iterator */ - template - struct is_iterator::iterator_category>> - : std::true_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - */ - template - inline constexpr bool is_iterator_v = is_iterator::value; - - - /** - * @brief Provides the member constant `value` to true if a given type is of the - * required iterator type, false otherwise. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - struct is_iterator_type : std::false_type {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type&& std::is_same_v>> - : std::true_type - {}; - - - /*! @copydoc is_iterator_type */ - template - struct is_iterator_type, std::void_t>> - : is_iterator_type - {}; - - - /** - * @brief Helper variable template. - * @tparam Type The type to test. - * @tparam It Required iterator type. - */ - template - inline constexpr bool is_iterator_type_v = is_iterator_type::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 - - -#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION) -# define ENTT_NOEXCEPT noexcept -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_NOEXCEPT -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - - -#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L -# include -# define ENTT_LAUNDER(expr) std::launder(expr) -#else -# define ENTT_LAUNDER(expr) expr -#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_SPARSE_PAGE -static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE& (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two"); -#else -# define ENTT_SPARSE_PAGE 4096 -#endif - - -#ifdef ENTT_PACKED_PAGE -static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE& (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two"); -#else -# define ENTT_PACKED_PAGE 1024 -#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 - - -#ifdef ENTT_NO_ETO -# include -# define ENTT_IGNORE_IF_EMPTY std::false_type -#else -# include -# define ENTT_IGNORE_IF_EMPTY std::true_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 '>' +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ # endif #endif @@ -45912,7 +15766,7 @@ namespace entt { template - [[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) { + constexpr auto index_sequence_for(Ret(*)(Args...)) { return std::index_sequence_for{}; } @@ -45922,7 +15776,7 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ @@ -45960,39 +15814,37 @@ namespace entt { */ template class delegate { + using proto_fn_type = Ret(const void*, Args...); + template - [[nodiscard]] auto wrap(std::index_sequence) ENTT_NOEXCEPT { + 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))...)); + const auto arguments = std::forward_as_tuple(std::forward(args)...); + return Ret(std::invoke(Candidate, std::forward>>(std::get(arguments))...)); }; } template - [[nodiscard]] auto wrap(Type&, std::index_sequence) ENTT_NOEXCEPT { + 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))...)); + const auto arguments = std::forward_as_tuple(std::forward(args)...); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); + return Ret(std::invoke(Candidate, *curr, std::forward>>(std::get(arguments))...)); }; } template - [[nodiscard]] auto wrap(Type*, std::index_sequence) ENTT_NOEXCEPT { + 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))...)); + const auto arguments = std::forward_as_tuple(std::forward(args)...); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); + return Ret(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; + using function_type = Ret(Args...); /*! @brief Default constructor. */ delegate() ENTT_NOEXCEPT @@ -46005,7 +15857,9 @@ namespace entt { * @tparam Candidate Function or member to connect to the delegate. */ template - delegate(connect_arg_t) ENTT_NOEXCEPT { + delegate(connect_arg_t) ENTT_NOEXCEPT + : delegate{} + { connect(); } @@ -46017,20 +15871,12 @@ namespace entt { * @param value_or_instance A valid object that fits the purpose. */ template - delegate(connect_arg_t, Type&& value_or_instance) ENTT_NOEXCEPT { + delegate(connect_arg_t, Type&& value_or_instance) ENTT_NOEXCEPT + : delegate{} + { 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. @@ -46045,7 +15891,7 @@ namespace entt { }; } else if constexpr (std::is_member_pointer_v) { - fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); + fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); } else { fn = wrap(internal::index_sequence_for(internal::function_pointer_t{})); @@ -46058,7 +15904,7 @@ namespace entt { * * 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.
+ * 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. @@ -46073,7 +15919,7 @@ namespace entt { if constexpr (std::is_invocable_r_v) { fn = [](const void* payload, Args... args) -> Ret { - Type* curr = static_cast(const_cast *>(payload)); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); return Ret(std::invoke(Candidate, *curr, std::forward(args)...)); }; } @@ -46098,7 +15944,7 @@ namespace entt { if constexpr (std::is_invocable_r_v) { fn = [](const void* payload, Args... args) -> Ret { - Type* curr = static_cast(const_cast *>(payload)); + Type* curr = static_cast(const_cast, const void*, void*>>(payload)); return Ret(std::invoke(Candidate, curr, std::forward(args)...)); }; } @@ -46107,24 +15953,6 @@ namespace entt { } } - /** - * @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. * @@ -46139,7 +15967,7 @@ namespace entt { * @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 { + const void* instance() const ENTT_NOEXCEPT { return data; } @@ -46150,13 +15978,15 @@ namespace entt { * * @warning * Attempting to trigger an invalid delegate results in undefined - * behavior. + * behavior.
+ * An assertion will abort the execution at runtime in debug mode if the + * delegate has not yet been set. * * @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), "Uninitialized delegate"); + ENTT_ASSERT(fn); return fn(data, std::forward(args)...); } @@ -46164,7 +15994,7 @@ namespace entt { * @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 { + explicit operator bool() const ENTT_NOEXCEPT { // no need to test also data return !(fn == nullptr); } @@ -46174,12 +16004,12 @@ namespace entt { * @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 { + bool operator==(const delegate& other) const ENTT_NOEXCEPT { return fn == other.fn && data == other.data; } private: - function_type* fn; + proto_fn_type* fn; const void* data; }; @@ -46193,7 +16023,7 @@ namespace entt { * @return True if the two contents differ, false otherwise. */ template - [[nodiscard]] bool operator!=(const delegate& lhs, const delegate& rhs) ENTT_NOEXCEPT { + bool operator!=(const delegate& lhs, const delegate& rhs) ENTT_NOEXCEPT { return !(lhs == rhs); } @@ -46203,7 +16033,7 @@ namespace entt { * @tparam Candidate Function or member to connect to the delegate. */ template - delegate(connect_arg_t) + delegate(connect_arg_t) ENTT_NOEXCEPT ->delegate>>; @@ -46213,20 +16043,10 @@ namespace entt { * @tparam Type Type of class or type of payload. */ template - delegate(connect_arg_t, Type&&) + delegate(connect_arg_t, Type&&) ENTT_NOEXCEPT ->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; - - } @@ -46249,26 +16069,86 @@ namespace entt { #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_HS_SUFFIX +# define ENTT_HS_SUFFIX _hs +#endif + + +#ifndef ENTT_HWS_SUFFIX +# define ENTT_HWS_SUFFIX _hws +#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 + + +#ifndef ENTT_PAGE_SIZE +# define ENTT_PAGE_SIZE 32768 +#endif + + +#ifndef ENTT_ASSERT +# include +# define ENTT_ASSERT(condition) assert(condition) +#endif + + +#ifndef ENTT_NO_ETO +# include +# define ENTT_IS_EMPTY(Type) std::is_empty_v +#else +# include +# // sfinae-friendly definition +# define ENTT_IS_EMPTY(Type) (false && std::is_empty_v) +#endif + + +#ifndef ENTT_STANDARD_CPP +# if defined _MSC_VER +# define ENTT_PRETTY_FUNCTION __FUNCSIG__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8) +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) constexpr +# elif defined __GNUC__ +# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ +# define ENTT_PRETTY_FUNCTION_CONSTEXPR(...) __VA_ARGS__ +# 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<>; - - } @@ -46279,8 +16159,6 @@ namespace entt { #define ENTT_CORE_TYPE_INFO_HPP -#include -#include // #include "../config/config.h" // #include "../core/attribute.h" @@ -46368,7 +16246,7 @@ namespace entt { /** * Internal details not to be documented. - * @endcond + * @endcond TURN_OFF_DOXYGEN */ @@ -46393,8 +16271,8 @@ namespace entt { const Char* str; }; - // Fowler–Noll–Vo hash function v. 1a - the good - [[nodiscard]] static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { + // Fowler-Noll-Vo hash function v. 1a - the good + static constexpr id_type helper(const Char* curr) ENTT_NOEXCEPT { auto value = traits_type::offset; while (*curr != 0) { @@ -46410,18 +16288,6 @@ namespace entt { /*! @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. * @@ -46438,7 +16304,7 @@ namespace entt { * @return The numeric representation of the string. */ template - [[nodiscard]] static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { + static constexpr hash_type value(const value_type(&str)[N]) ENTT_NOEXCEPT { return helper(str); } @@ -46447,10 +16313,22 @@ namespace entt { * @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 { + static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT { return helper(wrapper.str); } + /** + * @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. + */ + static 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 Constructs an empty hashed string. */ constexpr basic_hashed_string() ENTT_NOEXCEPT : str{ nullptr }, hash{} @@ -46488,7 +16366,7 @@ namespace entt { * @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 { + constexpr const value_type* data() const ENTT_NOEXCEPT { return str; } @@ -46496,25 +16374,25 @@ namespace entt { * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the instance. */ - [[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT { + constexpr hash_type value() const ENTT_NOEXCEPT { return hash; } /*! @copydoc data */ - [[nodiscard]] constexpr operator const value_type* () const ENTT_NOEXCEPT { return data(); } + 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(); } + 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 { + constexpr bool operator==(const basic_hashed_string& other) const ENTT_NOEXCEPT { return hash == other.hash; } @@ -46535,7 +16413,7 @@ namespace entt { * @param str Human-readable identifer. */ template - basic_hashed_string(const Char(&str)[N]) + basic_hashed_string(const Char(&str)[N]) ENTT_NOEXCEPT ->basic_hashed_string; @@ -46547,7 +16425,7 @@ namespace entt { * @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 { + constexpr bool operator!=(const basic_hashed_string& lhs, const basic_hashed_string& rhs) ENTT_NOEXCEPT { return !(lhs == rhs); } @@ -46560,32 +16438,26 @@ namespace entt { 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 }; - } - - - } +/** + * @brief User defined literal for hashed strings. + * @param str The literal without its suffix. + * @return A properly initialized hashed string. + */ +constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(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. + */ +constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t* str, std::size_t) ENTT_NOEXCEPT { + return entt::hashed_wstring{ str }; } @@ -46607,239 +16479,86 @@ namespace entt { namespace internal { - struct ENTT_API type_seq final { - [[nodiscard]] static id_type next() ENTT_NOEXCEPT { + struct ENTT_API type_index { + 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 + * @endcond TURN_OFF_DOXYGEN */ /** - * @brief Type sequential identifier. + * @brief Type index. * @tparam Type Type for which to generate a sequential identifier. */ template - struct ENTT_API type_seq final { + struct ENTT_API type_index { /** * @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(); + static id_type value() ENTT_NOEXCEPT { + static const id_type value = internal::type_index::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. + * @brief Provides the member constant `value` to true if a given type is + * indexable, false otherwise. + * @tparam Type Potentially indexable type. + */ + template + struct has_type_index : std::false_type {}; + + + /*! @brief has_type_index */ + template + struct has_type_index::value())>> : std::true_type {}; + + + /** + * @brief Helper variable template. + * @tparam Type Potentially indexable type. + */ + template + inline constexpr bool has_type_index_v = has_type_index::value; + + + /** + * @brief Type info. + * @tparam Type Type for which to generate information. */ template - struct type_hash final { + struct ENTT_API type_info { /** * @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); + static ENTT_PRETTY_FUNCTION_CONSTEXPR() id_type id() ENTT_NOEXCEPT { + ENTT_PRETTY_FUNCTION_CONSTEXPR(static const) auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION); + return value; + } #else - [[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT { - return type_seq::value(); + static id_type id() ENTT_NOEXCEPT { + return type_index::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 @@ -46858,377 +16577,6 @@ namespace entt { // #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), "Uninitialized delegate"); - 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 @@ -47238,27 +16586,28 @@ namespace entt { namespace entt { + /*! @class delegate */ template class delegate; - + /*! @class dispatcher */ class dispatcher; - + /*! @class emitter */ template class emitter; - + /*! @class connection */ class connection; - + /*! @class scoped_connection */ struct scoped_connection; - + /*! @class sink */ template class sink; - + /*! @class sigh */ template class sigh; @@ -47321,7 +16670,7 @@ namespace entt { /*! @brief Unsigned integer type. */ using size_type = std::size_t; /*! @brief Sink type. */ - using sink_type = sink; + using sink_type = entt::sink; /** * @brief Instance type when it comes to connecting member functions. @@ -47334,7 +16683,7 @@ namespace entt { * @brief Number of listeners connected to the signal. * @return Number of listeners currently connected. */ - [[nodiscard]] size_type size() const ENTT_NOEXCEPT { + size_type size() const ENTT_NOEXCEPT { return calls.size(); } @@ -47342,7 +16691,7 @@ namespace entt { * @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 { + bool empty() const ENTT_NOEXCEPT { return calls.empty(); } @@ -47426,7 +16775,7 @@ namespace entt { * @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 { + explicit operator bool() const ENTT_NOEXCEPT { return static_cast(disconnect); } @@ -47493,7 +16842,7 @@ namespace entt { * @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 { + explicit operator bool() const ENTT_NOEXCEPT { return static_cast(conn); } @@ -47518,10 +16867,6 @@ namespace entt { * 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. */ @@ -47554,7 +16899,7 @@ namespace entt { * @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 { + bool empty() const ENTT_NOEXCEPT { return signal->calls.empty(); } @@ -47565,7 +16910,7 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before() { + sink before() { delegate call{}; call.template connect(); @@ -47586,9 +16931,9 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before(Type&& value_or_instance) { + sink before(Type&& value_or_instance) { delegate call{}; - call.template connect(value_or_instance); + call.template connect(std::forward(value_or_instance)); const auto& calls = signal->calls; const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call)); @@ -47606,7 +16951,7 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before(Type& value_or_instance) { + sink before(Type& value_or_instance) { return before(&value_or_instance); } @@ -47618,7 +16963,7 @@ namespace entt { * @return A properly initialized sink object. */ template - [[nodiscard]] sink before(Type* value_or_instance) { + sink before(Type* value_or_instance) { sink other{ *this }; if (value_or_instance) { @@ -47637,7 +16982,7 @@ namespace entt { * @brief Returns a sink that connects before anything else. * @return A properly initialized sink object. */ - [[nodiscard]] sink before() { + sink before() { sink other{ *this }; other.offset = signal->calls.size(); return other; @@ -47718,7 +17063,7 @@ namespace entt { void disconnect(Type&& value_or_instance) { auto& calls = signal->calls; delegate call{}; - call.template connect(value_or_instance); + call.template connect(std::forward(value_or_instance)); calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end()); } @@ -47770,8 +17115,7 @@ namespace entt { * @tparam Args Types of arguments of a function type. */ template - sink(sigh&) - ->sink; + sink(sigh&) ENTT_NOEXCEPT->sink; } @@ -47791,7 +17135,7 @@ namespace entt { * 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. + * type `const 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. @@ -47800,15 +17144,13 @@ namespace entt { struct basic_pool { virtual ~basic_pool() = default; virtual void publish() = 0; - virtual void disconnect(void*) = 0; virtual void clear() ENTT_NOEXCEPT = 0; + virtual id_type type_id() const ENTT_NOEXCEPT = 0; }; template struct pool_handler final : basic_pool { - static_assert(std::is_same_v>, "Invalid event type"); - - using signal_type = sigh; + using signal_type = sigh; using sink_type = typename signal_type::sink_type; void publish() override { @@ -47821,32 +17163,26 @@ namespace entt { 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 { + sink_type sink() ENTT_NOEXCEPT { return entt::sink{ signal }; } template void trigger(Args &&... args) { - Event instance{ std::forward(args)... }; - signal.publish(instance); + signal.publish(Event{ std::forward(args)... }); } 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)...); - } + events.emplace_back(std::forward(args)...); + } + + id_type type_id() const ENTT_NOEXCEPT override { + return type_info::id(); } private: @@ -47855,38 +17191,37 @@ namespace entt { }; template - [[nodiscard]] pool_handler& assure() { - const auto index = type_seq::value(); + pool_handler& assure() { + static_assert(std::is_same_v>); - if (!(index < pools.size())) { - pools.resize(std::size_t(index) + 1u); + if constexpr (has_type_index_v) { + const auto index = type_index::value(); + + if (!(index < pools.size())) { + pools.resize(index + 1); + } + + if (!pools[index]) { + pools[index].reset(new pool_handler{}); + } + + return static_cast &>(*pools[index]); } - - if (!pools[index]) { - pools[index].reset(new pool_handler{}); + else { + auto it = std::find_if(pools.begin(), pools.end(), [id = type_info::id()](const auto& cpool) { return id == cpool->type_id(); }); + return static_cast &>(it == pools.cend() ? *pools.emplace_back(new pool_handler{}) : **it); } - - 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: + * The function type for a listener is: * @code{.cpp} - * void(Event &); + * void(const Event &); * @endcode * * The order of invocation of the listeners isn't guaranteed. @@ -47897,7 +17232,7 @@ namespace entt { * @return A temporary sink object. */ template - [[nodiscard]] auto sink() { + auto sink() { return assure().sink(); } @@ -47959,32 +17294,6 @@ namespace entt { 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. * @@ -48085,9 +17394,9 @@ namespace entt { * 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. + * with a reference to itself along with a const 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. */ @@ -48097,18 +17406,17 @@ namespace entt { virtual ~basic_pool() = default; virtual bool empty() const ENTT_NOEXCEPT = 0; virtual void clear() ENTT_NOEXCEPT = 0; + virtual id_type type_id() const 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 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 { + bool empty() const ENTT_NOEXCEPT override { auto pred = [](auto&& element) { return element.first; }; return std::all_of(once_list.cbegin(), once_list.cend(), pred) && @@ -48149,7 +17457,7 @@ namespace entt { } } - void publish(Event& event, Derived& ref) { + void publish(const Event& event, Derived& ref) { container_type swap_list; once_list.swap(swap_list); @@ -48168,6 +17476,10 @@ namespace entt { on_list.remove_if([](auto&& element) { return element.first; }); } + id_type type_id() const ENTT_NOEXCEPT override { + return type_info::id(); + } + private: bool publishing{ false }; container_type once_list{}; @@ -48175,24 +17487,31 @@ namespace entt { }; template - [[nodiscard]] pool_handler* assure() { - const auto index = type_seq::value(); + const pool_handler& assure() const { + static_assert(std::is_same_v>); - if (!(index < pools.size())) { - pools.resize(std::size_t(index) + 1u); + if constexpr (has_type_index_v) { + const auto index = type_index::value(); + + if (!(index < pools.size())) { + pools.resize(index + 1); + } + + if (!pools[index]) { + pools[index].reset(new pool_handler{}); + } + + return static_cast &>(*pools[index]); } - - if (!pools[index]) { - pools[index].reset(new pool_handler{}); + else { + auto it = std::find_if(pools.begin(), pools.end(), [id = type_info::id()](const auto& cpool) { return id == cpool->type_id(); }); + return static_cast &>(it == pools.cend() ? *pools.emplace_back(new pool_handler{}) : **it); } - - 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()); + pool_handler& assure() { + return const_cast &>(std::as_const(*this).template assure()); } public: @@ -48231,7 +17550,7 @@ namespace entt { /*! @brief Default destructor. */ virtual ~emitter() { - static_assert(std::is_base_of_v, Derived>, "Incorrect use of the class template"); + static_assert(std::is_base_of_v, Derived>); } /*! @brief Default move constructor. */ @@ -48253,8 +17572,7 @@ namespace entt { */ template void publish(Args &&... args) { - Event instance{ std::forward(args)... }; - assure()->publish(instance, *static_cast(this)); + assure().publish(Event{ std::forward(args)... }, *static_cast(this)); } /** @@ -48266,7 +17584,7 @@ namespace entt { * 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 &)`. + * which is `void(const Event &, Derived &)`. * * @note * Whenever an event is emitted, the emitter provides the listener with a @@ -48279,7 +17597,7 @@ namespace entt { */ template connection on(listener instance) { - return assure()->on(std::move(instance)); + return assure().on(std::move(instance)); } /** @@ -48291,7 +17609,7 @@ namespace entt { * 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 &)`. + * which is `void(const Event &, Derived &)`. * * @note * Whenever an event is emitted, the emitter provides the listener with a @@ -48304,7 +17622,7 @@ namespace entt { */ template connection once(listener instance) { - return assure()->once(std::move(instance)); + return assure().once(std::move(instance)); } /** @@ -48318,7 +17636,7 @@ namespace entt { */ template void erase(connection conn) { - assure()->erase(std::move(conn)); + assure().erase(std::move(conn)); } /** @@ -48331,7 +17649,7 @@ namespace entt { */ template void clear() { - assure()->clear(); + assure().clear(); } /** @@ -48354,23 +17672,22 @@ namespace entt { * @return True if there are no listeners registered, false otherwise. */ template - [[nodiscard]] bool empty() const { - const auto* cpool = assure(); - return !cpool || cpool->empty(); + bool empty() const { + return assure().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 { + bool empty() const ENTT_NOEXCEPT { return std::all_of(pools.cbegin(), pools.cend(), [](auto&& cpool) { return !cpool || cpool->empty(); }); } private: - std::vector> pools{}; + mutable std::vector> pools{}; }; @@ -48380,530 +17697,4 @@ namespace entt { #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/Engine/src/Engine/Scene/Entity.h b/Engine/src/Engine/Scene/Entity.h index 424deb2..76b5645 100644 --- a/Engine/src/Engine/Scene/Entity.h +++ b/Engine/src/Engine/Scene/Entity.h @@ -19,17 +19,25 @@ namespace Light { ~Entity(); template - T& AddComponent(Args&&... args) + inline T& AddComponent(Args&&... args) { return m_Scene->m_Registry.emplace(m_Handle, std::forward(args)...); } template - T& GetComponent() + inline T& GetComponent() { return m_Scene->m_Registry.get(m_Handle); } + template + inline bool HasComponent() + { + return m_Scene->m_Registry.has(m_Handle); + } + + inline bool IsValid() const { return m_Handle != entt::null && m_Scene != nullptr; } + operator uint32_t() { return (uint32_t)m_Handle; } }; diff --git a/Mirror/default_gui_layout.ini b/Mirror/default_gui_layout.ini index b412e99..1391a48 100644 --- a/Mirror/default_gui_layout.ini +++ b/Mirror/default_gui_layout.ini @@ -7,7 +7,7 @@ Collapsed=1 [Window][Dear ImGui Demo] Pos=86,24 Size=247,278 -Collapsed=1 +Collapsed=0 [Window][GameView] Pos=203,64 diff --git a/Mirror/src/MirrorLayer.h b/Mirror/src/MirrorLayer.h index 6b2b804..bd45873 100644 --- a/Mirror/src/MirrorLayer.h +++ b/Mirror/src/MirrorLayer.h @@ -1,6 +1,8 @@ #include #include "Panels/SceneHierarchyPanel.h" +#include "Panels/PropertiesPanel.h" + #include @@ -17,7 +19,8 @@ namespace Light { Ref m_Framebuffer; Ref m_Scene; - SceneHierarchyPanel m_SceneHierarchyPanel; + Ref m_SceneHierarchyPanel; + Ref m_PropertiesPanel; Entity m_CameraEntity; Entity m_NativeScriptEntity; @@ -58,7 +61,6 @@ namespace Light { private: void OnUpdate(float deltaTime) { - LT_CLIENT_TRACE("NativeScript on update {}", deltaTime); } }; m_NativeScriptEntity.AddComponent().Bind(); @@ -66,7 +68,9 @@ namespace Light { // create native scripts m_Scene->OnCreate(); - m_SceneHierarchyPanel.SetContext(m_Scene); + + m_PropertiesPanel = CreateRef(); + m_SceneHierarchyPanel = CreateRef(m_Scene, m_PropertiesPanel); } void OnUpdate(float deltaTime) override @@ -124,7 +128,8 @@ namespace Light { ImGui::End(); - m_SceneHierarchyPanel.OnUserInterfaceUpdate(); + m_SceneHierarchyPanel->OnUserInterfaceUpdate(); + m_PropertiesPanel->OnUserInterfaceUpdate(); } }; diff --git a/Mirror/src/Panels/PropertiesPanel.cpp b/Mirror/src/Panels/PropertiesPanel.cpp new file mode 100644 index 0000000..a59952a --- /dev/null +++ b/Mirror/src/Panels/PropertiesPanel.cpp @@ -0,0 +1,54 @@ +#include "PropertiesPanel.h" + +#include "Scene/Components.h" + +#include +#include + +#include + + +namespace Light { + + void PropertiesPanel::OnUserInterfaceUpdate() + { + ImGui::Begin("Properties"); + + if(m_EntityContext.IsValid()) + { + if(m_EntityContext.HasComponent()) + { + auto& tagComponent = m_EntityContext.GetComponent(); + + char buffer[256]; + memset(buffer, 0, sizeof(buffer)); + std::strncpy(buffer, tagComponent.tag.c_str(), sizeof(buffer)); + if (ImGui::InputText("##Tag", buffer, sizeof(buffer))) + { + LT_ENGINE_TRACE("bruh"); + tagComponent.tag = std::string(buffer); + } + } + + if(m_EntityContext.HasComponent()) + { + + if (ImGui::TreeNodeEx((void*)typeid(TransformComponent).hash_code(), ImGuiTreeNodeFlags_DefaultOpen, "Transform")) + { + auto& transformComponent = m_EntityContext.GetComponent(); + ImGui::DragFloat3("Position", glm::value_ptr(transformComponent.transform[3]), 0.5f); + + ImGui::TreePop(); + } + } + } + + ImGui::End(); + } + + void PropertiesPanel::SetEntityContext(Entity entity) + { + m_EntityContext = entity; + } + +} \ No newline at end of file diff --git a/Mirror/src/Panels/PropertiesPanel.h b/Mirror/src/Panels/PropertiesPanel.h new file mode 100644 index 0000000..378e2e0 --- /dev/null +++ b/Mirror/src/Panels/PropertiesPanel.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Panel.h" + +#include "Scene/Entity.h" + +namespace Light { + + class PropertiesPanel : public Panel + { + private: + Entity m_EntityContext; + + public: + PropertiesPanel() = default; + ~PropertiesPanel() = default; + + void OnUserInterfaceUpdate(); + + void SetEntityContext(Entity entity); + }; + +} \ No newline at end of file diff --git a/Mirror/src/Panels/SceneHierarchyPanel.cpp b/Mirror/src/Panels/SceneHierarchyPanel.cpp index 2522402..044c8bb 100644 --- a/Mirror/src/Panels/SceneHierarchyPanel.cpp +++ b/Mirror/src/Panels/SceneHierarchyPanel.cpp @@ -1,5 +1,7 @@ #include "SceneHierarchyPanel.h" +#include "PropertiesPanel.h" + #include "Scene/Components.h" #include @@ -8,30 +10,44 @@ namespace Light { - SceneHierarchyPanel::SceneHierarchyPanel(Ref context) - : m_Context(context) + SceneHierarchyPanel::SceneHierarchyPanel() + : m_Context(nullptr), + m_PropertiesPanelContext(nullptr), + m_SelectionContext() { } - void SceneHierarchyPanel::SetContext(Ref context) + SceneHierarchyPanel::SceneHierarchyPanel(Ref context, Ref propertiesPanel /* = nullptr */) + : m_Context(context), + m_PropertiesPanelContext(propertiesPanel) { - m_Context = context; } void SceneHierarchyPanel::OnUserInterfaceUpdate() { - ImGui::Begin("Hierarchy"); - - m_Context->m_Registry. - each([&](auto& entityID) + if(m_Context) { - Entity entity(entityID, m_Context.get()); - const std::string& tag = entity.GetComponent(); + ImGui::Begin("Hierarchy"); - DrawNode(entity, tag); - }); + m_Context->m_Registry. + each([&](auto entityID) + { + Entity entity(entityID, m_Context.get()); + const std::string& tag = entity.GetComponent(); + + DrawNode(entity, tag); + }); - ImGui::End(); + ImGui::End(); + } + } + + void SceneHierarchyPanel::SetContext(Ref context, Ref propertiesPanel /* = nullptr */) + { + if (propertiesPanel) + m_PropertiesPanelContext = propertiesPanel; + + m_Context = context; } void SceneHierarchyPanel::DrawNode(Entity entity, const std::string& label) @@ -43,7 +59,10 @@ namespace Light { bool expanded = ImGui::TreeNodeEx((void*)(uint64_t)(uint32_t)(entity), flags, label.c_str()); if (ImGui::IsItemClicked()) + { m_SelectionContext = entity; + m_PropertiesPanelContext->SetEntityContext(entity); + } if(expanded) { diff --git a/Mirror/src/Panels/SceneHierarchyPanel.h b/Mirror/src/Panels/SceneHierarchyPanel.h index 20ec6fa..0674d52 100644 --- a/Mirror/src/Panels/SceneHierarchyPanel.h +++ b/Mirror/src/Panels/SceneHierarchyPanel.h @@ -9,20 +9,23 @@ namespace Light { + class PropertiesPanel; + class SceneHierarchyPanel : public Panel { private: Ref m_Context; + Ref m_PropertiesPanelContext; Entity m_SelectionContext; public: - SceneHierarchyPanel() = default; - SceneHierarchyPanel(Ref context); - - void SetContext(Ref context); + SceneHierarchyPanel(); + SceneHierarchyPanel(Ref context, Ref propertiesPanel = nullptr); void OnUserInterfaceUpdate(); + void SetContext(Ref context, Ref propertiesPanel = nullptr); + private: void DrawNode(Entity entity, const std::string& label); };