/*! @brief `EnTT` default namespace. */ namespace entt {} /*! @brief Custom `EnTT` namespace for the standard template library. */ namespace entt::stl {} // IWYU pragma: begin_exports // #include "config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "config/macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "config/version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // #include "container/dense_map.hpp" #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" namespace entt { template< typename Key, typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator>> class dense_map; template< typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator> class dense_set; template class basic_table; /** * @brief Alias declaration for the most common use case. * @tparam Type Element types. */ template using table = basic_table...>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { using value_type = stl::pair; template dense_map_node(const stl::size_t pos, Args &&...args) : next{pos}, element{stl::forward(args)...} {} template dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) : next{pos}, element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, other.element)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} stl::size_t next; value_type element; }; template class dense_map_iterator final { template friend class dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr dense_map_iterator() noexcept : it{} {} constexpr dense_map_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_iterator(const dense_map_iterator &other) noexcept : it{other.it} {} constexpr dense_map_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_map_iterator operator++(int) noexcept { const dense_map_iterator orig = *this; return ++(*this), orig; } constexpr dense_map_iterator &operator--() noexcept { return --it, *this; } constexpr dense_map_iterator operator--(int) noexcept { const dense_map_iterator orig = *this; return operator--(), orig; } constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_map_iterator operator+(const difference_type value) const noexcept { dense_map_iterator copy = *this; return (copy += value); } constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_map_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].element.first, it[value].element.second}; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_map_local_iterator final { template friend class dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr dense_map_local_iterator() noexcept = default; constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_map_local_iterator &operator++() noexcept { return (offset = it[static_cast(offset)].next), *this; } constexpr dense_map_local_iterator operator++(int) noexcept { const dense_map_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { const auto idx = static_cast(offset); return {it[idx].element.first, it[idx].element.second}; } template [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_map_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for key-value pairs with unique keys. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on the hash of its key. Keys with the same hash * code appear in the same bucket. * * @tparam Key Key type of the associative container. * @tparam Type Mapped type of the associative container. * @tparam Hash Type of function to use to hash the keys. * @tparam KeyEqual Type of function to use to compare the keys for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_map { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; using node_type = internal::dense_map_node; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v>, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) return fast_mod(static_cast(sparse.second()(key)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } template [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { it->second = stl::forward(value); return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].next) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Key; /*! @brief Mapped type of the container. */ using mapped_type = Type; /*! @brief Key-value type of the container. */ using value_type = stl::pair; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the keys. */ using hasher = Hash; /*! @brief Type of function to use to compare the keys for equality. */ using key_equal = KeyEqual; /*! @brief Input iterator type. */ using iterator = internal::dense_map_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::dense_map_iterator; /*! @brief Input iterator type. */ using local_iterator = internal::dense_map_local_iterator; /*! @brief Constant input iterator type. */ using const_local_iterator = internal::dense_map_local_iterator; /*! @brief Default constructor. */ dense_map() : dense_map{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_map(const allocator_type &allocator) : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const allocator_type &allocator) : dense_map{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_map{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_map(const dense_map &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_map(const dense_map &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_map(dense_map &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_map(dense_map &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_map() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_map &operator=(const dense_map &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_map &operator=(dense_map &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_map &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if the key does not exist. * @param value A key-value pair eventually convertible to the value type. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value.first, value.second); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); } /** * @copydoc insert * @tparam Arg Type of the key-value pair to insert into the container. */ template requires stl::constructible_from stl::pair insert(Arg &&value) { return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); } /** * @brief Inserts elements into the container, if their keys do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Inserts an element into the container or assigns to the current * element if the key already exists. * @tparam Arg Type of the value to insert or assign. * @param key A key used both to look up and to insert if not found. * @param value A value to insert or assign. * @return A pair consisting of an iterator to the element and a bool * denoting whether the insertion took place. */ template stl::pair insert_or_assign(const key_type &key, Arg &&value) { return insert_or_overwrite(key, stl::forward(value)); } /*! @copydoc insert_or_assign */ template stl::pair insert_or_assign(key_type &&key, Arg &&value) { return insert_or_overwrite(stl::move(key), stl::forward(value)); } /** * @brief Constructs an element in-place, if the key does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace([[maybe_unused]] Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return insert_or_do_nothing(key_type{}); } else if constexpr(sizeof...(Args) == 1u) { return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); } else if constexpr(sizeof...(Args) == 2u) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); const auto index = key_to_bucket(node.element.first); if(auto it = constrained_find(node.element.first, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.next, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Inserts in-place if the key does not exist, does nothing if the * key exists. * @tparam Args Types of arguments to forward to the constructor of the * element. * @param key A key used both to look up and to insert if not found. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair try_emplace(const key_type &key, Args &&...args) { return insert_or_do_nothing(key, stl::forward(args)...); } /*! @copydoc try_emplace */ template stl::pair try_emplace(key_type &&key, Args &&...args) { return insert_or_do_nothing(stl::move(key), stl::forward(args)...); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(pos->first); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].element.first); } return (begin() + dist); } /** * @brief Removes the element associated with a given key. * @param key A key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const key_type &key) { for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { if(packed.second()(packed.first()[*curr].element.first, key)) { const auto index = *curr; *curr = packed.first()[*curr].next; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &at(const key_type &key) { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] const mapped_type &at(const key_type &key) const { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type const &at(const auto &key) const requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] mapped_type &at(const auto &key) requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](const key_type &key) { return insert_or_do_nothing(key).first->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](key_type &&key) { return insert_or_do_nothing(stl::move(key)).first->second; } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const key_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const key_type &key) { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const key_type &key) const { return constrained_find(key, key_to_bucket(key)); } /** * @brief Finds an element with a key that compares _equivalent_ to a given * key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &key) requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &key) const requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /** * @brief Returns a range containing all elements with a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const key_type &key) { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const key_type &key) const { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &key) requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &key) const requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given key. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const key_type &key) const { return (find(key) != cend()); } /** * @brief Checks if the container contains an element with a key that * compares _equivalent_ to a given value. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &key) const requires is_transparent_v && is_transparent_v { return (find(key) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given key. * @param key The value of the key to examine. * @return The bucket for the given key. */ [[nodiscard]] size_type bucket(const key_type &key) const { return key_to_bucket(key); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = key_to_bucket(packed.first()[pos].element.first); packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the keys. * @return The function used to hash the keys. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare keys for equality. * @return The function used to compare keys for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::true_type {}; } // namespace std /*! @endcond */ #endif // #include "container/dense_set.hpp" #ifndef ENTT_CONTAINER_DENSE_SET_HPP #define ENTT_CONTAINER_DENSE_SET_HPP #include // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../core/compressed_pair.hpp" // #include "../core/type_traits.hpp" // #include "../stl/bit.hpp" // #include "../stl/cmath.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" // #include "../stl/iterator.hpp" // #include "../stl/limits.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits::max)(); template class dense_set_iterator final { template friend class dense_set_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); public: using value_type = stl::remove_const_t>::second_type; using pointer = const value_type *; using reference = const value_type &; using difference_type = stl::ptrdiff_t; using iterator_category = stl::random_access_iterator_tag; constexpr dense_set_iterator() noexcept : it{} {} constexpr dense_set_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_set_iterator(const dense_set_iterator &other) noexcept : it{other.it} {} constexpr dense_set_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_set_iterator operator++(int) noexcept { const dense_set_iterator orig = *this; return ++(*this), orig; } constexpr dense_set_iterator &operator--() noexcept { return --it, *this; } constexpr dense_set_iterator operator--(int) noexcept { const dense_set_iterator orig = *this; return operator--(), orig; } constexpr dense_set_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_set_iterator operator+(const difference_type value) const noexcept { dense_set_iterator copy = *this; return (copy += value); } constexpr dense_set_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_set_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return it[value].second; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(operator[](0)); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_set_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_set_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_set_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_set_local_iterator final { template friend class dense_set_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); public: using value_type = stl::remove_const_t>::second_type; using pointer = const value_type *; using reference = const value_type &; using difference_type = stl::ptrdiff_t; using iterator_category = stl::forward_iterator_tag; constexpr dense_set_local_iterator() noexcept = default; constexpr dense_set_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_set_local_iterator(const dense_set_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_set_local_iterator &operator++() noexcept { return offset = it[static_cast(offset)].first, *this; } constexpr dense_set_local_iterator operator++(int) noexcept { const dense_set_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(it[static_cast(offset)].second); } [[nodiscard]] constexpr reference operator*() const noexcept { return *operator->(); } template [[nodiscard]] constexpr bool operator==(const dense_set_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_set_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for unique objects of a given type. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on its hash. Elements with the same hash code * appear in the same bucket. * * @tparam Type Value type of the associative container. * @tparam Hash Type of function to use to hash the values. * @tparam KeyEqual Type of function to use to compare the values for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_set { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_set_placeholder_position; using node_type = stl::pair; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t value_to_bucket(const auto &value) const noexcept { return fast_mod(static_cast(sparse.second()(value)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { if(packed.second()(packed.first()[offset].second, value)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { if(packed.second()(packed.first()[offset].second, value)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&value) { const auto index = value_to_bucket(value); if(auto it = constrained_find(value, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[value_to_bucket(packed.first().back().second)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].first) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Type; /*! @brief Value type of the container. */ using value_type = Type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the elements. */ using hasher = Hash; /*! @brief Type of function to use to compare the elements for equality. */ using key_equal = KeyEqual; /*! @brief Random access iterator type. */ using iterator = internal::dense_set_iterator; /*! @brief Constant random access iterator type. */ using const_iterator = internal::dense_set_iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = stl::reverse_iterator; /*! @brief Forward iterator type. */ using local_iterator = internal::dense_set_local_iterator; /*! @brief Constant forward iterator type. */ using const_local_iterator = internal::dense_set_local_iterator; /*! @brief Default constructor. */ dense_set() : dense_set{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_set(const allocator_type &allocator) : dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_set(const size_type cnt, const allocator_type &allocator) : dense_set{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_set{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_set(const dense_set &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_set(const dense_set &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_set(dense_set &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_set(dense_set &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_set() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_set &operator=(const dense_set &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_set &operator=(dense_set &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_set &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Returns a reverse iterator to the beginning. * * If the array 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 noexcept { return stl::make_reverse_iterator(cend()); } /*! @copydoc crbegin */ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @copydoc rbegin */ [[nodiscard]] reverse_iterator rbegin() noexcept { return stl::make_reverse_iterator(end()); } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last instance of the * reversed internal array. */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return stl::make_reverse_iterator(cbegin()); } /*! @copydoc crend */ [[nodiscard]] const_reverse_iterator rend() const noexcept { return crend(); } /*! @copydoc rend */ [[nodiscard]] reverse_iterator rend() noexcept { return stl::make_reverse_iterator(begin()); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if it does not exist. * @param value An element to insert into the container. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value)); } /** * @brief Inserts elements into the container, if they do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Constructs an element in-place, if it does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace(Args &&...args) { if constexpr(((sizeof...(Args) == 1u) && ... && stl::is_same_v, value_type>)) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(stl::piecewise_construct, stl::make_tuple(packed.first().size()), stl::forward_as_tuple(stl::forward(args)...)); const auto index = value_to_bucket(node.second); if(auto it = constrained_find(node.second, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.first, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(*pos); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].second); } return (begin() + dist); } /** * @brief Removes the element associated with a given value. * @param value Value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const value_type &value) { for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != placeholder_position; curr = &packed.first()[*curr].first) { if(packed.second()(packed.first()[*curr].second, value)) { const auto index = *curr; *curr = packed.first()[*curr].first; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Returns the number of elements matching a value (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const value_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given value. * @param value Value of an element to search for. * @return An iterator to an element with the given value. If no such * element is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const value_type &value) { return constrained_find(value, value_to_bucket(value)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const value_type &value) const { return constrained_find(value, value_to_bucket(value)); } /** * @brief Finds an element that compares _equivalent_ to a given value. * @param value Value of an element to search for. * @return An iterator to an element with the given value. If no such * element is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &value) requires is_transparent_v && is_transparent_v { return constrained_find(value, value_to_bucket(value)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &value) const requires is_transparent_v && is_transparent_v { return constrained_find(value, value_to_bucket(value)); } /** * @brief Returns a range containing all elements with a given value. * @param value Value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const value_type &value) { const auto it = find(value); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const value_type &value) const { const auto it = find(value); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given value. * @param value Value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &value) requires is_transparent_v && is_transparent_v { const auto it = find(value); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &value) const requires is_transparent_v && is_transparent_v { const auto it = find(value); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given value. * @param value Value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const value_type &value) const { return (find(value) != cend()); } /** * @brief Checks if the container contains an element that compares * _equivalent_ to a given value. * @param value Value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &value) const requires is_transparent_v && is_transparent_v { return (find(value) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given element. * @param value The value of the element to examine. * @return The bucket for the given element. */ [[nodiscard]] size_type bucket(const value_type &value) const { return value_to_bucket(value); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = value_to_bucket(packed.first()[pos].second); packed.first()[pos].first = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the elements. * @return The function used to hash the elements. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare elements for equality. * @return The function used to compare elements for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt #endif // #include "container/table.hpp" #ifndef ENTT_CONTAINER_TABLE_HPP #define ENTT_CONTAINER_TABLE_HPP // #include "../config/config.h" // #include "../core/iterator.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class table_iterator { template friend class table_iterator; public: using value_type = decltype(stl::forward_as_tuple(*stl::declval()...)); using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr table_iterator() noexcept : it{} {} constexpr table_iterator(It... from) noexcept : it{from...} {} template requires (stl::constructible_from && ...) constexpr table_iterator(const table_iterator &other) noexcept : table_iterator{stl::get(other.it)...} {} constexpr table_iterator &operator++() noexcept { return (++stl::get(it), ...), *this; } constexpr table_iterator operator++(int) noexcept { const table_iterator orig = *this; return ++(*this), orig; } constexpr table_iterator &operator--() noexcept { return (--stl::get(it), ...), *this; } constexpr table_iterator operator--(int) noexcept { const table_iterator orig = *this; return operator--(), orig; } constexpr table_iterator &operator+=(const difference_type value) noexcept { return ((stl::get(it) += value), ...), *this; } constexpr table_iterator operator+(const difference_type value) const noexcept { table_iterator copy = *this; return (copy += value); } constexpr table_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr table_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return stl::forward_as_tuple(stl::get(it)[value]...); } [[nodiscard]] constexpr pointer operator->() const noexcept { return {operator[](0)}; } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const table_iterator &other) const noexcept { return stl::get<0>(it) - stl::get<0>(other.it); } template [[nodiscard]] constexpr bool operator==(const table_iterator &other) const noexcept { return stl::get<0>(it) == stl::get<0>(other.it); } template [[nodiscard]] constexpr auto operator<=>(const table_iterator &other) const noexcept { return stl::get<0>(it) <=> stl::get<0>(other.it); } private: stl::tuple it; }; } // namespace internal /*! @endcond */ /** * @brief Basic table implementation. * * Internal data structures arrange elements to maximize performance. There are * no guarantees that objects are returned in the insertion order when iterate * a table. Do not make assumption on the order in any case. * * @tparam Container Sequence container row types. */ template class basic_table { using container_type = stl::tuple; public: /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Input iterator type. */ using iterator = internal::table_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::table_iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = internal::table_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = internal::table_iterator; /*! @brief Default constructor. */ basic_table() : payload{} { } /** * @brief Copy constructs the underlying containers. * @param container The containers to copy from. */ explicit basic_table(const Container &...container) noexcept : payload{container...} { ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); } /** * @brief Move constructs the underlying containers. * @param container The containers to move from. */ explicit basic_table(Container &&...container) noexcept : payload{stl::move(container)...} { ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); } /*! @brief Default copy constructor, deleted on purpose. */ basic_table(const basic_table &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_table(basic_table &&other) noexcept : payload{stl::move(other.payload)} {} /** * @brief Constructs the underlying containers using a given allocator. * @param allocator A valid allocator. */ explicit basic_table(const auto &allocator) : payload{Container{allocator}...} {} /** * @brief Copy constructs the underlying containers using a given allocator. * @tparam Allocator Type of allocator. * @param container The containers to copy from. * @param allocator A valid allocator. */ template basic_table(const Container &...container, const Allocator &allocator) noexcept : payload{Container{container, allocator}...} { ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); } /** * @brief Move constructs the underlying containers using a given allocator. * @tparam Allocator Type of allocator. * @param container The containers to move from. * @param allocator A valid allocator. */ template basic_table(Container &&...container, const Allocator &allocator) noexcept : payload{Container{stl::move(container), allocator}...} { ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); } /** * @brief Allocator-extended move constructor. * @tparam Allocator Type of allocator. * @param other The instance to move from. * @param allocator The allocator to use. */ template basic_table(basic_table &&other, const Allocator &allocator) : payload{Container{stl::move(stl::get(other.payload)), allocator}...} {} /*! @brief Default destructor. */ ~basic_table() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This container. */ basic_table &operator=(const basic_table &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This container. */ basic_table &operator=(basic_table &&other) noexcept { swap(other); return *this; } /** * @brief Exchanges the contents with those of a given table. * @param other Table to exchange the content with. */ void swap(basic_table &other) noexcept { using stl::swap; swap(payload, other.payload); } /** * @brief Increases the capacity of a table. * * 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) { (stl::get(payload).reserve(cap), ...); } /** * @brief Returns the number of rows that a table has currently allocated * space for. * @return Capacity of the table. */ [[nodiscard]] size_type capacity() const noexcept { return stl::get<0>(payload).capacity(); } /*! @brief Requests the removal of unused capacity. */ void shrink_to_fit() { (stl::get(payload).shrink_to_fit(), ...); } /** * @brief Returns the number of rows in a table. * @return Number of rows. */ [[nodiscard]] size_type size() const noexcept { return stl::get<0>(payload).size(); } /** * @brief Checks whether a table is empty. * @return True if the table is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return stl::get<0>(payload).empty(); } /** * @brief Returns an iterator to the beginning. * * If the table is empty, the returned iterator will be equal to `end()`. * * @return An iterator to the first row of the table. */ [[nodiscard]] const_iterator cbegin() const noexcept { return {stl::get(payload).cbegin()...}; } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return {stl::get(payload).begin()...}; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last row of the table. */ [[nodiscard]] const_iterator cend() const noexcept { return {stl::get(payload).cend()...}; } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return {stl::get(payload).end()...}; } /** * @brief Returns a reverse iterator to the beginning. * * If the table is empty, the returned iterator will be equal to `rend()`. * * @return An iterator to the first row of the reversed table. */ [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return {stl::get(payload).crbegin()...}; } /*! @copydoc crbegin */ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @copydoc rbegin */ [[nodiscard]] reverse_iterator rbegin() noexcept { return {stl::get(payload).rbegin()...}; } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last row of the reversed * table. */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return {stl::get(payload).crend()...}; } /*! @copydoc crend */ [[nodiscard]] const_reverse_iterator rend() const noexcept { return crend(); } /*! @copydoc rend */ [[nodiscard]] reverse_iterator rend() noexcept { return {stl::get(payload).rend()...}; } /** * @brief Appends a row to the end of a table. * @tparam Args Types of arguments to use to construct the row data. * @param args Parameters to use to construct the row data. * @return A reference to the newly created row data. */ template stl::tuple emplace(Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return stl::forward_as_tuple(stl::get(payload).emplace_back()...); } else { return stl::forward_as_tuple(stl::get(payload).emplace_back(stl::forward(args))...); } } /** * @brief Removes a row from a table. * @param pos An iterator to the row to remove. * @return An iterator following the removed row. */ iterator erase(const_iterator pos) { const auto diff = pos - begin(); return {stl::get(payload).erase(stl::get(payload).begin() + diff)...}; } /** * @brief Removes a row from a table. * @param pos Index of the row to remove. */ void erase(const size_type pos) { ENTT_ASSERT(pos < size(), "Index out of bounds"); erase(begin() + static_cast(pos)); } /** * @brief Returns the row data at specified location. * @param pos The row for which to return the data. * @return The row data at specified location. */ [[nodiscard]] stl::tuple operator[](const size_type pos) const { ENTT_ASSERT(pos < size(), "Index out of bounds"); return stl::forward_as_tuple(stl::get(payload)[pos]...); } /*! @copydoc operator[] */ [[nodiscard]] stl::tuple operator[](const size_type pos) { ENTT_ASSERT(pos < size(), "Index out of bounds"); return stl::forward_as_tuple(stl::get(payload)[pos]...); } /*! @brief Clears a table. */ void clear() { (stl::get(payload).clear(), ...); } private: container_type payload; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::bool_constant<(entt::stl::uses_allocator_v && ...)> {}; } // namespace std /*! @endcond */ #endif // #include "core/algorithm.hpp" #ifndef ENTT_CORE_ALGORITHM_HPP #define ENTT_CORE_ALGORITHM_HPP // #include "../stl/algorithm.hpp" #ifndef ENTT_STL_ALGORITHM_HPP #define ENTT_STL_ALGORITHM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::all_of; using std::any_of; using std::find_if; using std::none_of; using std::sort; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Function object to wrap `stl::sort` in a class type. * * Unfortunately, `stl::sort` cannot be passed as template argument to a class * template or a function template.
* This class fills the gap by wrapping some flavors of `stl::sort` in a * function object. */ struct std_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given binary comparison function. * * @tparam Compare Type of comparison function object. * @tparam Args Types of arguments to forward to the sort function. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param compare A valid comparison function object. * @param args Arguments to forward to the sort function, if any. */ template, typename... Args> void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}, Args &&...args) const { stl::sort(stl::forward(args)..., stl::move(first), stl::move(last), stl::move(compare)); } }; /*! @brief Function object for performing insertion sort. */ struct insertion_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given binary comparison function. * * @tparam Compare Type of comparison function object. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param compare A valid comparison function object. */ template> void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}) const { if(first < last) { for(auto it = first + 1; it < last; ++it) { auto value = stl::move(*it); auto pre = it; // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; pre > first && compare(value, *(pre - 1)); --pre) { *pre = stl::move(*(pre - 1)); } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) *pre = stl::move(value); } } } }; /** * @brief Function object for performing LSD radix sort. * @tparam Bit Number of bits processed per pass. * @tparam N Maximum number of bits to sort. */ template requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass struct radix_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given _getter_ to access the * actual data to be sorted. * * This implementation is inspired by the online book * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). * * @tparam It Type of random access iterator. * @tparam Getter Type of _getter_ function object. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param getter A valid _getter_ function object. */ template void operator()(It first, It last, Getter getter = Getter{}) const { if(first < last) { constexpr auto passes = N / Bit; using value_type = stl::iterator_traits::value_type; using difference_type = stl::iterator_traits::difference_type; stl::vector aux(static_cast(stl::distance(first, last))); auto part = [getter = stl::move(getter)](auto from, auto to, auto out, auto start) { constexpr auto mask = (1 << Bit) - 1; constexpr auto buckets = 1 << Bit; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-const-correctness) stl::size_t count[buckets]{}; for(auto it = from; it != to; ++it) { ++count[(getter(*it) >> start) & mask]; } // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) stl::size_t index[buckets]{}; for(stl::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { index[pos + 1u] = index[pos] + count[pos]; } for(auto it = from; it != to; ++it) { const auto pos = index[(getter(*it) >> start) & mask]++; out[static_cast(pos)] = stl::move(*it); } }; for(stl::size_t pass = 0; pass < (passes & ~1u); pass += 2) { part(first, last, aux.begin(), pass * Bit); part(aux.begin(), aux.end(), first, (pass + 1) * Bit); } if constexpr(passes & 1) { part(first, last, aux.begin(), (passes - 1) * Bit); stl::move(aux.begin(), aux.end(), first); } } } }; } // namespace entt #endif // #include "core/any.hpp" #ifndef ENTT_CORE_ANY_HPP #define ENTT_CORE_ANY_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" #ifndef ENTT_STL_STRING_VIEW_HPP #define ENTT_STL_STRING_VIEW_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string_view; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct fnv_1a_params; template<> struct fnv_1a_params { static constexpr auto offset = 2166136261; static constexpr auto prime = 16777619; }; template<> struct fnv_1a_params { static constexpr auto offset = 14695981039346656037ull; static constexpr auto prime = 1099511628211ull; }; template struct basic_hashed_string { using value_type = Char; using size_type = stl::size_t; using hash_type = id_type; const value_type *repr{}; hash_type hash{fnv_1a_params<>::offset}; size_type length{}; }; } // namespace internal /*! @endcond */ /** * @brief Zero overhead unique identifier. * * A hashed string is a compile-time tool that allows users to use * human-readable identifiers 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. * * @warning * This class doesn't take ownership of user-supplied strings nor does it make a * copy of them. * * @tparam Char Character type. */ template class basic_hashed_string: internal::basic_hashed_string { using base_type = internal::basic_hashed_string; using params = internal::fnv_1a_params<>; struct const_wrapper { // non-explicit constructor on purpose constexpr const_wrapper(const base_type::value_type *str) noexcept : repr{str} {} const base_type::value_type *repr; }; public: /*! @brief Character type. */ using value_type = base_type::value_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Unsigned integer type. */ using hash_type = base_type::hash_type; /** * @brief Returns directly the numeric representation of a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. * @return The numeric representation of the string. */ [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { return basic_hashed_string{str, len}; } /** * @brief Returns directly the numeric representation of a string. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. * @return The numeric representation of the string. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { return basic_hashed_string{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 constexpr hash_type value(const_wrapper wrapper) noexcept { return basic_hashed_string{wrapper}; } /*! @brief Constructs an empty hashed string. */ constexpr basic_hashed_string() noexcept : basic_hashed_string{nullptr, 0u} {} /** * @brief Constructs a hashed string from a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. */ constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; base_type::length < len; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Constructs a hashed string from an array of const characters. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { for(; str[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } } /** * @brief Explicit constructor on purpose to avoid constructing a hashed * string directly from a `const value_type *`. * * @warning * The lifetime of the string is not extended nor is it copied. * * @param wrapper Helps achieving the purpose by relying on overloading. */ explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept : base_type{wrapper.repr} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; wrapper.repr[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Returns the size of a hashed string. * @return The size of the hashed string. */ [[nodiscard]] constexpr size_type size() const noexcept { return base_type::length; } /** * @brief Returns the human-readable representation of a hashed string. * @return The string used to initialize the hashed string. */ [[nodiscard]] constexpr const value_type *data() const noexcept { return base_type::repr; } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr hash_type value() const noexcept { return base_type::hash; } /*! @copydoc data */ [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { return data(); } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr operator hash_type() const noexcept { return value(); } /** * @brief Compares two hashed strings. * @param other A valid hashed string. * @return True if the two hashed strings are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { return value() == other.value(); } /** * @brief Lexicographically compares two hashed strings. * @param other A valid hashed string. * @return The relative order between the two hashed strings. */ [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { return value() <=> other.value(); } }; /** * @brief Deduction guide. * @tparam Char Character type. * @param str Human-readable identifier. * @param len Length of the string to hash. */ template basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; /** * @brief Deduction guide. * @tparam Char Character type. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) basic_hashed_string(const Char (&str)[N]) -> 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]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { return hashed_string{str}; } /** * @brief User defined literal for hashed wstrings. * @param str The literal without its suffix. * @return A properly initialized hashed wstring. */ [[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { return hashed_wstring{str}; } } // namespace literals } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @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) 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) 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. */ constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) : func{stl::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 constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } private: Func func; }; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { enum class any_request : stl::uint8_t { info, transfer, assign, compare, copy, move }; template struct basic_any_storage { static constexpr bool has_buffer = true; union { const void *instance{}; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) alignas(Align) stl::byte buffer[Len]; }; }; template struct basic_any_storage<0u, Align> { static constexpr bool has_buffer = false; const void *instance{}; }; template // NOLINTNEXTLINE(bugprone-sizeof-expression) struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v> {}; template struct in_situ: stl::false_type {}; } // namespace internal /*! @endcond */ /** * @brief A SBO friendly, type-safe container for single values of any type. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Optional alignment requirement. */ template class basic_any: private internal::basic_any_storage { using request = internal::any_request; using base_type = internal::basic_any_storage; using vtable_type = const void *(const request, const basic_any &, const void *); using deleter_type = void(const basic_any &); template static constexpr bool in_situ_v = internal::in_situ::value; template static const void *basic_vtable(const request req, const basic_any &value, const void *other) { switch(const auto *elem = static_cast(value.data()); req) { using enum internal::any_request; case info: return &type_id(); case transfer: if constexpr(stl::is_move_assignable_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) *const_cast(elem) = stl::move(*static_cast(const_cast(other))); return other; } [[fallthrough]]; case assign: if constexpr(stl::is_copy_assignable_v) { *const_cast(elem) = *static_cast(other); return other; } break; case compare: if constexpr(!stl::is_function_v && !stl::is_array_v && is_equality_comparable_v) { return (*elem == *static_cast(other)) ? other : nullptr; } else { return (elem == other) ? other : nullptr; } case copy: if constexpr(stl::is_copy_constructible_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) static_cast(const_cast(other))->initialize(*elem); } break; case move: ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy"); if constexpr(in_situ_v) { // NOLINTNEXTLINE(bugprone-casting-through-void, bugprone-multi-level-implicit-pointer-conversion) return ::new(&static_cast(const_cast(other))->buffer) Type{stl::move(*const_cast(elem))}; } } return nullptr; } template static void basic_deleter(const basic_any &value) { ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::is_trivially_destructible_v), "Unexpected policy"); const auto *elem = static_cast(value.data()); if constexpr(in_situ_v) { (value.mode == any_policy::embedded) ? elem->~Type() : (delete elem); } else if constexpr(stl::is_array_v) { delete[] elem; } else { delete elem; } } template void initialize([[maybe_unused]] Args &&...args) { using plain_type = stl::remove_cvref_t; vtable = basic_vtable; underlying_type = type_hash::value(); if constexpr(stl::is_void_v) { deleter = nullptr; mode = any_policy::empty; this->instance = nullptr; } else if constexpr(stl::is_lvalue_reference_v) { deleter = nullptr; mode = stl::is_const_v> ? any_policy::cref : any_policy::ref; static_assert((stl::is_lvalue_reference_v && ...) && (sizeof...(Args) == 1u), "Invalid arguments"); // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) this->instance = (stl::addressof(args), ...); } else if constexpr(in_situ_v) { if constexpr(stl::is_trivially_destructible_v) { deleter = nullptr; } else { deleter = &basic_deleter; } mode = any_policy::embedded; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { ::new(&this->buffer) plain_type{stl::forward(args)...}; } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) ::new(&this->buffer) plain_type(stl::forward(args)...); } } else { deleter = &basic_deleter; mode = any_policy::dynamic; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { this->instance = new plain_type{stl::forward(args)...}; } else if constexpr(stl::is_array_v) { static_assert(sizeof...(Args) == 0u, "Invalid arguments"); this->instance = new plain_type[stl::extent_v](); } else { this->instance = new plain_type(stl::forward(args)...); } } } void invoke_deleter_if_exists() { if(deleter != nullptr) { deleter(*this); } } public: /*! @brief Size of the internal buffer. */ static constexpr auto length = Len; /*! @brief Alignment requirement. */ static constexpr auto alignment = Align; /*! @brief Default constructor. */ constexpr basic_any() noexcept : basic_any{stl::in_place_type} {} /** * @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(stl::in_place_type_t, Args &&...args) : base_type{} { initialize(stl::forward(args)...); } /** * @brief Constructs a wrapper taking ownership of the passed object. * @tparam Type Type of object to use to initialize the wrapper. * @param value A pointer to an object to take ownership of. */ template requires (!stl::is_const_v && !stl::is_void_v) explicit basic_any(stl::in_place_t, Type *value) : base_type{} { if(value == nullptr) { initialize(); } else { initialize(*value); deleter = &basic_deleter; mode = any_policy::dynamic; } } /** * @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 requires (!stl::same_as, basic_any>) basic_any(Type &&value) : basic_any{stl::in_place_type>, stl::forward(value)} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ basic_any(const basic_any &other) : basic_any{} { other.vtable(request::copy, other, this); } /** * @brief Move constructor. * @param other The instance to move from. */ basic_any(basic_any &&other) noexcept : base_type{}, vtable{other.vtable}, deleter{other.deleter}, underlying_type{other.underlying_type}, mode{other.mode} { if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } } /*! @brief Frees the internal buffer, whatever it means. */ ~basic_any() { invoke_deleter_if_exists(); } /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This any object. */ basic_any &operator=(const basic_any &other) { if(this != &other) { invoke_deleter_if_exists(); if(other) { other.vtable(request::copy, other, this); } else { initialize(); } } return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This any object. */ basic_any &operator=(basic_any &&other) noexcept { if(this != &other) { invoke_deleter_if_exists(); if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } vtable = other.vtable; deleter = other.deleter; underlying_type = other.underlying_type; 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 requires (!stl::same_as, basic_any>) basic_any &operator=(Type &&value) { emplace>(stl::forward(value)); return *this; } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] bool has_value() const noexcept { return (mode != any_policy::empty); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @param req Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ [[nodiscard]] bool has_value(const type_info &req) const noexcept { return (underlying_type == req.hash()); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @tparam Type Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ template [[nodiscard]] bool has_value() const noexcept { return (underlying_type == type_hash::value()); } /** * @brief Returns the object type info if any, `type_id()` otherwise. * @return The object type info if any, `type_id()` otherwise. */ [[nodiscard]] const type_info &info() const noexcept { return *static_cast(vtable(request::info, *this, nullptr)); } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data() const noexcept { if constexpr(base_type::has_buffer) { return (mode == any_policy::embedded) ? &this->buffer : this->instance; } else { return this->instance; } } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data(const type_info &req) const noexcept { return has_value(req) ? data() : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] const Type *data() const noexcept { return has_value>() ? static_cast(data()) : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data() noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data()); } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data(const type_info &req) noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data(req)); } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] Type *data() noexcept { if constexpr(stl::is_const_v) { return stl::as_const(*this).template data>(); } else { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).template data>()); } } /** * @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) { invoke_deleter_if_exists(); initialize(stl::forward(args)...); } /** * @brief Assigns a value to the contained object without replacing it. * @param other The value to assign to the contained object. * @return True in case of success, false otherwise. */ bool assign(const basic_any &other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (vtable(request::assign, *this, other.data()) != nullptr); } return false; } /*! @copydoc assign */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) bool assign(basic_any &&other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (other.mode == any_policy::cref) ? (vtable(request::assign, *this, stl::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr); } return false; } /*! @brief Destroys contained object */ void reset() { invoke_deleter_if_exists(); initialize(); } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return has_value(); } /** * @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 basic_any &other) const noexcept { if(other && (underlying_type == other.underlying_type)) { return (vtable(request::compare, *this, other.data()) != nullptr); } return (!*this && !other); } /** * @brief Aliasing constructor. * @return A wrapper that shares a reference to an unmanaged object. */ [[nodiscard]] basic_any as_ref() noexcept { basic_any other = stl::as_const(*this).as_ref(); switch(mode) { using enum any_policy; case cref: case empty: other.mode = mode; break; default: other.mode = any_policy::ref; break; } return other; } /*! @copydoc as_ref */ [[nodiscard]] basic_any as_ref() const noexcept { basic_any other{}; other.instance = data(); other.vtable = vtable; other.underlying_type = underlying_type; other.mode = any_policy::cref; return other; } /** * @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 noexcept { return (mode == any_policy::dynamic || mode == any_policy::embedded); } /** * @brief Returns the current mode of an any object. * @return The current mode of the any object. */ [[nodiscard]] any_policy policy() const noexcept { return mode; } private: vtable_type *vtable{}; deleter_type *deleter{}; id_type underlying_type{}; any_policy mode{}; }; /** * @brief Performs type-safe access to the contained object. * @tparam Type Type to which conversion is required. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Alignment requirement. * @param data Target any object. * @return The element converted to the requested type. */ template [[nodiscard]] stl::remove_const_t any_cast(const basic_any &data) noexcept { const auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(*instance); } /*! @copydoc any_cast */ template [[nodiscard]] stl::remove_const_t any_cast(basic_any &data) 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 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) [[nodiscard]] stl::remove_const_t any_cast(basic_any &&data) noexcept { if constexpr(stl::is_copy_constructible_v>) { if(auto *const instance = any_cast>(&data); instance) { return static_cast(stl::move(*instance)); } return any_cast(data); } else { auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(stl::move(*instance)); } } /*! @copydoc any_cast */ template [[nodiscard]] const Type *any_cast(const basic_any *data) noexcept { return data->template data>(); } /*! @copydoc any_cast */ template [[nodiscard]] Type *any_cast(basic_any *data) noexcept { if constexpr(stl::is_const_v) { // last attempt to make wrappers for const references return their values return any_cast(&stl::as_const(*data)); } else { return data->template data(); } } /** * @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 buffer 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, stl::size_t Align = basic_any::alignment, typename... Args> [[nodiscard]] basic_any make_any(Args &&...args) { return basic_any{stl::in_place_type, stl::forward(args)...}; } /** * @brief Forwards its argument and avoids copies for lvalue references. * @tparam Len Size of the buffer 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, stl::size_t Align = basic_any::alignment, typename Type> [[nodiscard]] basic_any forward_as_any(Type &&value) { return basic_any{stl::in_place_type, stl::forward(value)}; } } // namespace entt #endif // #include "core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "core/enum.hpp" #ifndef ENTT_CORE_ENUM_HPP #define ENTT_CORE_ENUM_HPP // #include "../stl/concepts.hpp" // #include "../stl/type_traits.hpp" namespace entt { /** * @brief Enable bitmask support for enum classes. * @tparam Type The enum type for which to enable bitmask support. */ template struct enum_as_bitmask: stl::false_type {}; /*! @copydoc enum_as_bitmask */ template requires requires { requires stl::is_enum_v; { Type::_entt_enum_as_bitmask } -> stl::same_as; } struct enum_as_bitmask: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The enum class type for which to enable bitmask support. */ template inline constexpr bool enum_as_bitmask_v = enum_as_bitmask::value; /** * @brief Specifies that an enum class supports bitmask operations. * @tparam Type Enum class type. */ template // check again that it is an enum to deal with incorrect specializations concept enum_bitmask = stl::is_enum_v && enum_as_bitmask_v; } // namespace entt /** * @brief Operator available for enums for which bitmask support is enabled. * @tparam Type Enum class type. * @param lhs The first value to use. * @param rhs The second value to use. * @return The result of invoking the operator on the underlying types of the * two values provided. */ template [[nodiscard]] constexpr Type operator|(const Type lhs, const Type rhs) noexcept { return static_cast(static_cast>(lhs) | static_cast>(rhs)); } /*! @copydoc operator| */ template [[nodiscard]] constexpr Type operator&(const Type lhs, const Type rhs) noexcept { return static_cast(static_cast>(lhs) & static_cast>(rhs)); } /*! @copydoc operator| */ template [[nodiscard]] constexpr Type operator^(const Type lhs, const Type rhs) noexcept { return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); } /** * @brief Operator available for enums for which bitmask support is enabled. * @tparam Type Enum class type. * @param value The value to use. * @return The result of invoking the operator on the underlying types of the * value provided. */ template [[nodiscard]] constexpr Type operator~(const Type value) noexcept { return static_cast(~static_cast>(value)); } /*! @copydoc operator~ */ template [[nodiscard]] constexpr bool operator!(const Type value) noexcept { return !static_cast>(value); } /*! @copydoc operator| */ template constexpr Type &operator|=(Type &lhs, const Type rhs) noexcept { return (lhs = (lhs | rhs)); } /*! @copydoc operator| */ template constexpr Type &operator&=(Type &lhs, const Type rhs) noexcept { return (lhs = (lhs & rhs)); } /*! @copydoc operator| */ template constexpr Type &operator^=(Type &lhs, const Type rhs) noexcept { return (lhs = (lhs ^ rhs)); } #endif // #include "core/family.hpp" #ifndef ENTT_CORE_FAMILY_HPP #define ENTT_CORE_FAMILY_HPP // #include "../config/config.h" // #include "fwd.hpp" namespace entt { /** * @brief Dynamic identifier generator. * * Utility class template that can be used to assign unique identifiers to types * at runtime. Use different specializations to create separate sets of * identifiers. */ template class family { static auto identifier() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } public: /*! @brief Unsigned integer type. */ using value_type = id_type; /*! @brief Statically generated unique identifier for the given type. */ template // at the time I'm writing, clang crashes during compilation if auto is used instead of value_type inline static const value_type value = identifier(); }; } // namespace entt #endif // #include "core/hashed_string.hpp" #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct fnv_1a_params; template<> struct fnv_1a_params { static constexpr auto offset = 2166136261; static constexpr auto prime = 16777619; }; template<> struct fnv_1a_params { static constexpr auto offset = 14695981039346656037ull; static constexpr auto prime = 1099511628211ull; }; template struct basic_hashed_string { using value_type = Char; using size_type = stl::size_t; using hash_type = id_type; const value_type *repr{}; hash_type hash{fnv_1a_params<>::offset}; size_type length{}; }; } // namespace internal /*! @endcond */ /** * @brief Zero overhead unique identifier. * * A hashed string is a compile-time tool that allows users to use * human-readable identifiers 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. * * @warning * This class doesn't take ownership of user-supplied strings nor does it make a * copy of them. * * @tparam Char Character type. */ template class basic_hashed_string: internal::basic_hashed_string { using base_type = internal::basic_hashed_string; using params = internal::fnv_1a_params<>; struct const_wrapper { // non-explicit constructor on purpose constexpr const_wrapper(const base_type::value_type *str) noexcept : repr{str} {} const base_type::value_type *repr; }; public: /*! @brief Character type. */ using value_type = base_type::value_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Unsigned integer type. */ using hash_type = base_type::hash_type; /** * @brief Returns directly the numeric representation of a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. * @return The numeric representation of the string. */ [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { return basic_hashed_string{str, len}; } /** * @brief Returns directly the numeric representation of a string. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. * @return The numeric representation of the string. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { return basic_hashed_string{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 constexpr hash_type value(const_wrapper wrapper) noexcept { return basic_hashed_string{wrapper}; } /*! @brief Constructs an empty hashed string. */ constexpr basic_hashed_string() noexcept : basic_hashed_string{nullptr, 0u} {} /** * @brief Constructs a hashed string from a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. */ constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; base_type::length < len; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Constructs a hashed string from an array of const characters. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { for(; str[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } } /** * @brief Explicit constructor on purpose to avoid constructing a hashed * string directly from a `const value_type *`. * * @warning * The lifetime of the string is not extended nor is it copied. * * @param wrapper Helps achieving the purpose by relying on overloading. */ explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept : base_type{wrapper.repr} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; wrapper.repr[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Returns the size of a hashed string. * @return The size of the hashed string. */ [[nodiscard]] constexpr size_type size() const noexcept { return base_type::length; } /** * @brief Returns the human-readable representation of a hashed string. * @return The string used to initialize the hashed string. */ [[nodiscard]] constexpr const value_type *data() const noexcept { return base_type::repr; } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr hash_type value() const noexcept { return base_type::hash; } /*! @copydoc data */ [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { return data(); } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr operator hash_type() const noexcept { return value(); } /** * @brief Compares two hashed strings. * @param other A valid hashed string. * @return True if the two hashed strings are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { return value() == other.value(); } /** * @brief Lexicographically compares two hashed strings. * @param other A valid hashed string. * @return The relative order between the two hashed strings. */ [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { return value() <=> other.value(); } }; /** * @brief Deduction guide. * @tparam Char Character type. * @param str Human-readable identifier. * @param len Length of the string to hash. */ template basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; /** * @brief Deduction guide. * @tparam Char Character type. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) basic_hashed_string(const Char (&str)[N]) -> 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]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { return hashed_string{str}; } /** * @brief User defined literal for hashed wstrings. * @param str The literal without its suffix. * @return A properly initialized hashed wstring. */ [[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { return hashed_wstring{str}; } } // namespace literals } // namespace entt #endif // #include "core/ident.hpp" #ifndef ENTT_CORE_IDENT_HPP #define ENTT_CORE_IDENT_HPP // #include "../stl/cstddef.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "type_traits.hpp" namespace entt { /** * @brief Type integral identifiers. * @tparam Type List of types for which to generate identifiers. */ template class ident { template [[nodiscard]] static ENTT_CONSTEVAL id_type get(stl::index_sequence) noexcept { return (0 + ... + (stl::is_same_v...>>> ? id_type{Index} : id_type{})); } public: /*! @brief Unsigned integer type. */ using value_type = id_type; /*! @brief Statically generated unique identifier for the given type. */ template requires (stl::is_same_v, Type> || ...) static constexpr value_type value = get>(stl::index_sequence_for{}); }; } // namespace entt #endif // #include "core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "core/monostate.hpp" #ifndef ENTT_CORE_MONOSTATE_HPP #define ENTT_CORE_MONOSTATE_HPP // #include "../config/config.h" // #include "fwd.hpp" namespace entt { /** * @brief Minimal implementation of the monostate pattern. * * A minimal, yet complete configuration system built on top of the monostate * pattern. Thread safe by design, it works only with basic types like `int`s or * `bool`s.
* Multiple types and therefore more than one value can be associated with a * single key. Because of this, users must pay attention to use the same type * both during an assignment and when they try to read back their data. * Otherwise, they can incur in unexpected results. */ template struct monostate { /** * @brief Assigns a value of a specific type to a given key. * @tparam Type Type of the value to assign. * @param val User data to assign to the given key. * @return This monostate object. */ template monostate &operator=(Type val) noexcept { value = val; return *this; } /** * @brief Gets a value of a specific type for a given key. * @tparam Type Type of the value to get. * @return Stored value, if any. */ template operator Type() const noexcept { return value; } private: template // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) inline static ENTT_MAYBE_ATOMIC(Type) value{}; }; /** * @brief Helper variable template. * @tparam Value Value used to differentiate between different variables. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) inline monostate monostate_v{}; } // namespace entt #endif // #include "core/ranges.hpp" #ifndef ENTT_CORE_RANGES_HPP #define ENTT_CORE_RANGES_HPP #include #if defined(__cpp_lib_ranges) # include // # include "iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif namespace std::ranges { template inline constexpr bool enable_borrowed_range>{true}; template inline constexpr bool enable_view>{true}; } // namespace std::ranges #endif #endif // #include "core/tuple.hpp" #ifndef ENTT_CORE_TUPLE_HPP #define ENTT_CORE_TUPLE_HPP // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Provides the member constant `value` equal to true if a given type is * a tuple, false otherwise. * @tparam Type The type to test. */ template struct is_tuple: stl::false_type {}; /** * @copybrief is_tuple * @tparam Args Tuple template arguments. */ template struct is_tuple>: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_tuple_v = is_tuple::value; /** * @brief Utility function to unwrap tuples of a single element. * @tparam Type Tuple type of any sizes. * @param value A tuple object of the given type. * @return The tuple itself if it contains more than one element, the first * element otherwise. */ template constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept { if constexpr(stl::tuple_size_v> == 1u) { return stl::get<0>(stl::forward(value)); } else { return stl::forward(value); } } /** * @brief Utility class to forward-and-apply tuple objects. * @tparam Func Type of underlying invocable object. */ template struct forward_apply: private Func { /** * @brief Constructs a forward-and-apply object. * @tparam Args Types of arguments to use to construct the new instance. * @param args Parameters to use to construct the instance. */ template constexpr forward_apply(Args &&...args) noexcept(stl::is_nothrow_constructible_v) : Func{stl::forward(args)...} {} /** * @brief Forwards and applies the arguments with the underlying function. * @tparam Type Tuple-like type to forward to the underlying function. * @param args Parameters to forward to the underlying function. * @return Return value of the underlying function, if any. */ template constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(stl::apply(stl::declval(), args))) { return stl::apply(static_cast(*this), stl::forward(args)); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(stl::apply(stl::declval(), args))) { return stl::apply(static_cast(*this), stl::forward(args)); } }; /** * @brief Deduction guide. * @tparam Func Type of underlying invocable object. */ template forward_apply(Func) -> forward_apply>; } // namespace entt #endif // #include "core/type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "core/utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @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) 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) 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. */ constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) : func{stl::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 constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } private: Func func; }; } // namespace entt #endif // #include "entity/component.hpp" #ifndef ENTT_ENTITY_COMPONENT_HPP #define ENTT_ENTITY_COMPONENT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_ENTITY_FWD_HPP #define ENTT_ENTITY_FWD_HPP // #include "../config/config.h" // #include "../core/concepts.hpp" // #include "../core/fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" namespace entt { /*! @brief Default entity identifier. */ enum class entity : id_type {}; /*! @brief Storage deletion policy. */ enum class deletion_policy : stl::uint8_t { /*! @brief Swap-and-pop deletion policy. */ swap_and_pop = 0u, /*! @brief In-place deletion policy. */ in_place = 1u, /*! @brief Swap-only deletion policy. */ swap_only = 2u, /*! @brief Unspecified deletion policy. */ unspecified = swap_and_pop }; template struct component_traits; template> class basic_sparse_set; template> class basic_storage; template class basic_sigh_mixin; template class basic_reactive_mixin; template> class basic_registry; template class basic_view; template> class basic_runtime_view; template class basic_group; template class basic_organizer; template class basic_handle; template class basic_snapshot; template class basic_snapshot_loader; template class basic_continuous_loader; /*! @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 Type Element type. */ template using storage = basic_storage; /** * @brief Alias declaration for the most common use case. * @tparam Type Underlying storage type. */ template using sigh_mixin = basic_sigh_mixin>; /** * @brief Alias declaration for the most common use case. * @tparam Type Underlying storage type. */ template using reactive_mixin = basic_reactive_mixin>; /*! @brief Alias declaration for the most common use case. */ using registry = basic_registry<>; /*! @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. */ using runtime_view = basic_runtime_view; /*! @brief Alias declaration for the most common use case. */ using const_runtime_view = basic_runtime_view; /** * @brief Alias for exclusion lists. * @tparam Type List of types. */ template struct exclude_t final: type_list { /*! @brief Default constructor. */ explicit ENTT_CONSTEVAL exclude_t() = default; }; /** * @brief Variable template for exclusion lists. * @tparam Type List of types. */ template inline constexpr exclude_t exclude{}; /** * @brief Alias for lists of observed elements. * @tparam Type List of types. */ template struct get_t final: type_list { /*! @brief Default constructor. */ explicit ENTT_CONSTEVAL get_t() = default; }; /** * @brief Variable template for lists of observed elements. * @tparam Type List of types. */ template inline constexpr get_t get{}; /** * @brief Alias for lists of owned elements. * @tparam Type List of types. */ template struct owned_t final: type_list { /*! @brief Default constructor. */ explicit ENTT_CONSTEVAL owned_t() = default; }; /** * @brief Variable template for lists of owned elements. * @tparam Type List of types. */ template inline constexpr owned_t owned{}; /** * @brief Applies a given _function_ to a get list and generate a new list. * @tparam Type Types provided by the get list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting get list after applying the transform function. */ using type = get_t::type...>; }; /** * @brief Applies a given _function_ to an exclude list and generate a new list. * @tparam Type Types provided by the exclude list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting exclude list after applying the transform function. */ using type = exclude_t::type...>; }; /** * @brief Applies a given _function_ to an owned list and generate a new list. * @tparam Type Types provided by the owned list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting owned list after applying the transform function. */ using type = owned_t::type...>; }; /** * @brief Provides a common way to define storage types. * @tparam Type Storage value type. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template> struct storage_type { /*! @brief Type-to-storage conversion result. */ using type = ENTT_STORAGE(sigh_mixin, basic_storage); }; /*! @brief Empty value type for reactive storage types. */ struct reactive final {}; /** * @ brief Partial specialization for reactive storage types. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct storage_type { /*! @brief Type-to-storage conversion result. */ using type = ENTT_STORAGE(reactive_mixin, basic_storage); }; /** * @brief Helper type. * @tparam Args Arguments to forward. */ template using storage_type_t = storage_type::type; /** * Type-to-storage conversion utility that preserves constness. * @tparam Type Storage value type, eventually const. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template>> struct storage_for { /*! @brief Type-to-storage conversion result. */ using type = constness_as_t, Entity, Allocator>, Type>; }; /** * @brief Helper type. * @tparam Args Arguments to forward. */ template using storage_for_t = storage_for::type; /** * @brief Alias declaration for the most common use case. * @tparam Get Types of storage iterated by the view. * @tparam Exclude Types of storage used to filter the view. */ template> using view = basic_view, type_list_transform_t>; /** * @brief Alias declaration for the most common use case. * @tparam Owned Types of storage _owned_ by the group. * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. */ template, typename Exclude = exclude_t<>> using group = basic_group, type_list_transform_t, type_list_transform_t>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct in_place_delete: stl::bool_constant && stl::is_move_assignable_v)> {}; template<> struct in_place_delete: stl::false_type {}; template requires Type::in_place_delete struct in_place_delete: stl::true_type {}; template struct page_size: stl::integral_constant * ENTT_PACKED_PAGE> {}; template<> struct page_size: stl::integral_constant {}; template requires stl::is_convertible_v struct page_size: stl::integral_constant {}; } // namespace internal /*! @endcond */ /** * @brief Common way to access various properties of components. * @tparam Type Element type. * @tparam Entity A valid entity type. */ template struct component_traits { /*! @brief Element type. */ using element_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Pointer stability, default is `false`. */ static constexpr bool in_place_delete = internal::in_place_delete::value; /*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */ static constexpr stl::size_t page_size = internal::page_size::value; }; } // namespace entt #endif // #include "entity/entity.hpp" #ifndef ENTT_ENTITY_ENTITY_HPP #define ENTT_ENTITY_ENTITY_HPP // #include "../config/config.h" // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "../stl/type_traits.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct entt_traits; template requires requires { requires stl::is_enum_v; typename internal::entt_traits>::value_type; } struct entt_traits: entt_traits> { using value_type = Type; }; template requires requires { typename Type::entity_type; } struct entt_traits : entt_traits { using value_type = Type; }; template<> struct entt_traits { using value_type = stl::uint32_t; using entity_type = stl::uint32_t; using version_type = stl::uint16_t; static constexpr entity_type entity_mask = 0xFFFFF; static constexpr entity_type version_mask = 0xFFF; }; template<> struct entt_traits { using value_type = stl::uint64_t; using entity_type = stl::uint64_t; using version_type = stl::uint32_t; static constexpr entity_type entity_mask = 0xFFFFFFFF; static constexpr entity_type version_mask = 0xFFFFFFFF; }; } // namespace internal /*! @endcond */ /** * @brief Specifies that a type is an entity-like type. * @tparam Type Type to check. */ template concept entity_like = requires { typename internal::entt_traits::value_type; }; /** * @brief Common basic entity traits implementation. * @tparam Traits Actual entity traits to use. */ template class basic_entt_traits { static constexpr auto length = stl::popcount(Traits::entity_mask); public: /*! @brief Value type. */ using value_type = Traits::value_type; /*! @brief Underlying entity type. */ using entity_type = Traits::entity_type; /*! @brief Underlying version type. */ using version_type = Traits::version_type; /*! @brief Entity mask size. */ static constexpr entity_type entity_mask = Traits::entity_mask; /*! @brief Version mask size */ static constexpr entity_type version_mask = Traits::version_mask; /** * @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) 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) noexcept { static_assert(Traits::entity_mask && ((Traits::entity_mask & (Traits::entity_mask + 1)) == 0), "Invalid entity mask"); return (to_integral(value) & 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) noexcept { if constexpr(Traits::version_mask == 0u) { return version_type{}; } else { static_assert((Traits::version_mask & (Traits::version_mask + 1)) == 0, "Invalid version mask"); return (static_cast(to_integral(value) >> length) & version_mask); } } /** * @brief Returns the successor of a given identifier. * @param value The identifier of which to return the successor. * @return The successor of the given identifier. */ [[nodiscard]] static constexpr value_type next(const value_type value) noexcept { const auto vers = to_version(value) + 1; return construct(to_integral(value), static_cast(vers + (vers == version_mask))); } /** * @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, const version_type version) noexcept { if constexpr(Traits::version_mask == 0u) { return value_type{entity & entity_mask}; } else { return value_type{(entity & entity_mask) | (static_cast(version & version_mask) << length)}; } } /** * @brief Combines two identifiers in a single one. * * The returned identifier is a copy of the first element except for its * version, which is taken from the second element. * * @param lhs The identifier from which to take the entity part. * @param rhs The identifier from which to take the version part. * @return A properly constructed identifier. */ [[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept { if constexpr(Traits::version_mask == 0u) { return value_type{lhs & entity_mask}; } else { return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))}; } } }; /** * @brief Entity traits. * @tparam Type Type of identifier. */ template struct entt_traits: basic_entt_traits> { /*! @brief Base type. */ using base_type = basic_entt_traits>; /*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */ static constexpr stl::size_t page_size = ENTT_SPARSE_PAGE; }; /** * @brief Converts an entity to its underlying type. * @tparam Entity The value type. * @param value The value to convert. * @return The integral representation of the given value. */ template [[nodiscard]] constexpr entt_traits::entity_type to_integral(const Entity value) noexcept { return entt_traits::to_integral(value); } /** * @brief Returns the entity part once converted to the underlying type. * @tparam Entity The value type. * @param value The value to convert. * @return The integral representation of the entity part. */ template [[nodiscard]] constexpr entt_traits::entity_type to_entity(const Entity value) noexcept { return entt_traits::to_entity(value); } /** * @brief Returns the version part once converted to the underlying type. * @tparam Entity The value type. * @param value The value to convert. * @return The integral representation of the version part. */ template [[nodiscard]] constexpr entt_traits::version_type to_version(const Entity value) noexcept { return entt_traits::to_version(value); } /*! @brief Null object for all identifiers. */ struct null_t { /** * @brief Converts the null object to identifiers of any type. * @tparam Entity Type of identifier. * @return The null representation for the given type. */ template [[nodiscard]] constexpr operator Entity() const noexcept { using traits_type = entt_traits; return traits_type::construct(traits_type::entity_mask, traits_type::version_mask); } /** * @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 noexcept { return true; } /** * @brief Compares a null object and an identifier of any type. * @tparam Entity Type of identifier. * @param entity Identifier with which to compare. * @return False if the two elements differ, true otherwise. */ template [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { using traits_type = entt_traits; return traits_type::to_entity(entity) == traits_type::to_entity(*this); } }; /*! @brief Tombstone object for all identifiers. */ struct tombstone_t { /** * @brief Converts the tombstone object to identifiers of any type. * @tparam Entity Type of identifier. * @return The tombstone representation for the given type. */ template [[nodiscard]] constexpr operator Entity() const noexcept { using traits_type = entt_traits; return traits_type::construct(traits_type::entity_mask, traits_type::version_mask); } /** * @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 noexcept { return true; } /** * @brief Compares a tombstone object and an identifier of any type. * @tparam Entity Type of identifier. * @param entity Identifier with which to compare. * @return False if the two elements differ, true otherwise. */ template [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { using traits_type = entt_traits; if constexpr(traits_type::version_mask == 0u) { return false; } else { return (traits_type::to_version(entity) == traits_type::to_version(*this)); } } }; /** * @brief Compile-time constant for null entities. * * There exist implicit conversions from this variable to identifiers of any * allowed type. Similarly, there exist comparison operators between the null * entity and any other identifier. */ inline constexpr null_t null{}; /** * @brief Compile-time constant for tombstone entities. * * There exist implicit conversions from this variable to identifiers of any * allowed type. Similarly, there exist comparison operators between the * tombstone entity and any other identifier. */ inline constexpr tombstone_t tombstone{}; } // namespace entt #endif // #include "entity/group.hpp" #ifndef ENTT_ENTITY_GROUP_HPP #define ENTT_ENTITY_GROUP_HPP // #include "../config/config.h" // #include "../core/algorithm.hpp" #ifndef ENTT_CORE_ALGORITHM_HPP #define ENTT_CORE_ALGORITHM_HPP // #include "../stl/algorithm.hpp" #ifndef ENTT_STL_ALGORITHM_HPP #define ENTT_STL_ALGORITHM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::all_of; using std::any_of; using std::find_if; using std::none_of; using std::sort; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Function object to wrap `stl::sort` in a class type. * * Unfortunately, `stl::sort` cannot be passed as template argument to a class * template or a function template.
* This class fills the gap by wrapping some flavors of `stl::sort` in a * function object. */ struct std_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given binary comparison function. * * @tparam Compare Type of comparison function object. * @tparam Args Types of arguments to forward to the sort function. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param compare A valid comparison function object. * @param args Arguments to forward to the sort function, if any. */ template, typename... Args> void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}, Args &&...args) const { stl::sort(stl::forward(args)..., stl::move(first), stl::move(last), stl::move(compare)); } }; /*! @brief Function object for performing insertion sort. */ struct insertion_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given binary comparison function. * * @tparam Compare Type of comparison function object. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param compare A valid comparison function object. */ template> void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}) const { if(first < last) { for(auto it = first + 1; it < last; ++it) { auto value = stl::move(*it); auto pre = it; // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; pre > first && compare(value, *(pre - 1)); --pre) { *pre = stl::move(*(pre - 1)); } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) *pre = stl::move(value); } } } }; /** * @brief Function object for performing LSD radix sort. * @tparam Bit Number of bits processed per pass. * @tparam N Maximum number of bits to sort. */ template requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass struct radix_sort { /** * @brief Sorts the elements in a range. * * Sorts the elements in a range using the given _getter_ to access the * actual data to be sorted. * * This implementation is inspired by the online book * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). * * @tparam It Type of random access iterator. * @tparam Getter Type of _getter_ function object. * @param first An iterator to the first element of the range to sort. * @param last An iterator past the last element of the range to sort. * @param getter A valid _getter_ function object. */ template void operator()(It first, It last, Getter getter = Getter{}) const { if(first < last) { constexpr auto passes = N / Bit; using value_type = stl::iterator_traits::value_type; using difference_type = stl::iterator_traits::difference_type; stl::vector aux(static_cast(stl::distance(first, last))); auto part = [getter = stl::move(getter)](auto from, auto to, auto out, auto start) { constexpr auto mask = (1 << Bit) - 1; constexpr auto buckets = 1 << Bit; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-const-correctness) stl::size_t count[buckets]{}; for(auto it = from; it != to; ++it) { ++count[(getter(*it) >> start) & mask]; } // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) stl::size_t index[buckets]{}; for(stl::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { index[pos + 1u] = index[pos] + count[pos]; } for(auto it = from; it != to; ++it) { const auto pos = index[(getter(*it) >> start) & mask]++; out[static_cast(pos)] = stl::move(*it); } }; for(stl::size_t pass = 0; pass < (passes & ~1u); pass += 2) { part(first, last, aux.begin(), pass * Bit); part(aux.begin(), aux.end(), first, (pass + 1) * Bit); } if constexpr(passes & 1) { part(first, last, aux.begin(), (passes - 1) * Bit); stl::move(aux.begin(), aux.end(), first); } } } }; } // namespace entt #endif // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" #ifndef ENTT_STL_STRING_VIEW_HPP #define ENTT_STL_STRING_VIEW_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string_view; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct fnv_1a_params; template<> struct fnv_1a_params { static constexpr auto offset = 2166136261; static constexpr auto prime = 16777619; }; template<> struct fnv_1a_params { static constexpr auto offset = 14695981039346656037ull; static constexpr auto prime = 1099511628211ull; }; template struct basic_hashed_string { using value_type = Char; using size_type = stl::size_t; using hash_type = id_type; const value_type *repr{}; hash_type hash{fnv_1a_params<>::offset}; size_type length{}; }; } // namespace internal /*! @endcond */ /** * @brief Zero overhead unique identifier. * * A hashed string is a compile-time tool that allows users to use * human-readable identifiers 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. * * @warning * This class doesn't take ownership of user-supplied strings nor does it make a * copy of them. * * @tparam Char Character type. */ template class basic_hashed_string: internal::basic_hashed_string { using base_type = internal::basic_hashed_string; using params = internal::fnv_1a_params<>; struct const_wrapper { // non-explicit constructor on purpose constexpr const_wrapper(const base_type::value_type *str) noexcept : repr{str} {} const base_type::value_type *repr; }; public: /*! @brief Character type. */ using value_type = base_type::value_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Unsigned integer type. */ using hash_type = base_type::hash_type; /** * @brief Returns directly the numeric representation of a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. * @return The numeric representation of the string. */ [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { return basic_hashed_string{str, len}; } /** * @brief Returns directly the numeric representation of a string. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. * @return The numeric representation of the string. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { return basic_hashed_string{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 constexpr hash_type value(const_wrapper wrapper) noexcept { return basic_hashed_string{wrapper}; } /*! @brief Constructs an empty hashed string. */ constexpr basic_hashed_string() noexcept : basic_hashed_string{nullptr, 0u} {} /** * @brief Constructs a hashed string from a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. */ constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; base_type::length < len; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Constructs a hashed string from an array of const characters. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { for(; str[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } } /** * @brief Explicit constructor on purpose to avoid constructing a hashed * string directly from a `const value_type *`. * * @warning * The lifetime of the string is not extended nor is it copied. * * @param wrapper Helps achieving the purpose by relying on overloading. */ explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept : base_type{wrapper.repr} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; wrapper.repr[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Returns the size of a hashed string. * @return The size of the hashed string. */ [[nodiscard]] constexpr size_type size() const noexcept { return base_type::length; } /** * @brief Returns the human-readable representation of a hashed string. * @return The string used to initialize the hashed string. */ [[nodiscard]] constexpr const value_type *data() const noexcept { return base_type::repr; } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr hash_type value() const noexcept { return base_type::hash; } /*! @copydoc data */ [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { return data(); } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr operator hash_type() const noexcept { return value(); } /** * @brief Compares two hashed strings. * @param other A valid hashed string. * @return True if the two hashed strings are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { return value() == other.value(); } /** * @brief Lexicographically compares two hashed strings. * @param other A valid hashed string. * @return The relative order between the two hashed strings. */ [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { return value() <=> other.value(); } }; /** * @brief Deduction guide. * @tparam Char Character type. * @param str Human-readable identifier. * @param len Length of the string to hash. */ template basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; /** * @brief Deduction guide. * @tparam Char Character type. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) basic_hashed_string(const Char (&str)[N]) -> 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]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { return hashed_string{str}; } /** * @brief User defined literal for hashed wstrings. * @param str The literal without its suffix. * @return A properly initialized hashed wstring. */ [[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { return hashed_wstring{str}; } } // namespace literals } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "../core/type_traits.hpp" // #include "../stl/array.hpp" #ifndef ENTT_STL_ARRAY_HPP #define ENTT_STL_ARRAY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::array; using std::get; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "entity.hpp" #ifndef ENTT_ENTITY_ENTITY_HPP #define ENTT_ENTITY_ENTITY_HPP // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../stl/bit.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "../stl/type_traits.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct entt_traits; template requires requires { requires stl::is_enum_v; typename internal::entt_traits>::value_type; } struct entt_traits: entt_traits> { using value_type = Type; }; template requires requires { typename Type::entity_type; } struct entt_traits : entt_traits { using value_type = Type; }; template<> struct entt_traits { using value_type = stl::uint32_t; using entity_type = stl::uint32_t; using version_type = stl::uint16_t; static constexpr entity_type entity_mask = 0xFFFFF; static constexpr entity_type version_mask = 0xFFF; }; template<> struct entt_traits { using value_type = stl::uint64_t; using entity_type = stl::uint64_t; using version_type = stl::uint32_t; static constexpr entity_type entity_mask = 0xFFFFFFFF; static constexpr entity_type version_mask = 0xFFFFFFFF; }; } // namespace internal /*! @endcond */ /** * @brief Specifies that a type is an entity-like type. * @tparam Type Type to check. */ template concept entity_like = requires { typename internal::entt_traits::value_type; }; /** * @brief Common basic entity traits implementation. * @tparam Traits Actual entity traits to use. */ template class basic_entt_traits { static constexpr auto length = stl::popcount(Traits::entity_mask); public: /*! @brief Value type. */ using value_type = Traits::value_type; /*! @brief Underlying entity type. */ using entity_type = Traits::entity_type; /*! @brief Underlying version type. */ using version_type = Traits::version_type; /*! @brief Entity mask size. */ static constexpr entity_type entity_mask = Traits::entity_mask; /*! @brief Version mask size */ static constexpr entity_type version_mask = Traits::version_mask; /** * @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) 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) noexcept { static_assert(Traits::entity_mask && ((Traits::entity_mask & (Traits::entity_mask + 1)) == 0), "Invalid entity mask"); return (to_integral(value) & 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) noexcept { if constexpr(Traits::version_mask == 0u) { return version_type{}; } else { static_assert((Traits::version_mask & (Traits::version_mask + 1)) == 0, "Invalid version mask"); return (static_cast(to_integral(value) >> length) & version_mask); } } /** * @brief Returns the successor of a given identifier. * @param value The identifier of which to return the successor. * @return The successor of the given identifier. */ [[nodiscard]] static constexpr value_type next(const value_type value) noexcept { const auto vers = to_version(value) + 1; return construct(to_integral(value), static_cast(vers + (vers == version_mask))); } /** * @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, const version_type version) noexcept { if constexpr(Traits::version_mask == 0u) { return value_type{entity & entity_mask}; } else { return value_type{(entity & entity_mask) | (static_cast(version & version_mask) << length)}; } } /** * @brief Combines two identifiers in a single one. * * The returned identifier is a copy of the first element except for its * version, which is taken from the second element. * * @param lhs The identifier from which to take the entity part. * @param rhs The identifier from which to take the version part. * @return A properly constructed identifier. */ [[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept { if constexpr(Traits::version_mask == 0u) { return value_type{lhs & entity_mask}; } else { return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))}; } } }; /** * @brief Entity traits. * @tparam Type Type of identifier. */ template struct entt_traits: basic_entt_traits> { /*! @brief Base type. */ using base_type = basic_entt_traits>; /*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */ static constexpr stl::size_t page_size = ENTT_SPARSE_PAGE; }; /** * @brief Converts an entity to its underlying type. * @tparam Entity The value type. * @param value The value to convert. * @return The integral representation of the given value. */ template [[nodiscard]] constexpr entt_traits::entity_type to_integral(const Entity value) noexcept { return entt_traits::to_integral(value); } /** * @brief Returns the entity part once converted to the underlying type. * @tparam Entity The value type. * @param value The value to convert. * @return The integral representation of the entity part. */ template [[nodiscard]] constexpr entt_traits::entity_type to_entity(const Entity value) noexcept { return entt_traits::to_entity(value); } /** * @brief Returns the version part once converted to the underlying type. * @tparam Entity The value type. * @param value The value to convert. * @return The integral representation of the version part. */ template [[nodiscard]] constexpr entt_traits::version_type to_version(const Entity value) noexcept { return entt_traits::to_version(value); } /*! @brief Null object for all identifiers. */ struct null_t { /** * @brief Converts the null object to identifiers of any type. * @tparam Entity Type of identifier. * @return The null representation for the given type. */ template [[nodiscard]] constexpr operator Entity() const noexcept { using traits_type = entt_traits; return traits_type::construct(traits_type::entity_mask, traits_type::version_mask); } /** * @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 noexcept { return true; } /** * @brief Compares a null object and an identifier of any type. * @tparam Entity Type of identifier. * @param entity Identifier with which to compare. * @return False if the two elements differ, true otherwise. */ template [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { using traits_type = entt_traits; return traits_type::to_entity(entity) == traits_type::to_entity(*this); } }; /*! @brief Tombstone object for all identifiers. */ struct tombstone_t { /** * @brief Converts the tombstone object to identifiers of any type. * @tparam Entity Type of identifier. * @return The tombstone representation for the given type. */ template [[nodiscard]] constexpr operator Entity() const noexcept { using traits_type = entt_traits; return traits_type::construct(traits_type::entity_mask, traits_type::version_mask); } /** * @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 noexcept { return true; } /** * @brief Compares a tombstone object and an identifier of any type. * @tparam Entity Type of identifier. * @param entity Identifier with which to compare. * @return False if the two elements differ, true otherwise. */ template [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { using traits_type = entt_traits; if constexpr(traits_type::version_mask == 0u) { return false; } else { return (traits_type::to_version(entity) == traits_type::to_version(*this)); } } }; /** * @brief Compile-time constant for null entities. * * There exist implicit conversions from this variable to identifiers of any * allowed type. Similarly, there exist comparison operators between the null * entity and any other identifier. */ inline constexpr null_t null{}; /** * @brief Compile-time constant for tombstone entities. * * There exist implicit conversions from this variable to identifiers of any * allowed type. Similarly, there exist comparison operators between the * tombstone entity and any other identifier. */ inline constexpr tombstone_t tombstone{}; } // namespace entt #endif // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class extended_group_iterator; template class extended_group_iterator, get_t> { template [[nodiscard]] auto index_to_element([[maybe_unused]] Type &cpool) const { if constexpr(stl::is_void_v) { return stl::make_tuple(); } else { return stl::forward_as_tuple(cpool.rbegin()[it.index()]); } } public: using iterator_type = It; using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::declval().get_as_tuple({})..., stl::declval().get_as_tuple({})...)); using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr extended_group_iterator() : it{}, pools{} {} extended_group_iterator(iterator_type from, stl::tuple cpools) : it{from}, pools{stl::move(cpools)} {} extended_group_iterator &operator++() noexcept { return ++it, *this; } extended_group_iterator operator++(int) noexcept { const extended_group_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] reference operator*() const noexcept { return stl::tuple_cat(stl::make_tuple(*it), index_to_element(*stl::get(pools))..., stl::get(pools)->get_as_tuple(*it)...); } [[nodiscard]] pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr iterator_type base() const noexcept { return it; } template [[nodiscard]] constexpr bool operator==(const extended_group_iterator &other) const noexcept { return it == other.it; } private: It it; stl::tuple pools; }; struct group_descriptor { using size_type = stl::size_t; virtual ~group_descriptor() = default; [[nodiscard]] virtual bool owned(const id_type) const noexcept { return false; } }; template class group_handler final: public group_descriptor { using entity_type = Type::entity_type; void swap_elements(const stl::size_t pos, const entity_type entt) { for(size_type next{}; next < Owned; ++next) { pools[next]->swap_elements((*pools[next])[pos], entt); } } void push_on_construct(const entity_type entt) { if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) { swap_elements(len++, entt); } } void push_on_destroy(const entity_type entt) { if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) { swap_elements(len++, entt); } } void remove_if(const entity_type entt) { if(pools[0u]->contains(entt) && (pools[0u]->index(entt) < len)) { swap_elements(--len, entt); } } void common_setup() { // we cannot iterate backwards because we want to leave behind valid entities in case of owned types for(auto first = pools[0u]->rbegin(), last = first + static_cast(pools[0u]->size()); first != last; ++first) { push_on_construct(*first); } } public: using common_type = Type; using size_type = Type::size_type; template group_handler(stl::tuple ogpool, stl::tuple epool) : pools{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, ogpool)}, filter{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, epool)} { stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool); stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool); common_setup(); } [[nodiscard]] bool owned(const id_type hash) const noexcept override { for(size_type pos{}; pos < Owned; ++pos) { if(pools[pos]->info().hash() == hash) { return true; } } return false; } [[nodiscard]] size_type length() const noexcept { return len; } template [[nodiscard]] common_type *storage() const noexcept { if constexpr(Index < (Owned + Get)) { return pools[Index]; } else { return filter[Index - (Owned + Get)]; } } private: stl::array pools; stl::array filter; stl::size_t len{}; }; template class group_handler final: public group_descriptor { using entity_type = Type::entity_type; void push_on_construct(const entity_type entt) { if(!elem.contains(entt) && stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) { elem.push(entt); } } void push_on_destroy(const entity_type entt) { if(!elem.contains(entt) && stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) { elem.push(entt); } } void remove_if(const entity_type entt) { elem.remove(entt); } void common_setup() { for(const auto entity: *pools[0u]) { push_on_construct(entity); } } public: using common_type = Type; template group_handler(const Allocator &allocator, stl::tuple gpool, stl::tuple epool) : pools{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, gpool)}, filter{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, epool)}, elem{allocator} { stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool); stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool); common_setup(); } [[nodiscard]] common_type &handle() noexcept { return elem; } [[nodiscard]] const common_type &handle() const noexcept { return elem; } template [[nodiscard]] common_type *storage() const noexcept { if constexpr(Index < Get) { return pools[Index]; } else { return filter[Index - Get]; } } private: stl::array pools; stl::array filter; common_type elem; }; } // namespace internal /*! @endcond */ /** * @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 are at * least in the given storage. Moreover, it's guaranteed that the entity list is * tightly packed in memory for fast iterations. * * @b Important * * Iterators aren't invalidated if: * * * New elements are added to the storage. * * The entity currently pointed is modified (for example, elements are added * or removed from it). * * The entity currently pointed is destroyed. * * In all other cases, modifying the pools iterated by the group in any way * invalidates all the iterators. * * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. */ template class basic_group, get_t, exclude_t> { using base_type = stl::common_type_t; using underlying_type = base_type::entity_type; template static constexpr stl::size_t index_of = type_list_index_v, type_list>; template [[nodiscard]] auto pools_for(stl::index_sequence) const noexcept { using return_type = stl::tuple; return descriptor ? return_type{static_cast(descriptor->template storage())...} : return_type{}; } public: /*! @brief Underlying entity identifier. */ using entity_type = underlying_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Common type among all storage types. */ using common_type = base_type; /*! @brief Random access iterator type. */ using iterator = common_type::iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = common_type::reverse_iterator; /*! @brief Iterable group type. */ using iterable = iterable_adaptor, get_t>>; /*! @brief Group handler type. */ using handler = internal::group_handler; /** * @brief Group opaque identifier. * @return Group opaque identifier. */ static id_type group_id() noexcept { return type_hash, get_t...>, exclude_t...>>>::value(); } /*! @brief Default constructor to use to create empty, invalid groups. */ basic_group() noexcept : descriptor{} {} /** * @brief Constructs a group from a set of storage classes. * @param ref A reference to a group handler. */ basic_group(handler &ref) noexcept : descriptor{&ref} {} /** * @brief Returns the leading storage of a group. * @return The leading storage of the group. */ [[nodiscard]] const common_type &handle() const noexcept { return descriptor->handle(); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { return storage>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { using type = type_list_element_t>; return *this ? static_cast(descriptor->template storage()) : nullptr; } /** * @brief Returns the number of entities that are part of the group. * @return Number of entities that are part of the group. */ [[nodiscard]] size_type size() const noexcept { return *this ? handle().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 noexcept { return *this ? handle().capacity() : size_type{}; } /*! @brief Requests the removal of unused capacity. */ void shrink_to_fit() { if(*this) { descriptor->handle().shrink_to_fit(); } } /** * @brief Checks whether a group is empty. * @return True if the group is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return !*this || handle().empty(); } /** * @brief Returns an iterator 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 noexcept { return *this ? handle().begin() : iterator{}; } /** * @brief Returns an iterator that is past the last entity of the group. * @return An iterator to the entity following the last entity of the * group. */ [[nodiscard]] iterator end() const noexcept { return *this ? handle().end() : iterator{}; } /** * @brief Returns an iterator 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 noexcept { return *this ? handle().rbegin() : reverse_iterator{}; } /** * @brief Returns an iterator that is past the last entity of the reversed * group. * @return An iterator to the entity following the last entity of the * reversed group. */ [[nodiscard]] reverse_iterator rend() const noexcept { return *this ? handle().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 noexcept { 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 noexcept { const auto it = rbegin(); return it != rend() ? *it : null; } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { return *this ? handle().find(entt) : iterator{}; } /** * @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()[static_cast(pos)]; } /** * @brief Checks if a group is properly initialized. * @return True if the group is properly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return descriptor != nullptr; } /** * @brief Checks if a group contains an entity. * @param entt A valid identifier. * @return True if the group contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { return *this && handle().contains(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Type Type of the element to get. * @tparam Other Other types of elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { return get, index_of...>(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Index Indexes of the elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { const auto cpools = pools_for(stl::index_sequence_for{}); if constexpr(sizeof...(Index) == 0) { return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools); } else if constexpr(sizeof...(Index) == 1) { return (stl::get(cpools)->get(entt), ...); } else { return stl::tuple_cat(stl::get(cpools)->get_as_tuple(entt)...); } } /** * @brief Iterates entities and elements 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 elements. The * _constness_ of the elements 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{}, stl::declval().get({})))>) { stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), get(entt))); } else { stl::apply(func, get(entt)); } } } /** * @brief Returns an iterable object to use to _visit_ a group. * * The iterable object returns tuples that contain the current entity and a * set of references to its non-empty elements. The _constness_ of the * elements 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 each() const noexcept { const auto cpools = pools_for(stl::index_sequence_for{}); return iterable{{begin(), cpools}, {end(), cpools}}; } /** * @brief Sort a group 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(stl::tuple, stl::tuple); * bool(const Type &..., const Type &...); * bool(const Entity, const Entity); * @endcode * * Where `Type` 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 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 Type Optional type of element to compare. * @tparam Other Other optional types of elements 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) { sort, index_of...>(stl::move(compare), stl::move(algo), stl::forward(args)...); } /** * @brief Sort a group according to the given comparison function. * * @sa sort * * @tparam Index Optional indexes of elements 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...(Index) == 0) { static_assert(stl::is_invocable_v, "Invalid comparison function"); descriptor->handle().sort(stl::move(compare), stl::move(algo), stl::forward(args)...); } else { auto comp = [&compare, cpools = pools_for(stl::index_sequence_for{})](const entity_type lhs, const entity_type rhs) { if constexpr(sizeof...(Index) == 1) { return compare((stl::get(cpools)->get(lhs), ...), (stl::get(cpools)->get(rhs), ...)); } else { return compare(stl::forward_as_tuple(stl::get(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get(cpools)->get(rhs)...)); } }; descriptor->handle().sort(stl::move(comp), stl::move(algo), stl::forward(args)...); } } } /** * @brief Sort entities according to their order in a range. * * The shared pool of entities and thus its order is affected by the changes * to each and every pool that it tracks. * * @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. */ void sort_as(stl::input_iterator auto first, stl::input_iterator auto last) const { if(*this) { descriptor->handle().sort_as(first, last); } } private: handler *descriptor; }; /** * @brief Owning group. * * Owning groups returns all entities and only the entities that are at * least in the given storage. Moreover: * * * It's guaranteed that the entity list is tightly packed in memory for fast * iterations. * * It's guaranteed that all elements in the owned storage are tightly packed * in memory for even faster iterations and to allow direct access. * * They stay true to the order of the owned storage and all instances have the * same order in memory. * * The more types of storage are owned, the faster it is to iterate a group. * * @b Important * * Iterators aren't invalidated if: * * * New elements are added to the storage. * * The entity currently pointed is modified (for example, elements are added * or removed from it). * * The entity currently pointed is destroyed. * * In all other cases, modifying the pools iterated by the group in any way * invalidates all the iterators. * * @tparam Owned Types of storage _owned_ by the group. * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. */ template class basic_group, get_t, exclude_t> { static_assert(((Owned::storage_policy != deletion_policy::in_place) && ...), "Groups do not support in-place delete"); using base_type = stl::common_type_t; using underlying_type = base_type::entity_type; template static constexpr stl::size_t index_of = type_list_index_v, type_list>; template [[nodiscard]] auto pools_for(stl::index_sequence, stl::index_sequence) const noexcept { using return_type = stl::tuple; return descriptor ? return_type{static_cast(descriptor->template storage())..., static_cast(descriptor->template storage())...} : return_type{}; } public: /*! @brief Underlying entity identifier. */ using entity_type = underlying_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Common type among all storage types. */ using common_type = base_type; /*! @brief Random access iterator type. */ using iterator = common_type::iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = common_type::reverse_iterator; /*! @brief Iterable group type. */ using iterable = iterable_adaptor, get_t>>; /*! @brief Group handler type. */ using handler = internal::group_handler; /** * @brief Group opaque identifier. * @return Group opaque identifier. */ static id_type group_id() noexcept { return type_hash...>, get_t...>, exclude_t...>>>::value(); } /*! @brief Default constructor to use to create empty, invalid groups. */ basic_group() noexcept : descriptor{} {} /** * @brief Constructs a group from a set of storage classes. * @param ref A reference to a group handler. */ basic_group(handler &ref) noexcept : descriptor{&ref} {} /** * @brief Returns the leading storage of a group. * @return The leading storage of the group. */ [[nodiscard]] const common_type &handle() const noexcept { return *storage<0>(); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { return storage>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { using type = type_list_element_t>; return *this ? static_cast(descriptor->template storage()) : nullptr; } /** * @brief Returns the number of entities that that are part of the group. * @return Number of entities that that are part of the group. */ [[nodiscard]] size_type size() const noexcept { return *this ? descriptor->length() : size_type{}; } /** * @brief Checks whether a group is empty. * @return True if the group is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return !*this || !descriptor->length(); } /** * @brief Returns an iterator 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 noexcept { return *this ? (handle().end() - static_cast(descriptor->length())) : iterator{}; } /** * @brief Returns an iterator that is past the last entity of the group. * @return An iterator to the entity following the last entity of the * group. */ [[nodiscard]] iterator end() const noexcept { return *this ? handle().end() : iterator{}; } /** * @brief Returns an iterator 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 noexcept { return *this ? handle().rbegin() : reverse_iterator{}; } /** * @brief Returns an iterator that is past the last entity of the reversed * group. * @return An iterator to the entity following the last entity of the * reversed group. */ [[nodiscard]] reverse_iterator rend() const noexcept { return *this ? (handle().rbegin() + static_cast(descriptor->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 noexcept { 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 noexcept { const auto it = rbegin(); return it != rend() ? *it : null; } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { const auto it = *this ? handle().find(entt) : iterator{}; return it >= begin() ? it : iterator{}; } /** * @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()[static_cast(pos)]; } /** * @brief Checks if a group is properly initialized. * @return True if the group is properly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return descriptor != nullptr; } /** * @brief Checks if a group contains an entity. * @param entt A valid identifier. * @return True if the group contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { return *this && handle().contains(entt) && (handle().index(entt) < (descriptor->length())); } /** * @brief Returns the elements assigned to the given entity. * @tparam Type Type of the element to get. * @tparam Other Other types of elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { return get, index_of...>(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Index Indexes of the elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); if constexpr(sizeof...(Index) == 0) { return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools); } else if constexpr(sizeof...(Index) == 1) { return (stl::get(cpools)->get(entt), ...); } else { return stl::tuple_cat(stl::get(cpools)->get_as_tuple(entt)...); } } /** * @brief Iterates entities and elements 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 elements. The * _constness_ of the elements 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{}, stl::declval().get({})))>) { stl::apply(func, args); } else { stl::apply([&func](auto, auto &&...less) { func(stl::forward(less)...); }, args); } } } /** * @brief Returns an iterable object to use to _visit_ a group. * * The iterable object returns tuples that contain the current entity and a * set of references to its non-empty elements. The _constness_ of the * elements 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 each() const noexcept { const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); return iterable{{begin(), cpools}, {end(), cpools}}; } /** * @brief Sort a group 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(stl::tuple, stl::tuple); * bool(const Type &, const Type &); * bool(const Entity, const Entity); * @endcode * * Where `Type` 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 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 Type Optional type of element to compare. * @tparam Other Other optional types of elements 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 { sort, index_of...>(stl::move(compare), stl::move(algo), stl::forward(args)...); } /** * @brief Sort a group according to the given comparison function. * * @sa sort * * @tparam Index Optional indexes of elements 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 { const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); if constexpr(sizeof...(Index) == 0) { static_assert(stl::is_invocable_v, "Invalid comparison function"); storage<0>()->sort_n(descriptor->length(), stl::move(compare), stl::move(algo), stl::forward(args)...); } else { auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) { if constexpr(sizeof...(Index) == 1) { return compare((stl::get(cpools)->get(lhs), ...), (stl::get(cpools)->get(rhs), ...)); } else { return compare(stl::forward_as_tuple(stl::get(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get(cpools)->get(rhs)...)); } }; storage<0>()->sort_n(descriptor->length(), stl::move(comp), stl::move(algo), stl::forward(args)...); } auto cb = [this](auto *head, auto *...other) { for(auto next = descriptor->length(); next; --next) { const auto pos = next - 1; [[maybe_unused]] const auto entt = head->data()[pos]; (other->swap_elements(other->data()[pos], entt), ...); } }; stl::apply(cb, cpools); } private: handler *descriptor; }; } // namespace entt #endif // #include "entity/handle.hpp" #ifndef ENTT_ENTITY_HANDLE_HPP #define ENTT_ENTITY_HANDLE_HPP // #include "../config/config.h" // #include "../core/iterator.hpp" // #include "../core/type_traits.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class handle_storage_iterator final { template friend class handle_storage_iterator; using underlying_type = stl::remove_reference_t; using entity_type = underlying_type::entity_type; public: using value_type = stl::iterator_traits::value_type; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr handle_storage_iterator() noexcept : entt{null}, it{}, last{} {} constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept : entt{value}, it{from}, last{to} { while(it != last && !it->second.contains(entt)) { ++it; } } constexpr handle_storage_iterator &operator++() noexcept { for(++it; it != last && !it->second.contains(entt); ++it) {} return *this; } constexpr handle_storage_iterator operator++(int) noexcept { const handle_storage_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr reference operator*() const noexcept { return *it; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } template [[nodiscard]] constexpr bool operator==(const handle_storage_iterator &other) const noexcept { return it == other.it; } private: entity_type entt; It it; It last; }; } // namespace internal /*! @endcond */ /** * @brief Non-owning handle to an entity. * * Tiny wrapper around a registry and an entity. * * @tparam Registry Basic registry type. * @tparam Scope Types to which to restrict the scope of a handle. */ template class basic_handle { using traits_type = entt_traits; [[nodiscard]] auto &owner_or_assert() const noexcept { ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); return static_cast(*owner); } public: /*! @brief Type of registry accepted by the handle. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = traits_type::value_type; /*! @brief Underlying version type. */ using version_type = traits_type::version_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Iterable handle type. */ using iterable = iterable_adaptor().storage())::iterator>>; /*! @brief Constructs an invalid handle. */ basic_handle() noexcept : owner{}, entt{null} {} /** * @brief Constructs a handle from a given registry and entity. * @param ref An instance of the registry class. * @param value A valid identifier. */ basic_handle(registry_type &ref, entity_type value) noexcept : owner{&ref}, entt{value} {} /** * @brief Returns an iterable object to use to _visit_ a handle. * * The iterable object returns a pair that contains the name and a reference * to the current storage.
* Returned storage are those that contain the entity associated with the * handle. * * @return An iterable object to use to _visit_ the handle. */ [[nodiscard]] iterable storage() const noexcept { auto underlying = owner_or_assert().storage(); return iterable{{entt, underlying.begin(), underlying.end()}, {entt, underlying.end(), underlying.end()}}; } /*! @copydoc valid */ [[nodiscard]] explicit operator bool() const noexcept { return owner && owner->valid(entt); } /** * @brief Checks if a handle refers to a valid registry and entity. * @return True if the handle refers to a valid registry and entity, false * otherwise. */ [[nodiscard]] bool valid() const { return static_cast(*this); } /** * @brief Returns a pointer to the underlying registry, if any. * @return A pointer to the underlying registry, if any. */ [[nodiscard]] registry_type *registry() const noexcept { return owner; } /** * @brief Returns the entity associated with a handle. * @return The entity associated with the handle. */ [[nodiscard]] entity_type entity() const noexcept { return entt; } /*! @copydoc entity */ [[nodiscard]] operator entity_type() const noexcept { return entity(); } /*! @brief Destroys the entity associated with a handle. */ void destroy() { owner_or_assert().destroy(stl::exchange(entt, null)); } /** * @brief Destroys the entity associated with a handle. * @param version A desired version upon destruction. */ void destroy(const version_type version) { owner_or_assert().destroy(stl::exchange(entt, null), version); } /** * @brief Assigns the given element to a handle. * @tparam Type Type of element to create. * @tparam Args Types of arguments to use to construct the element. * @param args Parameters to use to initialize the element. * @return A reference to the newly created element. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) decltype(auto) emplace(Args &&...args) const { static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); return owner_or_assert().template emplace(entt, stl::forward(args)...); } /** * @brief Assigns or replaces the given element for a handle. * @tparam Type Type of element to assign or replace. * @tparam Args Types of arguments to use to construct the element. * @param args Parameters to use to initialize the element. * @return A reference to the newly created element. */ template decltype(auto) emplace_or_replace(Args &&...args) const { static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); return owner_or_assert().template emplace_or_replace(entt, stl::forward(args)...); } /** * @brief Patches the given element for a handle. * @tparam Type Type of element to patch. * @tparam Func Types of the function objects to invoke. * @param func Valid function objects. * @return A reference to the patched element. */ template decltype(auto) patch(Func &&...func) const { static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); return owner_or_assert().template patch(entt, stl::forward(func)...); } /** * @brief Replaces the given element for a handle. * @tparam Type Type of element to replace. * @tparam Args Types of arguments to use to construct the element. * @param args Parameters to use to initialize the element. * @return A reference to the element being replaced. */ template decltype(auto) replace(Args &&...args) const { static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); return owner_or_assert().template replace(entt, stl::forward(args)...); } /** * @brief Removes the given elements from a handle. * @tparam Type Types of elements to remove. * @return The number of elements actually removed. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) size_type remove() const { static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); return owner_or_assert().template remove(entt); } /** * @brief Erases the given elements from a handle. * @tparam Type Types of elements to erase. */ template void erase() const { static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); owner_or_assert().template erase(entt); } /** * @brief Checks if a handle has all the given elements. * @tparam Type Elements for which to perform the check. * @return True if the handle has all the elements, false otherwise. */ template [[nodiscard]] decltype(auto) all_of() const { return owner_or_assert().template all_of(entt); } /** * @brief Checks if a handle has at least one of the given elements. * @tparam Type Elements for which to perform the check. * @return True if the handle has at least one of the given elements, * false otherwise. */ template [[nodiscard]] decltype(auto) any_of() const { return owner_or_assert().template any_of(entt); } /** * @brief Returns references to the given elements for a handle. * @tparam Type Types of elements to get. * @return References to the elements owned by the handle. */ template [[nodiscard]] decltype(auto) get() const { static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); return owner_or_assert().template get(entt); } /** * @brief Returns a reference to the given element for a handle. * @tparam Type Type of element to get. * @tparam Args Types of arguments to use to construct the element. * @param args Parameters to use to initialize the element. * @return Reference to the element owned by the handle. */ template [[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const { static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); return owner_or_assert().template get_or_emplace(entt, stl::forward(args)...); } /** * @brief Returns pointers to the given elements for a handle. * @tparam Type Types of elements to get. * @return Pointers to the elements owned by the handle. */ template [[nodiscard]] auto try_get() const { static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); return owner_or_assert().template try_get(entt); } /** * @brief Checks if a handle has elements assigned. * @return True if the handle has no elements assigned, false otherwise. */ [[nodiscard]] bool orphan() const { return owner_or_assert().orphan(entt); } /** * @brief Compares two handles. * @tparam Other Scope of the other handle. * @param other A valid handle. * @return True if both handles refer to the same registry and the same * entity, false otherwise. */ template [[nodiscard]] bool operator==(const basic_handle &other) const noexcept { return owner == other.registry() && entt == other.entity(); } /** * @brief Compares a handle with the null object. * @param other A null object yet to be converted. * @return False if the two elements differ, true otherwise. */ [[nodiscard]] constexpr bool operator==(const null_t other) const noexcept { return (entt == other); } /** * @brief Returns a const handle from a non-const one. * @tparam Other A valid entity type. * @tparam Args Scope of the handle to construct. * @return A const handle referring to the same registry and the same * entity. */ template operator basic_handle() const noexcept { static_assert(stl::is_same_v || stl::is_same_v, Registry>, "Invalid conversion between different handles"); static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v, Args>))), "Invalid conversion between different handles"); return owner ? basic_handle{*owner, entt} : basic_handle{}; } private: registry_type *owner; entity_type entt; }; } // namespace entt #endif // #include "entity/helper.hpp" #ifndef ENTT_ENTITY_HELPER_HPP #define ENTT_ENTITY_HELPER_HPP // #include "../core/fwd.hpp" // #include "../core/type_traits.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "component.hpp" #ifndef ENTT_ENTITY_COMPONENT_HPP #define ENTT_ENTITY_COMPONENT_HPP // #include "../config/config.h" // #include "../core/concepts.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/type_traits.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct in_place_delete: stl::bool_constant && stl::is_move_assignable_v)> {}; template<> struct in_place_delete: stl::false_type {}; template requires Type::in_place_delete struct in_place_delete: stl::true_type {}; template struct page_size: stl::integral_constant * ENTT_PACKED_PAGE> {}; template<> struct page_size: stl::integral_constant {}; template requires stl::is_convertible_v struct page_size: stl::integral_constant {}; } // namespace internal /*! @endcond */ /** * @brief Common way to access various properties of components. * @tparam Type Element type. * @tparam Entity A valid entity type. */ template struct component_traits { /*! @brief Element type. */ using element_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Pointer stability, default is `false`. */ static constexpr bool in_place_delete = internal::in_place_delete::value; /*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */ static constexpr stl::size_t page_size = internal::page_size::value; }; } // namespace entt #endif // #include "fwd.hpp" // #include "group.hpp" #ifndef ENTT_ENTITY_GROUP_HPP #define ENTT_ENTITY_GROUP_HPP // #include "../config/config.h" // #include "../core/algorithm.hpp" // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" // #include "../core/type_info.hpp" // #include "../core/type_traits.hpp" // #include "../stl/array.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class extended_group_iterator; template class extended_group_iterator, get_t> { template [[nodiscard]] auto index_to_element([[maybe_unused]] Type &cpool) const { if constexpr(stl::is_void_v) { return stl::make_tuple(); } else { return stl::forward_as_tuple(cpool.rbegin()[it.index()]); } } public: using iterator_type = It; using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::declval().get_as_tuple({})..., stl::declval().get_as_tuple({})...)); using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr extended_group_iterator() : it{}, pools{} {} extended_group_iterator(iterator_type from, stl::tuple cpools) : it{from}, pools{stl::move(cpools)} {} extended_group_iterator &operator++() noexcept { return ++it, *this; } extended_group_iterator operator++(int) noexcept { const extended_group_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] reference operator*() const noexcept { return stl::tuple_cat(stl::make_tuple(*it), index_to_element(*stl::get(pools))..., stl::get(pools)->get_as_tuple(*it)...); } [[nodiscard]] pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr iterator_type base() const noexcept { return it; } template [[nodiscard]] constexpr bool operator==(const extended_group_iterator &other) const noexcept { return it == other.it; } private: It it; stl::tuple pools; }; struct group_descriptor { using size_type = stl::size_t; virtual ~group_descriptor() = default; [[nodiscard]] virtual bool owned(const id_type) const noexcept { return false; } }; template class group_handler final: public group_descriptor { using entity_type = Type::entity_type; void swap_elements(const stl::size_t pos, const entity_type entt) { for(size_type next{}; next < Owned; ++next) { pools[next]->swap_elements((*pools[next])[pos], entt); } } void push_on_construct(const entity_type entt) { if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) { swap_elements(len++, entt); } } void push_on_destroy(const entity_type entt) { if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) { swap_elements(len++, entt); } } void remove_if(const entity_type entt) { if(pools[0u]->contains(entt) && (pools[0u]->index(entt) < len)) { swap_elements(--len, entt); } } void common_setup() { // we cannot iterate backwards because we want to leave behind valid entities in case of owned types for(auto first = pools[0u]->rbegin(), last = first + static_cast(pools[0u]->size()); first != last; ++first) { push_on_construct(*first); } } public: using common_type = Type; using size_type = Type::size_type; template group_handler(stl::tuple ogpool, stl::tuple epool) : pools{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, ogpool)}, filter{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, epool)} { stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool); stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool); common_setup(); } [[nodiscard]] bool owned(const id_type hash) const noexcept override { for(size_type pos{}; pos < Owned; ++pos) { if(pools[pos]->info().hash() == hash) { return true; } } return false; } [[nodiscard]] size_type length() const noexcept { return len; } template [[nodiscard]] common_type *storage() const noexcept { if constexpr(Index < (Owned + Get)) { return pools[Index]; } else { return filter[Index - (Owned + Get)]; } } private: stl::array pools; stl::array filter; stl::size_t len{}; }; template class group_handler final: public group_descriptor { using entity_type = Type::entity_type; void push_on_construct(const entity_type entt) { if(!elem.contains(entt) && stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) { elem.push(entt); } } void push_on_destroy(const entity_type entt) { if(!elem.contains(entt) && stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) && stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) { elem.push(entt); } } void remove_if(const entity_type entt) { elem.remove(entt); } void common_setup() { for(const auto entity: *pools[0u]) { push_on_construct(entity); } } public: using common_type = Type; template group_handler(const Allocator &allocator, stl::tuple gpool, stl::tuple epool) : pools{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, gpool)}, filter{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, epool)}, elem{allocator} { stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool); stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool); common_setup(); } [[nodiscard]] common_type &handle() noexcept { return elem; } [[nodiscard]] const common_type &handle() const noexcept { return elem; } template [[nodiscard]] common_type *storage() const noexcept { if constexpr(Index < Get) { return pools[Index]; } else { return filter[Index - Get]; } } private: stl::array pools; stl::array filter; common_type elem; }; } // namespace internal /*! @endcond */ /** * @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 are at * least in the given storage. Moreover, it's guaranteed that the entity list is * tightly packed in memory for fast iterations. * * @b Important * * Iterators aren't invalidated if: * * * New elements are added to the storage. * * The entity currently pointed is modified (for example, elements are added * or removed from it). * * The entity currently pointed is destroyed. * * In all other cases, modifying the pools iterated by the group in any way * invalidates all the iterators. * * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. */ template class basic_group, get_t, exclude_t> { using base_type = stl::common_type_t; using underlying_type = base_type::entity_type; template static constexpr stl::size_t index_of = type_list_index_v, type_list>; template [[nodiscard]] auto pools_for(stl::index_sequence) const noexcept { using return_type = stl::tuple; return descriptor ? return_type{static_cast(descriptor->template storage())...} : return_type{}; } public: /*! @brief Underlying entity identifier. */ using entity_type = underlying_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Common type among all storage types. */ using common_type = base_type; /*! @brief Random access iterator type. */ using iterator = common_type::iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = common_type::reverse_iterator; /*! @brief Iterable group type. */ using iterable = iterable_adaptor, get_t>>; /*! @brief Group handler type. */ using handler = internal::group_handler; /** * @brief Group opaque identifier. * @return Group opaque identifier. */ static id_type group_id() noexcept { return type_hash, get_t...>, exclude_t...>>>::value(); } /*! @brief Default constructor to use to create empty, invalid groups. */ basic_group() noexcept : descriptor{} {} /** * @brief Constructs a group from a set of storage classes. * @param ref A reference to a group handler. */ basic_group(handler &ref) noexcept : descriptor{&ref} {} /** * @brief Returns the leading storage of a group. * @return The leading storage of the group. */ [[nodiscard]] const common_type &handle() const noexcept { return descriptor->handle(); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { return storage>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { using type = type_list_element_t>; return *this ? static_cast(descriptor->template storage()) : nullptr; } /** * @brief Returns the number of entities that are part of the group. * @return Number of entities that are part of the group. */ [[nodiscard]] size_type size() const noexcept { return *this ? handle().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 noexcept { return *this ? handle().capacity() : size_type{}; } /*! @brief Requests the removal of unused capacity. */ void shrink_to_fit() { if(*this) { descriptor->handle().shrink_to_fit(); } } /** * @brief Checks whether a group is empty. * @return True if the group is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return !*this || handle().empty(); } /** * @brief Returns an iterator 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 noexcept { return *this ? handle().begin() : iterator{}; } /** * @brief Returns an iterator that is past the last entity of the group. * @return An iterator to the entity following the last entity of the * group. */ [[nodiscard]] iterator end() const noexcept { return *this ? handle().end() : iterator{}; } /** * @brief Returns an iterator 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 noexcept { return *this ? handle().rbegin() : reverse_iterator{}; } /** * @brief Returns an iterator that is past the last entity of the reversed * group. * @return An iterator to the entity following the last entity of the * reversed group. */ [[nodiscard]] reverse_iterator rend() const noexcept { return *this ? handle().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 noexcept { 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 noexcept { const auto it = rbegin(); return it != rend() ? *it : null; } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { return *this ? handle().find(entt) : iterator{}; } /** * @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()[static_cast(pos)]; } /** * @brief Checks if a group is properly initialized. * @return True if the group is properly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return descriptor != nullptr; } /** * @brief Checks if a group contains an entity. * @param entt A valid identifier. * @return True if the group contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { return *this && handle().contains(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Type Type of the element to get. * @tparam Other Other types of elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { return get, index_of...>(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Index Indexes of the elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { const auto cpools = pools_for(stl::index_sequence_for{}); if constexpr(sizeof...(Index) == 0) { return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools); } else if constexpr(sizeof...(Index) == 1) { return (stl::get(cpools)->get(entt), ...); } else { return stl::tuple_cat(stl::get(cpools)->get_as_tuple(entt)...); } } /** * @brief Iterates entities and elements 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 elements. The * _constness_ of the elements 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{}, stl::declval().get({})))>) { stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), get(entt))); } else { stl::apply(func, get(entt)); } } } /** * @brief Returns an iterable object to use to _visit_ a group. * * The iterable object returns tuples that contain the current entity and a * set of references to its non-empty elements. The _constness_ of the * elements 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 each() const noexcept { const auto cpools = pools_for(stl::index_sequence_for{}); return iterable{{begin(), cpools}, {end(), cpools}}; } /** * @brief Sort a group 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(stl::tuple, stl::tuple); * bool(const Type &..., const Type &...); * bool(const Entity, const Entity); * @endcode * * Where `Type` 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 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 Type Optional type of element to compare. * @tparam Other Other optional types of elements 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) { sort, index_of...>(stl::move(compare), stl::move(algo), stl::forward(args)...); } /** * @brief Sort a group according to the given comparison function. * * @sa sort * * @tparam Index Optional indexes of elements 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...(Index) == 0) { static_assert(stl::is_invocable_v, "Invalid comparison function"); descriptor->handle().sort(stl::move(compare), stl::move(algo), stl::forward(args)...); } else { auto comp = [&compare, cpools = pools_for(stl::index_sequence_for{})](const entity_type lhs, const entity_type rhs) { if constexpr(sizeof...(Index) == 1) { return compare((stl::get(cpools)->get(lhs), ...), (stl::get(cpools)->get(rhs), ...)); } else { return compare(stl::forward_as_tuple(stl::get(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get(cpools)->get(rhs)...)); } }; descriptor->handle().sort(stl::move(comp), stl::move(algo), stl::forward(args)...); } } } /** * @brief Sort entities according to their order in a range. * * The shared pool of entities and thus its order is affected by the changes * to each and every pool that it tracks. * * @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. */ void sort_as(stl::input_iterator auto first, stl::input_iterator auto last) const { if(*this) { descriptor->handle().sort_as(first, last); } } private: handler *descriptor; }; /** * @brief Owning group. * * Owning groups returns all entities and only the entities that are at * least in the given storage. Moreover: * * * It's guaranteed that the entity list is tightly packed in memory for fast * iterations. * * It's guaranteed that all elements in the owned storage are tightly packed * in memory for even faster iterations and to allow direct access. * * They stay true to the order of the owned storage and all instances have the * same order in memory. * * The more types of storage are owned, the faster it is to iterate a group. * * @b Important * * Iterators aren't invalidated if: * * * New elements are added to the storage. * * The entity currently pointed is modified (for example, elements are added * or removed from it). * * The entity currently pointed is destroyed. * * In all other cases, modifying the pools iterated by the group in any way * invalidates all the iterators. * * @tparam Owned Types of storage _owned_ by the group. * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. */ template class basic_group, get_t, exclude_t> { static_assert(((Owned::storage_policy != deletion_policy::in_place) && ...), "Groups do not support in-place delete"); using base_type = stl::common_type_t; using underlying_type = base_type::entity_type; template static constexpr stl::size_t index_of = type_list_index_v, type_list>; template [[nodiscard]] auto pools_for(stl::index_sequence, stl::index_sequence) const noexcept { using return_type = stl::tuple; return descriptor ? return_type{static_cast(descriptor->template storage())..., static_cast(descriptor->template storage())...} : return_type{}; } public: /*! @brief Underlying entity identifier. */ using entity_type = underlying_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Common type among all storage types. */ using common_type = base_type; /*! @brief Random access iterator type. */ using iterator = common_type::iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = common_type::reverse_iterator; /*! @brief Iterable group type. */ using iterable = iterable_adaptor, get_t>>; /*! @brief Group handler type. */ using handler = internal::group_handler; /** * @brief Group opaque identifier. * @return Group opaque identifier. */ static id_type group_id() noexcept { return type_hash...>, get_t...>, exclude_t...>>>::value(); } /*! @brief Default constructor to use to create empty, invalid groups. */ basic_group() noexcept : descriptor{} {} /** * @brief Constructs a group from a set of storage classes. * @param ref A reference to a group handler. */ basic_group(handler &ref) noexcept : descriptor{&ref} {} /** * @brief Returns the leading storage of a group. * @return The leading storage of the group. */ [[nodiscard]] const common_type &handle() const noexcept { return *storage<0>(); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { return storage>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { using type = type_list_element_t>; return *this ? static_cast(descriptor->template storage()) : nullptr; } /** * @brief Returns the number of entities that that are part of the group. * @return Number of entities that that are part of the group. */ [[nodiscard]] size_type size() const noexcept { return *this ? descriptor->length() : size_type{}; } /** * @brief Checks whether a group is empty. * @return True if the group is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return !*this || !descriptor->length(); } /** * @brief Returns an iterator 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 noexcept { return *this ? (handle().end() - static_cast(descriptor->length())) : iterator{}; } /** * @brief Returns an iterator that is past the last entity of the group. * @return An iterator to the entity following the last entity of the * group. */ [[nodiscard]] iterator end() const noexcept { return *this ? handle().end() : iterator{}; } /** * @brief Returns an iterator 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 noexcept { return *this ? handle().rbegin() : reverse_iterator{}; } /** * @brief Returns an iterator that is past the last entity of the reversed * group. * @return An iterator to the entity following the last entity of the * reversed group. */ [[nodiscard]] reverse_iterator rend() const noexcept { return *this ? (handle().rbegin() + static_cast(descriptor->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 noexcept { 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 noexcept { const auto it = rbegin(); return it != rend() ? *it : null; } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { const auto it = *this ? handle().find(entt) : iterator{}; return it >= begin() ? it : iterator{}; } /** * @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()[static_cast(pos)]; } /** * @brief Checks if a group is properly initialized. * @return True if the group is properly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return descriptor != nullptr; } /** * @brief Checks if a group contains an entity. * @param entt A valid identifier. * @return True if the group contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { return *this && handle().contains(entt) && (handle().index(entt) < (descriptor->length())); } /** * @brief Returns the elements assigned to the given entity. * @tparam Type Type of the element to get. * @tparam Other Other types of elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { return get, index_of...>(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Index Indexes of the elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); if constexpr(sizeof...(Index) == 0) { return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools); } else if constexpr(sizeof...(Index) == 1) { return (stl::get(cpools)->get(entt), ...); } else { return stl::tuple_cat(stl::get(cpools)->get_as_tuple(entt)...); } } /** * @brief Iterates entities and elements 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 elements. The * _constness_ of the elements 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{}, stl::declval().get({})))>) { stl::apply(func, args); } else { stl::apply([&func](auto, auto &&...less) { func(stl::forward(less)...); }, args); } } } /** * @brief Returns an iterable object to use to _visit_ a group. * * The iterable object returns tuples that contain the current entity and a * set of references to its non-empty elements. The _constness_ of the * elements 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 each() const noexcept { const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); return iterable{{begin(), cpools}, {end(), cpools}}; } /** * @brief Sort a group 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(stl::tuple, stl::tuple); * bool(const Type &, const Type &); * bool(const Entity, const Entity); * @endcode * * Where `Type` 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 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 Type Optional type of element to compare. * @tparam Other Other optional types of elements 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 { sort, index_of...>(stl::move(compare), stl::move(algo), stl::forward(args)...); } /** * @brief Sort a group according to the given comparison function. * * @sa sort * * @tparam Index Optional indexes of elements 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 { const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); if constexpr(sizeof...(Index) == 0) { static_assert(stl::is_invocable_v, "Invalid comparison function"); storage<0>()->sort_n(descriptor->length(), stl::move(compare), stl::move(algo), stl::forward(args)...); } else { auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) { if constexpr(sizeof...(Index) == 1) { return compare((stl::get(cpools)->get(lhs), ...), (stl::get(cpools)->get(rhs), ...)); } else { return compare(stl::forward_as_tuple(stl::get(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get(cpools)->get(rhs)...)); } }; storage<0>()->sort_n(descriptor->length(), stl::move(comp), stl::move(algo), stl::forward(args)...); } auto cb = [this](auto *head, auto *...other) { for(auto next = descriptor->length(); next; --next) { const auto pos = next - 1; [[maybe_unused]] const auto entt = head->data()[pos]; (other->swap_elements(other->data()[pos], entt), ...); } }; stl::apply(cb, cpools); } private: handler *descriptor; }; } // namespace entt #endif // #include "storage.hpp" #ifndef ENTT_ENTITY_STORAGE_HPP #define ENTT_ENTITY_STORAGE_HPP #include // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../core/iterator.hpp" // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_info.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "component.hpp" // #include "entity.hpp" // #include "fwd.hpp" // #include "sparse_set.hpp" #ifndef ENTT_ENTITY_SPARSE_SET_HPP #define ENTT_ENTITY_SPARSE_SET_HPP #include // #include "../config/config.h" // #include "../core/algorithm.hpp" // #include "../core/any.hpp" #ifndef ENTT_CORE_ANY_HPP #define ENTT_CORE_ANY_HPP // #include "../config/config.h" // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @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) 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) 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. */ constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) : func{stl::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 constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } private: Func func; }; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { enum class any_request : stl::uint8_t { info, transfer, assign, compare, copy, move }; template struct basic_any_storage { static constexpr bool has_buffer = true; union { const void *instance{}; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) alignas(Align) stl::byte buffer[Len]; }; }; template struct basic_any_storage<0u, Align> { static constexpr bool has_buffer = false; const void *instance{}; }; template // NOLINTNEXTLINE(bugprone-sizeof-expression) struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v> {}; template struct in_situ: stl::false_type {}; } // namespace internal /*! @endcond */ /** * @brief A SBO friendly, type-safe container for single values of any type. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Optional alignment requirement. */ template class basic_any: private internal::basic_any_storage { using request = internal::any_request; using base_type = internal::basic_any_storage; using vtable_type = const void *(const request, const basic_any &, const void *); using deleter_type = void(const basic_any &); template static constexpr bool in_situ_v = internal::in_situ::value; template static const void *basic_vtable(const request req, const basic_any &value, const void *other) { switch(const auto *elem = static_cast(value.data()); req) { using enum internal::any_request; case info: return &type_id(); case transfer: if constexpr(stl::is_move_assignable_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) *const_cast(elem) = stl::move(*static_cast(const_cast(other))); return other; } [[fallthrough]]; case assign: if constexpr(stl::is_copy_assignable_v) { *const_cast(elem) = *static_cast(other); return other; } break; case compare: if constexpr(!stl::is_function_v && !stl::is_array_v && is_equality_comparable_v) { return (*elem == *static_cast(other)) ? other : nullptr; } else { return (elem == other) ? other : nullptr; } case copy: if constexpr(stl::is_copy_constructible_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) static_cast(const_cast(other))->initialize(*elem); } break; case move: ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy"); if constexpr(in_situ_v) { // NOLINTNEXTLINE(bugprone-casting-through-void, bugprone-multi-level-implicit-pointer-conversion) return ::new(&static_cast(const_cast(other))->buffer) Type{stl::move(*const_cast(elem))}; } } return nullptr; } template static void basic_deleter(const basic_any &value) { ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::is_trivially_destructible_v), "Unexpected policy"); const auto *elem = static_cast(value.data()); if constexpr(in_situ_v) { (value.mode == any_policy::embedded) ? elem->~Type() : (delete elem); } else if constexpr(stl::is_array_v) { delete[] elem; } else { delete elem; } } template void initialize([[maybe_unused]] Args &&...args) { using plain_type = stl::remove_cvref_t; vtable = basic_vtable; underlying_type = type_hash::value(); if constexpr(stl::is_void_v) { deleter = nullptr; mode = any_policy::empty; this->instance = nullptr; } else if constexpr(stl::is_lvalue_reference_v) { deleter = nullptr; mode = stl::is_const_v> ? any_policy::cref : any_policy::ref; static_assert((stl::is_lvalue_reference_v && ...) && (sizeof...(Args) == 1u), "Invalid arguments"); // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) this->instance = (stl::addressof(args), ...); } else if constexpr(in_situ_v) { if constexpr(stl::is_trivially_destructible_v) { deleter = nullptr; } else { deleter = &basic_deleter; } mode = any_policy::embedded; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { ::new(&this->buffer) plain_type{stl::forward(args)...}; } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) ::new(&this->buffer) plain_type(stl::forward(args)...); } } else { deleter = &basic_deleter; mode = any_policy::dynamic; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { this->instance = new plain_type{stl::forward(args)...}; } else if constexpr(stl::is_array_v) { static_assert(sizeof...(Args) == 0u, "Invalid arguments"); this->instance = new plain_type[stl::extent_v](); } else { this->instance = new plain_type(stl::forward(args)...); } } } void invoke_deleter_if_exists() { if(deleter != nullptr) { deleter(*this); } } public: /*! @brief Size of the internal buffer. */ static constexpr auto length = Len; /*! @brief Alignment requirement. */ static constexpr auto alignment = Align; /*! @brief Default constructor. */ constexpr basic_any() noexcept : basic_any{stl::in_place_type} {} /** * @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(stl::in_place_type_t, Args &&...args) : base_type{} { initialize(stl::forward(args)...); } /** * @brief Constructs a wrapper taking ownership of the passed object. * @tparam Type Type of object to use to initialize the wrapper. * @param value A pointer to an object to take ownership of. */ template requires (!stl::is_const_v && !stl::is_void_v) explicit basic_any(stl::in_place_t, Type *value) : base_type{} { if(value == nullptr) { initialize(); } else { initialize(*value); deleter = &basic_deleter; mode = any_policy::dynamic; } } /** * @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 requires (!stl::same_as, basic_any>) basic_any(Type &&value) : basic_any{stl::in_place_type>, stl::forward(value)} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ basic_any(const basic_any &other) : basic_any{} { other.vtable(request::copy, other, this); } /** * @brief Move constructor. * @param other The instance to move from. */ basic_any(basic_any &&other) noexcept : base_type{}, vtable{other.vtable}, deleter{other.deleter}, underlying_type{other.underlying_type}, mode{other.mode} { if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } } /*! @brief Frees the internal buffer, whatever it means. */ ~basic_any() { invoke_deleter_if_exists(); } /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This any object. */ basic_any &operator=(const basic_any &other) { if(this != &other) { invoke_deleter_if_exists(); if(other) { other.vtable(request::copy, other, this); } else { initialize(); } } return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This any object. */ basic_any &operator=(basic_any &&other) noexcept { if(this != &other) { invoke_deleter_if_exists(); if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } vtable = other.vtable; deleter = other.deleter; underlying_type = other.underlying_type; 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 requires (!stl::same_as, basic_any>) basic_any &operator=(Type &&value) { emplace>(stl::forward(value)); return *this; } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] bool has_value() const noexcept { return (mode != any_policy::empty); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @param req Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ [[nodiscard]] bool has_value(const type_info &req) const noexcept { return (underlying_type == req.hash()); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @tparam Type Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ template [[nodiscard]] bool has_value() const noexcept { return (underlying_type == type_hash::value()); } /** * @brief Returns the object type info if any, `type_id()` otherwise. * @return The object type info if any, `type_id()` otherwise. */ [[nodiscard]] const type_info &info() const noexcept { return *static_cast(vtable(request::info, *this, nullptr)); } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data() const noexcept { if constexpr(base_type::has_buffer) { return (mode == any_policy::embedded) ? &this->buffer : this->instance; } else { return this->instance; } } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data(const type_info &req) const noexcept { return has_value(req) ? data() : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] const Type *data() const noexcept { return has_value>() ? static_cast(data()) : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data() noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data()); } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data(const type_info &req) noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data(req)); } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] Type *data() noexcept { if constexpr(stl::is_const_v) { return stl::as_const(*this).template data>(); } else { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).template data>()); } } /** * @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) { invoke_deleter_if_exists(); initialize(stl::forward(args)...); } /** * @brief Assigns a value to the contained object without replacing it. * @param other The value to assign to the contained object. * @return True in case of success, false otherwise. */ bool assign(const basic_any &other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (vtable(request::assign, *this, other.data()) != nullptr); } return false; } /*! @copydoc assign */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) bool assign(basic_any &&other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (other.mode == any_policy::cref) ? (vtable(request::assign, *this, stl::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr); } return false; } /*! @brief Destroys contained object */ void reset() { invoke_deleter_if_exists(); initialize(); } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return has_value(); } /** * @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 basic_any &other) const noexcept { if(other && (underlying_type == other.underlying_type)) { return (vtable(request::compare, *this, other.data()) != nullptr); } return (!*this && !other); } /** * @brief Aliasing constructor. * @return A wrapper that shares a reference to an unmanaged object. */ [[nodiscard]] basic_any as_ref() noexcept { basic_any other = stl::as_const(*this).as_ref(); switch(mode) { using enum any_policy; case cref: case empty: other.mode = mode; break; default: other.mode = any_policy::ref; break; } return other; } /*! @copydoc as_ref */ [[nodiscard]] basic_any as_ref() const noexcept { basic_any other{}; other.instance = data(); other.vtable = vtable; other.underlying_type = underlying_type; other.mode = any_policy::cref; return other; } /** * @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 noexcept { return (mode == any_policy::dynamic || mode == any_policy::embedded); } /** * @brief Returns the current mode of an any object. * @return The current mode of the any object. */ [[nodiscard]] any_policy policy() const noexcept { return mode; } private: vtable_type *vtable{}; deleter_type *deleter{}; id_type underlying_type{}; any_policy mode{}; }; /** * @brief Performs type-safe access to the contained object. * @tparam Type Type to which conversion is required. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Alignment requirement. * @param data Target any object. * @return The element converted to the requested type. */ template [[nodiscard]] stl::remove_const_t any_cast(const basic_any &data) noexcept { const auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(*instance); } /*! @copydoc any_cast */ template [[nodiscard]] stl::remove_const_t any_cast(basic_any &data) 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 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) [[nodiscard]] stl::remove_const_t any_cast(basic_any &&data) noexcept { if constexpr(stl::is_copy_constructible_v>) { if(auto *const instance = any_cast>(&data); instance) { return static_cast(stl::move(*instance)); } return any_cast(data); } else { auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(stl::move(*instance)); } } /*! @copydoc any_cast */ template [[nodiscard]] const Type *any_cast(const basic_any *data) noexcept { return data->template data>(); } /*! @copydoc any_cast */ template [[nodiscard]] Type *any_cast(basic_any *data) noexcept { if constexpr(stl::is_const_v) { // last attempt to make wrappers for const references return their values return any_cast(&stl::as_const(*data)); } else { return data->template data(); } } /** * @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 buffer 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, stl::size_t Align = basic_any::alignment, typename... Args> [[nodiscard]] basic_any make_any(Args &&...args) { return basic_any{stl::in_place_type, stl::forward(args)...}; } /** * @brief Forwards its argument and avoids copies for lvalue references. * @tparam Len Size of the buffer 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, stl::size_t Align = basic_any::alignment, typename Type> [[nodiscard]] basic_any forward_as_any(Type &&value) { return basic_any{stl::in_place_type, stl::forward(value)}; } } // namespace entt #endif // #include "../core/bit.hpp" // #include "../core/type_info.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct sparse_set_iterator final { using value_type = Container::value_type; using pointer = Container::const_pointer; using reference = Container::const_reference; using difference_type = Container::difference_type; using iterator_category = stl::random_access_iterator_tag; constexpr sparse_set_iterator() noexcept : packed{}, offset{} {} constexpr sparse_set_iterator(const Container &ref, const difference_type idx) noexcept : packed{&ref}, offset{idx} {} constexpr sparse_set_iterator &operator++() noexcept { return --offset, *this; } constexpr sparse_set_iterator operator++(int) noexcept { const sparse_set_iterator orig = *this; return ++(*this), orig; } constexpr sparse_set_iterator &operator--() noexcept { return ++offset, *this; } constexpr sparse_set_iterator operator--(int) noexcept { const sparse_set_iterator orig = *this; return operator--(), orig; } constexpr sparse_set_iterator &operator+=(const difference_type value) noexcept { offset -= value; return *this; } constexpr sparse_set_iterator operator+(const difference_type value) const noexcept { sparse_set_iterator copy = *this; return (copy += value); } constexpr sparse_set_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr sparse_set_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return (*packed)[static_cast(index() - value)]; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(operator[](0)); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } [[nodiscard]] constexpr stl::ptrdiff_t operator-(const sparse_set_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset - offset; } [[nodiscard]] constexpr bool operator==(const sparse_set_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr auto operator<=>(const sparse_set_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset <=> offset; } [[nodiscard]] constexpr pointer data() const noexcept { return packed ? packed->data() : nullptr; } [[nodiscard]] constexpr difference_type index() const noexcept { return offset - 1; } private: const Container *packed; difference_type offset; }; } // namespace internal /*! @endcond */ /** * @brief 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 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_sparse_set { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector; using traits_type = entt_traits; static constexpr auto max_size = static_cast(traits_type::to_entity(null)); // it could be auto but gcc complains and emits a warning due to a false positive [[nodiscard]] stl::size_t policy_to_head() const noexcept { return static_cast(max_size * static_cast>(mode != deletion_policy::swap_only)); } [[nodiscard]] auto entity_to_pos(const Entity entt) const noexcept { return static_cast(traits_type::to_entity(entt)); } [[nodiscard]] auto pos_to_page(const stl::size_t pos) const noexcept { return static_cast(pos / traits_type::page_size); } [[nodiscard]] auto sparse_ptr(const Entity entt) const { const auto pos = entity_to_pos(entt); const auto page = pos_to_page(pos); return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, traits_type::page_size)) : nullptr; } [[nodiscard]] auto &sparse_ref(const Entity entt) const { ENTT_ASSERT(sparse_ptr(entt), "Invalid element"); const auto pos = entity_to_pos(entt); return sparse[pos_to_page(pos)][fast_mod(pos, traits_type::page_size)]; } [[nodiscard]] auto to_iterator(const Entity entt) const { return --(end() - static_cast(index(entt))); } [[nodiscard]] auto &assure_at_least(const Entity entt) { const auto pos = entity_to_pos(entt); const auto page = pos_to_page(pos); if(!(page < sparse.size())) { sparse.resize(page + 1u, nullptr); } if(!sparse[page]) { constexpr entity_type init = null; auto page_allocator{packed.get_allocator()}; sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size); stl::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init); } return sparse[page][fast_mod(pos, traits_type::page_size)]; } void release_sparse_pages() { for(auto page_allocator{packed.get_allocator()}; auto &&page: sparse) { if(page != nullptr) { stl::destroy(page, page + traits_type::page_size); alloc_traits::deallocate(page_allocator, page, traits_type::page_size); page = nullptr; } } } void swap_at(const stl::size_t lhs, const stl::size_t rhs) { auto &from = packed[lhs]; auto &to = packed[rhs]; sparse_ref(from) = traits_type::combine(static_cast(rhs), traits_type::to_integral(from)); sparse_ref(to) = traits_type::combine(static_cast(lhs), traits_type::to_integral(to)); stl::swap(from, to); } private: [[nodiscard]] virtual const void *get_at(const stl::size_t) const { return nullptr; } virtual void swap_or_move([[maybe_unused]] const stl::size_t lhs, [[maybe_unused]] const stl::size_t rhs) { ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < head) == (rhs < head)), "Cross swapping is not supported"); } protected: /*! @brief Random access iterator type. */ using basic_iterator = internal::sparse_set_iterator; /** * @brief Erases an entity from a sparse set. * @param entt A valid identifier for the element to pop. */ void swap_only(const Entity entt) { ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch"); const auto pos = index(entt); bump(traits_type::next(entt)); swap_at(pos, head -= (pos < head)); } /** * @brief Erases an entity from a sparse set. * @param entt A valid identifier for the element to pop. */ void swap_and_pop(const Entity entt) { ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatch"); auto &self = sparse_ref(entt); const auto pos = traits_type::to_entity(self); sparse_ref(packed.back()) = traits_type::combine(pos, traits_type::to_integral(packed.back())); packed[static_cast(pos)] = packed.back(); // unnecessary but it helps to detect nasty bugs // NOLINTNEXTLINE(bugprone-assert-side-effect) ENTT_ASSERT((packed.back() = null, true), ""); // lazy self-assignment guard self = null; packed.pop_back(); } /** * @brief Erases an entity from a sparse set. * @param entt A valid identifier for the element to pop. */ void in_place_pop(const Entity entt) { ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch"); const auto pos = entity_to_pos(stl::exchange(sparse_ref(entt), null)); packed[pos] = traits_type::combine(static_cast(stl::exchange(head, pos)), tombstone); } /** * @brief Erases entities from a sparse set. * @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. */ virtual void pop(basic_iterator first, basic_iterator last) { switch(mode) { case deletion_policy::swap_and_pop: for(; first != last; ++first) { swap_and_pop(*first); } break; case deletion_policy::in_place: for(; first != last; ++first) { in_place_pop(*first); } break; case deletion_policy::swap_only: for(; first != last; ++first) { swap_only(*first); } break; } } /*! @brief Erases all entities of a sparse set. */ virtual void pop_all() { if(!packed.empty()) { // suboptimal with few entities, but exploits cache way more with many for(auto &&elem: sparse) { if(elem) { for(size_type pos{}; pos < traits_type::page_size; ++pos) { elem[pos] = null; } } } } head = policy_to_head(); packed.clear(); } /** * @brief Assigns an entity to a sparse set. * @param entt A valid identifier. * @param force_back Force back insertion. * @return Iterator pointing to the emplaced element. */ virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) { ENTT_ASSERT(entt != null && entt != tombstone, "Invalid element"); auto &elem = assure_at_least(entt); auto pos = size(); switch(mode) { case deletion_policy::in_place: if(head != max_size && !force_back) { pos = head; ENTT_ASSERT(elem == null, "Slot not available"); elem = traits_type::combine(static_cast(head), traits_type::to_integral(entt)); head = entity_to_pos(stl::exchange(packed[pos], entt)); break; } [[fallthrough]]; case deletion_policy::swap_and_pop: packed.push_back(entt); ENTT_ASSERT(elem == null, "Slot not available"); elem = traits_type::combine(static_cast(packed.size() - 1u), traits_type::to_integral(entt)); break; case deletion_policy::swap_only: if(elem == null) { packed.push_back(entt); elem = traits_type::combine(static_cast(packed.size() - 1u), traits_type::to_integral(entt)); } else { ENTT_ASSERT(!(entity_to_pos(elem) < head), "Slot not available"); bump(entt); } pos = head++; swap_at(entity_to_pos(elem), pos); break; } return iterator{packed, static_cast(++pos)}; } /*! @brief Forwards variables to derived classes, if any. */ // NOLINTNEXTLINE(performance-unnecessary-value-param) virtual void bind_any(any) noexcept {} public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Underlying entity identifier. */ using entity_type = traits_type::value_type; /*! @brief Underlying version type. */ using version_type = traits_type::version_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Pointer type to contained entities. */ using pointer = packed_container_type::const_pointer; /*! @brief Random access iterator type. */ using iterator = basic_iterator; /*! @brief Constant random access iterator type. */ using const_iterator = iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = stl::reverse_iterator; /*! @brief Default constructor. */ basic_sparse_set() : basic_sparse_set{type_id()} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit basic_sparse_set(const allocator_type &allocator) : basic_sparse_set{deletion_policy::swap_and_pop, allocator} {} /** * @brief Constructs an empty container with the given policy and allocator. * @param pol Type of deletion policy. * @param allocator The allocator to use (possibly default-constructed). */ explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {}) : basic_sparse_set{type_id(), pol, allocator} {} /** * @brief Constructs an empty container with the given value type, policy * and allocator. * @param elem Returned value type, if any. * @param pol Type of deletion policy. * @param allocator The allocator to use (possibly default-constructed). */ explicit basic_sparse_set(const type_info &elem, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {}) : sparse{allocator}, packed{allocator}, descriptor{&elem}, mode{pol}, head{policy_to_head()} { ENTT_ASSERT(traits_type::version_mask || mode != deletion_policy::in_place, "Policy does not support zero-sized versions"); } /*! @brief Default copy constructor, deleted on purpose. */ basic_sparse_set(const basic_sparse_set &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_sparse_set(basic_sparse_set &&other) noexcept : sparse{stl::move(other.sparse)}, packed{stl::move(other.packed)}, descriptor{other.descriptor}, mode{other.mode}, head{stl::exchange(other.head, policy_to_head())} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) : sparse{stl::move(other.sparse), allocator}, packed{stl::move(other.packed), allocator}, descriptor{other.descriptor}, mode{other.mode}, head{stl::exchange(other.head, policy_to_head())} { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed"); } /*! @brief Default destructor. */ virtual ~basic_sparse_set() { release_sparse_pages(); } /** * @brief Default copy assignment operator, deleted on purpose. * @return This sparse set. */ basic_sparse_set &operator=(const basic_sparse_set &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This sparse set. */ basic_sparse_set &operator=(basic_sparse_set &&other) noexcept { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed"); swap(other); return *this; } /** * @brief Exchanges the contents with those of a given sparse set. * @param other Sparse set to exchange the content with. */ void swap(basic_sparse_set &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(descriptor, other.descriptor); swap(mode, other.mode); swap(head, other.head); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return packed.get_allocator(); } /** * @brief Returns the deletion policy of a sparse set. * @return The deletion policy of the sparse set. */ [[nodiscard]] deletion_policy policy() const noexcept { return mode; } /** * @brief Returns data on the free list whose meaning depends on the mode. * @return Free list information that is mode dependent. */ [[nodiscard]] size_type free_list() const noexcept { return head; } /** * @brief Sets data on the free list whose meaning depends on the mode. * @param value Free list information that is mode dependent. */ void free_list(const size_type value) noexcept { ENTT_ASSERT((mode == deletion_policy::swap_only) && !(value > packed.size()), "Invalid value"); head = value; } /** * @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. */ virtual void reserve(const size_type cap) { packed.reserve(cap); } /** * @brief Returns the number of elements that a sparse set has currently * allocated space for. * @return Capacity of the sparse set. */ [[nodiscard]] virtual size_type capacity() const noexcept { return packed.capacity(); } /*! @brief Requests the removal of unused capacity. */ virtual void shrink_to_fit() { sparse_container_type other{sparse.get_allocator()}; const auto len = sparse.size(); other.reserve(len); for(size_type cnt{}; auto &&elem: stl::as_const(packed)) { if(elem != tombstone) { if(const auto page = pos_to_page(entity_to_pos(elem)); sparse[page] != nullptr) { if(const auto sz = page + 1u; sz > other.size()) { other.resize(sz, nullptr); } other[page] = stl::exchange(sparse[page], nullptr); if(++cnt == len) { // early exit due to lack of pages break; } } } } release_sparse_pages(); sparse.swap(other); 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 all pages have been allocated, nor that the * internal packed array is be the same size. * * @return Extent of the sparse set. */ [[nodiscard]] size_type extent() const noexcept { return sparse.size() * traits_type::page_size; } /** * @brief Returns the number of elements in a sparse set. * * The number of elements is also the size of the internal packed array. * There is no guarantee that the internal sparse array has the same size. * Usually the size of the internal sparse array is equal or greater than * the one of the internal packed array. * * @return Number of elements. */ [[nodiscard]] size_type size() const noexcept { return packed.size(); } /** * @brief Checks whether a sparse set is empty. * @return True if the sparse set is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.empty(); } /** * @brief Checks whether a sparse set is fully packed. * @return True if the sparse set is fully packed, false otherwise. */ [[nodiscard]] bool contiguous() const noexcept { return (mode != deletion_policy::in_place) || (head == max_size); } /** * @brief Direct access to the internal packed array. * @return A pointer to the internal packed array. */ [[nodiscard]] pointer data() const noexcept { return packed.data(); } /** * @brief Returns an iterator to the beginning. * * If the sparse set is empty, the returned iterator will be equal to * `end()`. * * @return An iterator to the first entity of the sparse set. */ [[nodiscard]] iterator begin() const noexcept { const auto pos = static_cast(packed.size()); return iterator{packed, pos}; } /*! @copydoc begin */ [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last entity of a sparse * set. */ [[nodiscard]] iterator end() const noexcept { return iterator{packed, {}}; } /*! @copydoc end */ [[nodiscard]] const_iterator cend() const noexcept { return end(); } /** * @brief Returns a reverse iterator to the beginning. * * 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 noexcept { return stl::make_reverse_iterator(end()); } /*! @copydoc rbegin */ [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last entity of the * reversed sparse set. */ [[nodiscard]] reverse_iterator rend() const noexcept { return stl::make_reverse_iterator(begin()); } /*! @copydoc rend */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return rend(); } /** * @brief Finds an entity. * @param entt A valid identifier. * @return An iterator to the given entity if it's found, past the end * iterator otherwise. */ [[nodiscard]] const_iterator find(const entity_type entt) const noexcept { return contains(entt) ? to_iterator(entt) : end(); } /** * @brief Checks if a sparse set contains an entity. * @param entt A valid identifier. * @return True if the sparse set contains the entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { const auto *elem = sparse_ptr(entt); constexpr auto cap = traits_type::entity_mask; constexpr auto mask = traits_type::to_integral(null) & ~cap; // testing versions permits to avoid accessing the packed array return elem && (((mask & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap); } /** * @brief Returns the contained version for an identifier. * @param entt A valid identifier. * @return The version for the given identifier if present, the tombstone * version otherwise. */ [[nodiscard]] version_type current(const entity_type entt) const noexcept { const auto *elem = sparse_ptr(entt); constexpr auto fallback = traits_type::to_version(tombstone); return elem ? traits_type::to_version(*elem) : fallback; } /** * @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 identifier. * @return The position of the entity in the sparse set. */ [[nodiscard]] size_type index(const entity_type entt) const noexcept { ENTT_ASSERT(contains(entt), "Set does not contain entity"); return entity_to_pos(sparse_ref(entt)); } /** * @brief Returns the entity at specified location. * @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 noexcept { ENTT_ASSERT(pos < packed.size(), "Index out of bounds"); return packed[pos]; } /** * @brief Returns the element assigned to an entity, if any. * * @warning * Attempting to use an entity that doesn't belong to the sparse set results * in undefined behavior. * * @param entt A valid identifier. * @return An opaque pointer to the element assigned to the entity, if any. */ [[nodiscard]] const void *value(const entity_type entt) const noexcept { return get_at(index(entt)); } /*! @copydoc value */ [[nodiscard]] void *value(const entity_type entt) noexcept { return const_cast(stl::as_const(*this).value(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. * * @param entt A valid identifier. * @param elem Optional opaque element to forward to mixins, if any. * @return Iterator pointing to the emplaced element in case of success, the * `end()` iterator otherwise. */ iterator push(const entity_type entt, const void *elem = nullptr) { return try_emplace(entt, false, elem); } /** * @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. * * @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 Iterator pointing to the first element inserted in case of * success, the `end()` iterator otherwise. */ iterator push(stl::input_iterator auto first, stl::input_iterator auto last) { auto curr = end(); for(; first != last; ++first) { curr = try_emplace(*first, true); } return curr; } /** * @brief Bump the version number of an entity. * * @warning * Attempting to bump the version of an entity that doesn't belong to the * sparse set results in undefined behavior. * * @param entt A valid identifier. * @return The version of the given identifier. */ version_type bump(const entity_type entt) { auto &elem = sparse_ref(entt); ENTT_ASSERT(entt != null && elem != tombstone, "Cannot set the required version"); elem = traits_type::combine(traits_type::to_integral(elem), traits_type::to_integral(entt)); packed[entity_to_pos(elem)] = entt; return traits_type::to_version(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 identifier. */ void erase(const entity_type entt) { const auto it = to_iterator(entt); pop(it, it + 1u); } /** * @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. */ template void erase(It first, It last) { if constexpr(stl::is_same_v) { pop(first, last); } else { for(; first != last; ++first) { erase(*first); } } } /** * @brief Removes an entity from a sparse set if it exists. * @param entt A valid identifier. * @return True if the entity is actually removed, false otherwise. */ bool remove(const entity_type entt) { return contains(entt) && (erase(entt), 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. * @return The number of entities actually removed. */ template size_type remove(It first, It last) { size_type count{}; if constexpr(stl::is_same_v) { while(first != last) { while(first != last && !contains(*first)) { ++first; } const auto it = first; while(first != last && contains(*first)) { ++first; } count += static_cast(stl::distance(it, first)); erase(it, first); } } else { for(; first != last; ++first) { count += remove(*first); } } return count; } /*! @brief Removes all tombstones from a sparse set. */ void compact() { if(mode == deletion_policy::in_place) { size_type from = packed.size(); size_type pos = stl::exchange(head, max_size); for(; from && packed[from - 1u] == tombstone; --from) {} while(pos != max_size) { if(const auto to = stl::exchange(pos, entity_to_pos(packed[pos])); to < from) { --from; swap_or_move(from, to); packed[to] = packed[from]; const auto elem = static_cast(to); sparse_ref(packed[to]) = traits_type::combine(elem, traits_type::to_integral(packed[to])); for(; from && packed[from - 1u] == tombstone; --from) {} } } packed.erase(packed.begin() + static_cast(from), packed.end()); } } /** * @brief Swaps two entities in a sparse set. * * 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 identifier. * @param rhs A valid identifier. */ void swap_elements(const entity_type lhs, const entity_type rhs) { const auto from = index(lhs); const auto to = index(rhs); // basic no-leak guarantee if swapping throws swap_or_move(from, to); swap_at(from, to); } /** * @brief Sort the first count elements according to the given comparison * function. * * The comparison function object must return `true` if the first element * is _less_ than the second one, `false` otherwise. The signature of the * comparison function should be equivalent to the following: * * @code{.cpp} * bool(const Entity, const Entity); * @endcode * * Moreover, the comparison function object shall induce a * _strict weak ordering_ on the values. * * The sort function object must offer a member function template * `operator()` that accepts three arguments: * * * An iterator to the first element of the range to sort. * * An iterator past the last element of the range to sort. * * A comparison function to use to compare the elements. * * @tparam Compare Type of comparison function object. * @tparam Sort Type of sort function object. * @tparam Args Types of arguments to forward to the sort function object. * @param 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) { ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements"); algo(packed.rend() - static_cast(length), packed.rend(), stl::move(compare), stl::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_or_move(next, idx); const auto elem = static_cast(curr); sparse_ref(entt) = traits_type::combine(elem, traits_type::to_integral(packed[curr])); curr = stl::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) { const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size(); sort_n(len, stl::move(compare), stl::move(algo), stl::forward(args)...); } /** * @brief Sort entities according to their order in a range. * * Entities that are part of both the sparse set and the range are ordered * internally according to the order they have in the range.
* All other entities goes to the end of the sparse set and there are no * guarantees on their order. * * @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 An iterator past the last of the elements actually shared. */ template iterator sort_as(It first, It last) { ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size(); auto it = end() - static_cast(len); for(const auto other = end(); (it != other) && (first != last); ++first) { if(const auto curr = *first; contains(curr)) { if(const auto entt = *it; entt != curr) { // basic no-leak guarantee (with invalid state) if swapping throws swap_elements(entt, curr); } ++it; } } return it; } /*! @brief Clears a sparse set. */ void clear() { pop_all(); // sanity check to avoid subtle issues due to storage classes ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set"); head = policy_to_head(); packed.clear(); } /** * @brief Returns a type info object for the value type, if any. * @return A type info object for the value type, if any. */ [[nodiscard]] const type_info &info() const noexcept { return *descriptor; } /** * @brief Forwards variables to derived classes, if any. * @tparam Type Type of the element to forward. * @param value The element to forward. */ template void bind(Type &&value) noexcept { bind_any(forward_as_any(stl::forward(value))); } private: sparse_container_type sparse; packed_container_type packed; const type_info *descriptor; deletion_policy mode; size_type head; }; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class storage_iterator final { template friend class storage_iterator; using container_type = stl::remove_const_t; using alloc_traits = stl::allocator_traits; using iterator_traits = stl::iterator_traits, typename alloc_traits::template rebind_traits::element_type>::const_pointer, typename alloc_traits::template rebind_traits::element_type>::pointer>>; public: using value_type = iterator_traits::value_type; using pointer = iterator_traits::pointer; using reference = iterator_traits::reference; using difference_type = iterator_traits::difference_type; using iterator_category = stl::random_access_iterator_tag; constexpr storage_iterator() noexcept = default; constexpr storage_iterator(Container *ref, const difference_type idx) noexcept : payload{ref}, offset{idx} {} template> Other> requires stl::is_const_v constexpr storage_iterator(const storage_iterator &other) noexcept : storage_iterator{other.payload, other.offset} {} constexpr storage_iterator &operator++() noexcept { return --offset, *this; } constexpr storage_iterator operator++(int) noexcept { const storage_iterator orig = *this; return ++(*this), orig; } constexpr storage_iterator &operator--() noexcept { return ++offset, *this; } constexpr storage_iterator operator--(int) noexcept { const storage_iterator orig = *this; return operator--(), orig; } constexpr storage_iterator &operator+=(const difference_type value) noexcept { offset -= value; return *this; } constexpr storage_iterator operator+(const difference_type value) const noexcept { storage_iterator copy = *this; return (copy += value); } constexpr storage_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr storage_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { const auto pos = static_cast(index() - value); return (*payload)[pos / Page][fast_mod(static_cast(pos), Page)]; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(operator[](0)); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const storage_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset - offset; } template [[nodiscard]] constexpr bool operator==(const storage_iterator &other) const noexcept { return offset == other.offset; } template [[nodiscard]] constexpr auto operator<=>(const storage_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset <=> offset; } [[nodiscard]] constexpr difference_type index() const noexcept { return offset - 1; } private: Container *payload; difference_type offset; }; template class extended_storage_iterator final { template friend class extended_storage_iterator; public: using iterator_type = It; using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::forward_as_tuple(*stl::declval()...))); using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr extended_storage_iterator() : it{} {} constexpr extended_storage_iterator(iterator_type base, Other... other) : it{base, other...} {} template requires (!stl::same_as && ...) && (stl::constructible_from && ...) constexpr extended_storage_iterator(const extended_storage_iterator &other) : it{other.it} {} constexpr extended_storage_iterator &operator++() noexcept { return ++stl::get(it), (++stl::get(it), ...), *this; } constexpr extended_storage_iterator operator++(int) noexcept { const extended_storage_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return {*stl::get(it), *stl::get(it)...}; } [[nodiscard]] constexpr iterator_type base() const noexcept { return stl::get(it); } template [[nodiscard]] constexpr bool operator==(const extended_storage_iterator &other) const noexcept { return stl::get<0>(it) == stl::get<0>(other.it); } private: stl::tuple it; }; } // namespace internal /*! @endcond */ /** * @brief Storage implementation. * * 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. * * @tparam Type Element type. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_storage: public basic_sparse_set::template rebind_alloc> { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_type = stl::vector>; using underlying_type = basic_sparse_set>; using underlying_iterator = underlying_type::basic_iterator; using traits_type = component_traits; [[nodiscard]] auto &element_at(const stl::size_t pos) const { return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)]; } auto assure_at_least(const stl::size_t pos) { const auto idx = pos / traits_type::page_size; if(!(idx < payload.size())) { auto curr = payload.size(); allocator_type allocator{get_allocator()}; payload.resize(idx + 1u, nullptr); ENTT_TRY { for(const auto last = payload.size(); curr < last; ++curr) { payload[curr] = alloc_traits::allocate(allocator, traits_type::page_size); } } ENTT_CATCH { payload.resize(curr); ENTT_THROW; } } return payload[idx] + fast_mod(pos, traits_type::page_size); } template auto emplace_element(const Entity entt, const bool force_back, Args &&...args) { const auto it = base_type::try_emplace(entt, force_back); ENTT_TRY { auto *elem = stl::to_address(assure_at_least(static_cast(it.index()))); entt::uninitialized_construct_using_allocator(elem, get_allocator(), stl::forward(args)...); } ENTT_CATCH { base_type::pop(it, it + 1u); ENTT_THROW; } return it; } void shrink_to_size(const stl::size_t sz) { const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size; allocator_type allocator{get_allocator()}; if constexpr(!stl::is_trivially_destructible_v) { for(auto pos = sz, length = base_type::size(); pos < length; ++pos) { if constexpr(traits_type::in_place_delete) { if(base_type::data()[pos] != tombstone) { alloc_traits::destroy(allocator, stl::addressof(element_at(pos))); } } else { alloc_traits::destroy(allocator, stl::addressof(element_at(pos))); } } } for(auto pos = from, last = payload.size(); pos < last; ++pos) { alloc_traits::deallocate(allocator, payload[pos], traits_type::page_size); } payload.resize(from); payload.shrink_to_fit(); } void swap_at(const stl::size_t lhs, const stl::size_t rhs) { using stl::swap; swap(element_at(lhs), element_at(rhs)); } void move_to(const stl::size_t lhs, const stl::size_t rhs) { auto &elem = element_at(lhs); allocator_type allocator{get_allocator()}; entt::uninitialized_construct_using_allocator(stl::to_address(assure_at_least(rhs)), allocator, stl::move(elem)); alloc_traits::destroy(allocator, stl::addressof(elem)); } private: [[nodiscard]] const void *get_at(const stl::size_t pos) const final { return stl::addressof(element_at(pos)); } void swap_or_move([[maybe_unused]] const stl::size_t from, [[maybe_unused]] const stl::size_t to) override { static constexpr bool is_pinned_type = !(stl::is_move_constructible_v && stl::is_move_assignable_v); // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy ENTT_ASSERT((from + 1u) && !is_pinned_type, "Pinned type"); if constexpr(!is_pinned_type) { if constexpr(traits_type::in_place_delete) { (base_type::operator[](to) == tombstone) ? move_to(from, to) : swap_at(from, to); } else { swap_at(from, to); } } } protected: /** * @brief Erases entities from a storage. * @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. */ void pop(underlying_iterator first, underlying_iterator last) override { for(allocator_type allocator{get_allocator()}; first != last; ++first) { // cannot use first.index() because it would break with cross iterators auto &elem = element_at(base_type::index(*first)); if constexpr(traits_type::in_place_delete) { base_type::in_place_pop(*first); alloc_traits::destroy(allocator, stl::addressof(elem)); } else if constexpr(stl::is_trivially_destructible_v) { elem = stl::move(element_at(base_type::size() - 1u)); base_type::swap_and_pop(*first); } else { auto &other = element_at(base_type::size() - 1u); // destroying on exit allows reentrant destructors [[maybe_unused]] auto unused = stl::exchange(elem, stl::move(other)); alloc_traits::destroy(allocator, stl::addressof(other)); base_type::swap_and_pop(*first); } } } /*! @brief Erases all entities of a storage. */ void pop_all() override { if constexpr(stl::is_trivially_destructible_v) { base_type::pop_all(); } else { allocator_type allocator{get_allocator()}; for(auto first = base_type::begin(); !(first.index() < 0); ++first) { if constexpr(traits_type::in_place_delete) { if(*first != tombstone) { base_type::in_place_pop(*first); alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast(first.index())))); } } else { base_type::swap_and_pop(*first); alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast(first.index())))); } } } } /** * @brief Assigns an entity to a storage. * @param entt A valid identifier. * @param value Optional opaque value. * @param force_back Force back insertion. * @return Iterator pointing to the emplaced element. */ underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override { if(value != nullptr) { if constexpr(stl::is_copy_constructible_v) { return emplace_element(entt, force_back, *static_cast(value)); } else { return base_type::end(); } } else { if constexpr(stl::is_default_constructible_v) { return emplace_element(entt, force_back); } else { return base_type::end(); } } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Base type. */ using base_type = underlying_type; /*! @brief Element type. */ using element_type = Type; /*! @brief Type of the objects assigned to entities. */ using value_type = element_type; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Pointer type to contained elements. */ using pointer = container_type::pointer; /*! @brief Constant pointer type to contained elements. */ using const_pointer = alloc_traits::template rebind_traits::const_pointer; /*! @brief Random access iterator type. */ using iterator = internal::storage_iterator; /*! @brief Constant random access iterator type. */ using const_iterator = internal::storage_iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = stl::reverse_iterator; /*! @brief Extended iterable storage proxy. */ using iterable = iterable_adaptor>; /*! @brief Constant extended iterable storage proxy. */ using const_iterable = iterable_adaptor>; /*! @brief Extended reverse iterable storage proxy. */ using reverse_iterable = iterable_adaptor>; /*! @brief Constant extended reverse iterable storage proxy. */ using const_reverse_iterable = iterable_adaptor>; /*! @brief Storage deletion policy. */ static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; /*! @brief Default constructor. */ basic_storage() : basic_storage{allocator_type{}} {} /** * @brief Constructs an empty storage with a given allocator. * @param allocator The allocator to use. */ explicit basic_storage(const allocator_type &allocator) : base_type{type_id(), storage_policy, allocator}, payload{allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_storage(const basic_storage &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_storage(basic_storage &&other) noexcept : base_type{static_cast(other)}, payload{stl::move(other.payload)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_storage(basic_storage &&other, const allocator_type &allocator) : base_type{static_cast(other), allocator}, payload{stl::move(other.payload), allocator} { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed"); } /*! @brief Default destructor. */ // NOLINTNEXTLINE(bugprone-exception-escape) ~basic_storage() override { shrink_to_size(0u); } /** * @brief Default copy assignment operator, deleted on purpose. * @return This storage. */ basic_storage &operator=(const basic_storage &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This storage. */ basic_storage &operator=(basic_storage &&other) noexcept { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed"); swap(other); return *this; } /** * @brief Exchanges the contents with those of a given storage. * @param other Storage to exchange the content with. */ void swap(basic_storage &other) noexcept { using stl::swap; swap(payload, other.payload); base_type::swap(other); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return payload.get_allocator(); } /** * @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) override { if(cap != 0u) { base_type::reserve(cap); assure_at_least(cap - 1u); } } /** * @brief Returns the number of elements that a storage has currently * allocated space for. * @return Capacity of the storage. */ [[nodiscard]] size_type capacity() const noexcept override { return payload.size() * traits_type::page_size; } /*! @brief Requests the removal of unused capacity. */ void shrink_to_fit() override { base_type::shrink_to_fit(); shrink_to_size(base_type::size()); } /** * @brief Direct access to the array of objects. * @return A pointer to the array of objects. */ [[nodiscard]] const_pointer raw() const noexcept { return payload.data(); } /*! @copydoc raw */ [[nodiscard]] pointer raw() noexcept { return payload.data(); } /** * @brief Returns an iterator to the beginning. * * 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 noexcept { const auto pos = static_cast(base_type::size()); return const_iterator{&payload, pos}; } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { const auto pos = static_cast(base_type::size()); return iterator{&payload, pos}; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return const_iterator{&payload, {}}; } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return iterator{&payload, {}}; } /** * @brief Returns a reverse iterator to the beginning. * * 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 noexcept { return stl::make_reverse_iterator(cend()); } /*! @copydoc crbegin */ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @copydoc rbegin */ [[nodiscard]] reverse_iterator rbegin() noexcept { return stl::make_reverse_iterator(end()); } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last instance of the * reversed internal array. */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return stl::make_reverse_iterator(cbegin()); } /*! @copydoc crend */ [[nodiscard]] const_reverse_iterator rend() const noexcept { return crend(); } /*! @copydoc rend */ [[nodiscard]] reverse_iterator rend() noexcept { return stl::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 identifier. * @return The object assigned to the entity. */ [[nodiscard]] const value_type &get(const entity_type entt) const noexcept { return element_at(base_type::index(entt)); } /*! @copydoc get */ [[nodiscard]] value_type &get(const entity_type entt) noexcept { return const_cast(stl::as_const(*this).get(entt)); } /** * @brief Returns the object assigned to an entity as a tuple. * @param entt A valid identifier. * @return The object assigned to the entity as a tuple. */ [[nodiscard]] stl::tuple get_as_tuple(const entity_type entt) const noexcept { return stl::forward_as_tuple(get(entt)); } /*! @copydoc get_as_tuple */ [[nodiscard]] stl::tuple get_as_tuple(const entity_type entt) noexcept { return stl::forward_as_tuple(get(entt)); } /** * @brief Assigns an entity to a storage and constructs its object. * * @warning * Attempting to use an entity that already belongs to the storage results * in undefined behavior. * * @tparam Args Types of arguments to use to construct the object. * @param entt A valid identifier. * @param args Parameters to use to construct an object for the entity. * @return A reference to the newly created object. */ template value_type &emplace(const entity_type entt, Args &&...args) { if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { const auto it = emplace_element(entt, false, Type{stl::forward(args)...}); return element_at(static_cast(it.index())); } else { const auto it = emplace_element(entt, false, stl::forward(args)...); return element_at(static_cast(it.index())); } } /** * @brief Updates the instance assigned to a given entity in-place. * @tparam Func Types of the function objects to invoke. * @param entt A valid identifier. * @param func Valid function objects. * @return A reference to the updated instance. */ template value_type &patch(const entity_type entt, Func &&...func) { const auto idx = base_type::index(entt); auto &elem = element_at(idx); (stl::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. * * @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. * @return Iterator pointing to the first element inserted, if any. */ iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value = {}) { for(; first != last; ++first) { emplace_element(*first, true, value); } return begin(); } /** * @brief Assigns one or more entities to a storage and constructs their * objects from a given range. * * @sa construct * * @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 from An iterator to the first element of the range of objects. * @return Iterator pointing to the first element inserted, if any. */ template requires stl::same_as::value_type, value_type> iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from) { for(; first != last; ++first, ++from) { emplace_element(*first, true, *from); } return begin(); } /** * @brief Returns an iterable object to use to _visit_ a storage. * * The iterable object returns a tuple that contains the current entity and * a reference to its element. * * @return An iterable object to use to _visit_ the storage. */ [[nodiscard]] iterable each() noexcept { return iterable{{base_type::begin(), begin()}, {base_type::end(), end()}}; } /*! @copydoc each */ [[nodiscard]] const_iterable each() const noexcept { return const_iterable{{base_type::cbegin(), cbegin()}, {base_type::cend(), cend()}}; } /** * @brief Returns a reverse iterable object to use to _visit_ a storage. * * @sa each * * @return A reverse iterable object to use to _visit_ the storage. */ [[nodiscard]] reverse_iterable reach() noexcept { return reverse_iterable{{base_type::rbegin(), rbegin()}, {base_type::rend(), rend()}}; } /*! @copydoc reach */ [[nodiscard]] const_reverse_iterable reach() const noexcept { return const_reverse_iterable{{base_type::crbegin(), crbegin()}, {base_type::crend(), crend()}}; } private: container_type payload; }; /*! @copydoc basic_storage */ template requires (component_traits::page_size == 0u) class basic_storage : public basic_sparse_set::template rebind_alloc> { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using traits_type = component_traits; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Base type. */ using base_type = basic_sparse_set>; /*! @brief Element type. */ using element_type = Type; /*! @brief Type of the objects assigned to entities. */ using value_type = void; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Extended iterable storage proxy. */ using iterable = iterable_adaptor>; /*! @brief Constant extended iterable storage proxy. */ using const_iterable = iterable_adaptor>; /*! @brief Extended reverse iterable storage proxy. */ using reverse_iterable = iterable_adaptor>; /*! @brief Constant extended reverse iterable storage proxy. */ using const_reverse_iterable = iterable_adaptor>; /*! @brief Storage deletion policy. */ static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; /*! @brief Default constructor. */ basic_storage() : basic_storage{allocator_type{}} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit basic_storage(const allocator_type &allocator) : base_type{type_id(), storage_policy, allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_storage(const basic_storage &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_storage(basic_storage &&other) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_storage(basic_storage &&other, const allocator_type &allocator) : base_type{stl::move(other), allocator} {} /*! @brief Default destructor. */ ~basic_storage() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This storage. */ basic_storage &operator=(const basic_storage &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This storage. */ basic_storage &operator=(basic_storage &&other) noexcept = default; /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return allocator_type{base_type::get_allocator()}; } /** * @brief Returns the object assigned to an entity, that is `void`. * * @warning * Attempting to use an entity that doesn't belong to the storage results in * undefined behavior. * * @param entt A valid identifier. */ void get([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); } /** * @brief Returns an empty tuple. * @param entt A valid identifier. * @return Returns an empty tuple. */ [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); return stl::tuple{}; } /** * @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. * * @param entt A valid identifier. */ void emplace(const entity_type entt, const auto &...) { base_type::try_emplace(entt, false); } /** * @brief Updates the instance assigned to a given entity in-place. * @tparam Func Types of the function objects to invoke. * @param entt A valid identifier. * @param func Valid function objects. */ template void patch([[maybe_unused]] const entity_type entt, Func &&...func) { ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); (stl::forward(func)(), ...); } /** * @brief Assigns entities to a storage. * @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. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...) { for(; first != last; ++first) { base_type::try_emplace(*first, true); } } /** * @brief Returns an iterable object to use to _visit_ a storage. * * The iterable object returns a tuple that contains the current entity. * * @return An iterable object to use to _visit_ the storage. */ [[nodiscard]] iterable each() noexcept { return iterable{base_type::begin(), base_type::end()}; } /*! @copydoc each */ [[nodiscard]] const_iterable each() const noexcept { return const_iterable{base_type::cbegin(), base_type::cend()}; } /** * @brief Returns a reverse iterable object to use to _visit_ a storage. * * @sa each * * @return A reverse iterable object to use to _visit_ the storage. */ [[nodiscard]] reverse_iterable reach() noexcept { return reverse_iterable{{base_type::rbegin()}, {base_type::rend()}}; } /*! @copydoc reach */ [[nodiscard]] const_reverse_iterable reach() const noexcept { return const_reverse_iterable{{base_type::crbegin()}, {base_type::crend()}}; } }; /** * @brief Swap-only entity storage specialization. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_storage : public basic_sparse_set { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using underlying_iterator = basic_sparse_set::basic_iterator; using traits_type = entt_traits; auto from_placeholder() noexcept { const auto entt = traits_type::combine(static_cast(placeholder), {}); ENTT_ASSERT(entt != null, "No more entities available"); placeholder += static_cast(entt != null); return entt; } auto next() noexcept { entity_type entt = from_placeholder(); while(base_type::current(entt) != traits_type::to_version(tombstone) && entt != null) { entt = from_placeholder(); } return entt; } protected: /*! @brief Erases all entities of a storage. */ void pop_all() override { base_type::pop_all(); placeholder = {}; } /** * @brief Assigns an entity to a storage. * @param hint A valid identifier. * @return Iterator pointing to the emplaced element. */ underlying_iterator try_emplace(const Entity hint, const bool, const void *) override { return base_type::find(generate(hint)); } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Base type. */ using base_type = basic_sparse_set; /*! @brief Element type. */ using element_type = Entity; /*! @brief Type of the objects assigned to entities. */ using value_type = void; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Extended iterable storage proxy. */ using iterable = iterable_adaptor>; /*! @brief Constant extended iterable storage proxy. */ using const_iterable = iterable_adaptor>; /*! @brief Extended reverse iterable storage proxy. */ using reverse_iterable = iterable_adaptor>; /*! @brief Constant extended reverse iterable storage proxy. */ using const_reverse_iterable = iterable_adaptor>; /*! @brief Storage deletion policy. */ static constexpr deletion_policy storage_policy = deletion_policy::swap_only; /*! @brief Default constructor. */ basic_storage() : basic_storage{allocator_type{}} { } /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit basic_storage(const allocator_type &allocator) : base_type{type_id(), storage_policy, allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_storage(const basic_storage &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) basic_storage(basic_storage &&other) noexcept : base_type{static_cast(other)}, placeholder{other.placeholder} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) basic_storage(basic_storage &&other, const allocator_type &allocator) : base_type{static_cast(other), allocator}, placeholder{other.placeholder} {} /*! @brief Default destructor. */ ~basic_storage() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This storage. */ basic_storage &operator=(const basic_storage &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This storage. */ basic_storage &operator=(basic_storage &&other) noexcept { placeholder = other.placeholder; base_type::operator=(stl::move(other)); return *this; } /** * @brief Exchanges the contents with those of a given storage. * @param other Storage to exchange the content with. */ void swap(basic_storage &other) noexcept { using stl::swap; swap(placeholder, other.placeholder); base_type::swap(other); } /** * @brief Returns the object assigned to an entity, that is `void`. * * @warning * Attempting to use an entity that doesn't belong to the storage results in * undefined behavior. * * @param entt A valid identifier. */ void get([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); } /** * @brief Returns an empty tuple. * @param entt A valid identifier. * @return Returns an empty tuple. */ [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); return stl::tuple{}; } /** * @brief Creates a new identifier or recycles a destroyed one. * @return A valid identifier. */ entity_type generate() { const auto len = base_type::free_list(); const auto entt = (len == base_type::size()) ? next() : base_type::data()[len]; return *base_type::try_emplace(entt, true); } /** * @brief Creates a new identifier or recycles a destroyed one. * * If the requested identifier isn't in use, the suggested one is used. * Otherwise, a new identifier is returned. * * @param hint Required identifier. * @return A valid identifier. */ entity_type generate(const entity_type hint) { if(hint != null && hint != tombstone) { if(const auto curr = traits_type::construct(traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone || !(base_type::index(curr) < base_type::free_list())) { return *base_type::try_emplace(hint, true); } } return generate(); } /** * @brief Assigns each element in a range an identifier. * @tparam It Type of output 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 It> void generate(It first, It last) { for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) { *first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true); } for(; first != last; ++first) { *first = *base_type::try_emplace(next(), true); } } /** * @brief Updates a given identifier. * @tparam Func Types of the function objects to invoke. * @param entt A valid identifier. * @param func Valid function objects. */ template void patch([[maybe_unused]] const entity_type entt, Func &&...func) { ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); (stl::forward(func)(), ...); } /** * @brief Returns an iterable object to use to _visit_ a storage. * * The iterable object returns a tuple that contains the current entity. * * @return An iterable object to use to _visit_ the storage. */ [[nodiscard]] iterable each() noexcept { return stl::as_const(*this).each(); } /*! @copydoc each */ [[nodiscard]] const_iterable each() const noexcept { const auto it = base_type::cend(); const auto offset = static_cast(base_type::free_list()); return const_iterable{it - offset, it}; } /** * @brief Returns a reverse iterable object to use to _visit_ a storage. * * @sa each * * @return A reverse iterable object to use to _visit_ the storage. */ [[nodiscard]] reverse_iterable reach() noexcept { return stl::as_const(*this).reach(); } /*! @copydoc reach */ [[nodiscard]] const_reverse_iterable reach() const noexcept { const auto it = base_type::crbegin(); const auto offset = static_cast(base_type::free_list()); return const_reverse_iterable{it, it + offset}; } /** * @brief Sets the starting identifier for generation. * * The version is ignored, regardless of the value. * * @param hint A valid identifier. */ void start_from(const entity_type hint) { placeholder = static_cast(traits_type::to_entity(hint)); } private: size_type placeholder{}; }; } // namespace entt #endif // #include "view.hpp" #ifndef ENTT_ENTITY_VIEW_HPP #define ENTT_ENTITY_VIEW_HPP // #include "../config/config.h" // #include "../core/concepts.hpp" // #include "../core/iterator.hpp" // #include "../core/type_traits.hpp" // #include "../stl/array.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template // NOLINTNEXTLINE(misc-redundant-expression) static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place)); template const Type *view_placeholder() { static const Type placeholder{}; return &placeholder; } [[nodiscard]] bool all_of(auto first, const auto last, const auto entt) noexcept { for(; (first != last) && (*first)->contains(entt); ++first) {} return first == last; } [[nodiscard]] bool none_of(auto first, const auto last, const auto entt) noexcept { for(; (first != last) && !(*first)->contains(entt); ++first) {} return first == last; } template [[nodiscard]] bool fully_initialized(It first, const It last, const stl::remove_pointer_t::value_type> *placeholder) noexcept { for(; (first != last) && *first != placeholder; ++first) {} return first == last; } template [[nodiscard]] Result view_pack(const View &view, const Other &other, stl::index_sequence, stl::index_sequence, stl::index_sequence, stl::index_sequence) { Result elem{}; // friend-initialization, avoid multiple calls to refresh elem.pools = {view.template storage()..., other.template storage()...}; [[maybe_unused]] const auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; }; elem.filter = {filter_or_placeholder(view.template storage())..., filter_or_placeholder(other.template storage())...}; elem.refresh(); return elem; } template class view_iterator final { template friend struct extended_view_iterator; using iterator_type = Type::const_iterator; using iterator_traits = stl::iterator_traits; [[nodiscard]] bool valid(const iterator_traits::value_type entt) const noexcept { return (!Checked || (entt != tombstone)) && ((Get == 1u) || (internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt))) && ((Exclude == 0u) || internal::none_of(filter.begin(), filter.end(), entt)); } void seek_next() { for(constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {} } public: using value_type = iterator_traits::value_type; using pointer = iterator_traits::pointer; using reference = iterator_traits::reference; using difference_type = iterator_traits::difference_type; using iterator_category = stl::forward_iterator_tag; constexpr view_iterator() noexcept : it{}, pools{}, filter{}, index{} {} view_iterator(iterator_type first, stl::array value, stl::array excl, const stl::size_t idx) noexcept : it{first}, pools{value}, filter{excl}, index{static_cast(idx)} { ENTT_ASSERT((Get != 1u) || (Exclude != 0u) || pools[0u]->policy() == deletion_policy::in_place, "Non in-place storage view iterator"); seek_next(); } view_iterator &operator++() noexcept { ++it; seek_next(); return *this; } view_iterator operator++(int) noexcept { const view_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] pointer operator->() const noexcept { return &*it; } [[nodiscard]] reference operator*() const noexcept { return *operator->(); } template [[nodiscard]] constexpr bool operator==(const view_iterator &other) const noexcept { return it == other.it; } private: iterator_type it; stl::array pools; stl::array filter; difference_type index; }; template struct extended_view_iterator final { using iterator_type = It; using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::declval().get_as_tuple({})...)); using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr extended_view_iterator() : it{} {} extended_view_iterator(iterator_type from) : it{from} {} extended_view_iterator &operator++() noexcept { return ++it, *this; } extended_view_iterator operator++(int) noexcept { const extended_view_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] reference operator*() const noexcept { return [this](stl::index_sequence) { return stl::tuple_cat(stl::make_tuple(*it), static_cast(const_cast *>(stl::get(it.pools)))->get_as_tuple(*it)...); }(stl::index_sequence_for{}); } [[nodiscard]] pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr iterator_type base() const noexcept { return it; } template [[nodiscard]] constexpr bool operator==(const extended_view_iterator &other) const noexcept { return it == other.it; } private: It it; }; } // namespace internal /*! @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. * * @b Important * * View iterators aren't invalidated if: * * * New elements are added to the storage iterated by the view. * * The entity currently returned is modified (for example, elements are added * or removed from it). * * The entity currently returned is destroyed. * * In all other cases, modifying the storage iterated by a view in any way can * invalidate all iterators. */ template class basic_view; /** * @brief Basic storage view implementation. * @warning For internal use only, backward compatibility not guaranteed. * @tparam Type Common type among all storage types. * @tparam Checked True to enable the tombstone check, false otherwise. * @tparam Get Number of storage iterated by the view. * @tparam Exclude Number of storage used to filter the view. */ template class basic_common_view { template friend Return internal::view_pack(const View &, const Other &, stl::index_sequence, stl::index_sequence, stl::index_sequence, stl::index_sequence); [[nodiscard]] auto offset() const noexcept { ENTT_ASSERT(index != Get, "Invalid view"); return (pools[index]->policy() == deletion_policy::swap_only) ? pools[index]->free_list() : pools[index]->size(); } void unchecked_refresh() noexcept { index = 0u; if constexpr(Get > 1u) { for(size_type pos{1u}; pos < Get; ++pos) { if(pools[pos]->size() < pools[index]->size()) { index = pos; } } } } protected: /*! @cond ENTT_INTERNAL */ basic_common_view() noexcept { for(size_type pos{}, last = filter.size(); pos < last; ++pos) { filter[pos] = placeholder; } } basic_common_view(stl::array value, stl::array excl) noexcept : pools{value}, filter{excl}, index{Get} { unchecked_refresh(); } [[nodiscard]] const Type *pool_at(const stl::size_t pos) const noexcept { return pools[pos]; } void pool_at(const stl::size_t pos, const Type *elem) noexcept { ENTT_ASSERT(elem != nullptr, "Unexpected element"); pools[pos] = elem; refresh(); } [[nodiscard]] const Type *filter_at(const stl::size_t pos) const noexcept { return (filter[pos] == placeholder) ? nullptr : filter[pos]; } void filter_at(const stl::size_t pos, const Type *elem) noexcept { ENTT_ASSERT(elem != nullptr, "Unexpected element"); filter[pos] = elem; } [[nodiscard]] bool none_of(const Type::entity_type entt) const noexcept { return internal::none_of(filter.begin(), filter.end(), entt); } void use(const stl::size_t pos) noexcept { index = (index != Get) ? pos : Get; } /*! @endcond */ public: /*! @brief Common type among all storage types. */ using common_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = Type::entity_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Forward iterator type. */ using iterator = internal::view_iterator; /*! @brief Updates the internal leading view if required. */ void refresh() noexcept { size_type pos = static_cast(index != Get) * Get; for(; pos < Get && pools[pos] != nullptr; ++pos) {} if(pos == Get) { unchecked_refresh(); } } /** * @brief Returns the leading storage of a view, if any. * @return The leading storage of the view. */ [[nodiscard]] const common_type *handle() const noexcept { return (index != Get) ? pools[index] : nullptr; } /** * @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 noexcept { return (index != Get) ? offset() : size_type{}; } /** * @brief Returns an iterator 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 noexcept { return (index != Get) ? iterator{pools[index]->end() - static_cast(offset()), pools, filter, index} : iterator{}; } /** * @brief Returns an iterator that is past the last entity of the view. * @return An iterator to the entity following the last entity of the view. */ [[nodiscard]] iterator end() const noexcept { return (index != Get) ? iterator{pools[index]->end(), pools, filter, index} : iterator{}; } /** * @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 noexcept { 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 noexcept { if(index != Get) { auto it = pools[index]->rbegin(); const auto last = it + static_cast(offset()); for(const auto idx = static_cast(index); it != last && !(internal::all_of(pools.begin(), pools.begin() + idx, *it) && internal::all_of(pools.begin() + idx + 1, pools.end(), *it) && internal::none_of(filter.begin(), filter.end(), *it)); ++it) {} return it == last ? null : *it; } return null; } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { return contains(entt) ? iterator{pools[index]->find(entt), pools, filter, index} : end(); } /** * @brief Checks if a view is fully initialized. * @return True if the view is fully initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (index != Get) && internal::fully_initialized(filter.begin(), filter.end(), placeholder); } /** * @brief Checks if a view contains an entity. * @param entt A valid identifier. * @return True if the view contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { return (index != Get) && internal::all_of(pools.begin(), pools.end(), entt) && internal::none_of(filter.begin(), filter.end(), entt) && pools[index]->index(entt) < offset(); } private: stl::array pools{}; stl::array filter{}; const common_type *placeholder{internal::view_placeholder()}; size_type index{Get}; }; /** * @brief General purpose view. * * This view visits all entities that are at least in the given storage. During * initialization, it also looks at the number of elements available for each * storage and uses the smallest set in order to get a performance boost. * * @sa basic_view * * @tparam Get Types of storage iterated by the view. * @tparam Exclude Types of storage used to filter the view. */ template requires (sizeof...(Get) != 0u) class basic_view, exclude_t> : public basic_common_view, internal::tombstone_check_v, sizeof...(Get), sizeof...(Exclude)> { using base_type = basic_common_view, internal::tombstone_check_v, sizeof...(Get), sizeof...(Exclude)>; template using element_at = type_list_element_t>; template static constexpr stl::size_t index_of = type_list_index_v, type_list>; template [[nodiscard]] auto dispatch_get(const stl::tuple &curr) const { if constexpr(Curr == Other) { return stl::forward_as_tuple(stl::get(curr)...); } else { return storage()->get_as_tuple(stl::get<0>(curr)); } } template void each(Func func, stl::index_sequence) const { for(const auto curr: storage()->each()) { if(const auto entt = stl::get<0>(curr); (!internal::tombstone_check_v || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) { if constexpr(is_applicable_v{}, stl::declval().get({})))>) { stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), dispatch_get(curr)...)); } else { stl::apply(func, stl::tuple_cat(dispatch_get(curr)...)); } } } } template void storage_if(Type *elem) noexcept { if(elem != nullptr) { storage>(*elem); } } public: /*! @brief Common type among all storage types. */ using common_type = base_type::common_type; /*! @brief Underlying entity identifier. */ using entity_type = base_type::entity_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Forward iterator type. */ using iterator = base_type::iterator; /*! @brief Iterable view type. */ using iterable = iterable_adaptor>; /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() noexcept : base_type{} {} /** * @brief Constructs a view from a set of storage classes. * @param value The storage for the types to iterate. * @param excl The storage for the types used to filter the view. */ basic_view(Get &...value, Exclude &...excl) noexcept : base_type{{&value...}, {&excl...}} { } /** * @brief Constructs a view from a set of storage classes. * @param value The storage for the types to iterate. * @param excl The storage for the types used to filter the view. */ basic_view(stl::tuple value, stl::tuple excl = {}) noexcept : basic_view{stl::make_from_tuple(stl::tuple_cat(value, excl))} {} /** * @brief Constructs a view from a convertible counterpart. * @tparam Args Storage types managed by the other view. * @param other A view to convert from. */ template requires (!stl::same_as>) basic_view(const basic_view &other) noexcept : basic_view{} { (storage_if(other.template storage()), ...); (storage_if(other.template storage()), ...); } /** * @brief Forces a view to use a given element to drive iterations * @tparam Type Type of element to use to drive iterations. */ template void use() noexcept { use>(); } /** * @brief Forces a view to use a given element to drive iterations * @tparam Index Index of the element to use to drive iterations. */ template void use() noexcept { base_type::use(Index); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { return storage>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { if constexpr(Index < sizeof...(Get)) { return static_cast *>(const_cast> *>(base_type::pool_at(Index))); } else { return static_cast *>(const_cast> *>(base_type::filter_at(Index - sizeof...(Get)))); } } /** * @brief Assigns a storage to a view. * @tparam Type Type of storage to assign to the view. * @param elem A storage to assign to the view. */ template void storage(Type &elem) noexcept { storage>(elem); } /** * @brief Assigns a storage to a view. * @tparam Index Index of the storage to assign to the view. * @tparam Type Type of storage to assign to the view. * @param elem A storage to assign to the view. */ template void storage(Type &elem) noexcept { static_assert(stl::is_convertible_v &>, "Unexpected type"); if constexpr(Index < sizeof...(Get)) { base_type::pool_at(Index, &elem); } else { base_type::filter_at(Index - sizeof...(Get), &elem); } } /** * @brief Returns the elements assigned to the given entity. * @param entt A valid identifier. * @return The elements assigned to the given entity. */ [[nodiscard]] decltype(auto) operator[](const entity_type entt) const { return get(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Type Type of the element to get. * @tparam Other Other types of elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { return get, index_of...>(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Index Indexes of the elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { if constexpr(sizeof...(Index) == 0) { return [this, entt](stl::index_sequence) { return stl::tuple_cat(this->storage()->get_as_tuple(entt)...); }(stl::index_sequence_for{}); } else if constexpr(sizeof...(Index) == 1) { return (storage()->get(entt), ...); } else { return stl::tuple_cat(storage()->get_as_tuple(entt)...); } } /** * @brief Iterates entities and elements and applies the given function * object to them. * * The signature of the function must be equivalent to one of the following * (non-empty types only, constness as requested): * * @code{.cpp} * void(const entity_type, Type &...); * void(Type &...); * @endcode * * @tparam Func Type of the function object to invoke. * @param func A valid function object. */ template void each(Func func) const { [this, &func](stl::index_sequence seq) { if(const auto *view = base_type::handle(); view != nullptr) { ((view == base_type::pool_at(Index) ? each(stl::move(func), seq) : void()), ...); } }(stl::index_sequence_for{}); } /** * @brief Returns an iterable object to use to _visit_ a view. * * The iterable object returns a tuple that contains the current entity and * a set of references to its non-empty elements. The _constness_ of the * elements is as requested. * * @return An iterable object to use to _visit_ the view. */ [[nodiscard]] iterable each() const noexcept { return iterable{base_type::begin(), base_type::end()}; } /** * @brief Combines a view and a storage in _more specific_ view. * @tparam OGet Type of storage to combine the view with. * @param other The storage for the type to combine the view with. * @return A more specific view. */ template OGet> [[nodiscard]] basic_view, exclude_t> operator|(OGet &other) const noexcept { return *this | basic_view, exclude_t<>>{other}; } /** * @brief Combines two views in a _more specific_ one. * @tparam OGet Element list of the view to combine with. * @tparam OExclude Filter list of the view to combine with. * @param other The view to combine with. * @return A more specific view. */ template... OGet, stl::derived_from... OExclude> [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { return internal::view_pack, exclude_t>>( *this, other, stl::index_sequence_for{}, stl::index_sequence_for{}, stl::index_sequence_for{}, stl::index_sequence_for{}); } }; /** * @brief Basic storage view implementation. * @warning For internal use only, backward compatibility not guaranteed. * @tparam Type Common type among all storage types. * @tparam Policy Storage policy. */ template class basic_storage_view { protected: /*! @cond ENTT_INTERNAL */ basic_storage_view() noexcept = default; basic_storage_view(const Type *value) noexcept : leading{value} { ENTT_ASSERT(leading->policy() == Policy, "Unexpected storage policy"); } /*! @endcond */ public: /*! @brief Common type among all storage types. */ using common_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = common_type::entity_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Random access iterator type. */ using iterator = stl::conditional_t, typename common_type::iterator>; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::conditional_t; /** * @brief Returns the leading storage of a view, if any. * @return The leading storage of the view. */ [[nodiscard]] const common_type *handle() const noexcept { return leading; } /** * @brief Returns the number of entities that have the given element. * @return Number of entities that have the given element. */ [[nodiscard]] size_type size() const noexcept requires (Policy != deletion_policy::in_place) { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->size() : size_type{}; } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return leading ? leading->free_list() : size_type{}; } } /** * @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 noexcept requires (Policy == deletion_policy::in_place) { return leading ? leading->size() : size_type{}; } /** * @brief Checks whether a view is empty. * @return True if the view is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept requires (Policy != deletion_policy::in_place) { if constexpr(Policy == deletion_policy::swap_and_pop) { return !leading || leading->empty(); } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return !leading || (leading->free_list() == 0u); } } /** * @brief Returns an iterator 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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->begin() : iterator{}; } else if constexpr(Policy == deletion_policy::swap_only) { return leading ? (leading->end() - static_cast(leading->free_list())) : iterator{}; } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); return leading ? iterator{leading->begin(), {leading}, {}, 0u} : iterator{}; } } /** * @brief Returns an iterator that is past the last entity of the view. * @return An iterator to the entity following the last entity of the view. */ [[nodiscard]] iterator end() const noexcept { if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) { return leading ? leading->end() : iterator{}; } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); return leading ? iterator{leading->end(), {leading}, {}, 0u} : iterator{}; } } /** * @brief Returns an iterator 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 noexcept requires (Policy != deletion_policy::in_place) { return leading ? leading->rbegin() : reverse_iterator{}; } /** * @brief Returns an iterator that is past the last entity of the reversed * view. * @return An iterator to the entity following the last entity of the * reversed view. */ [[nodiscard]] reverse_iterator rend() const noexcept requires (Policy != deletion_policy::in_place) { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->rend() : reverse_iterator{}; } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return leading ? (leading->rbegin() + static_cast(leading->free_list())) : reverse_iterator{}; } } /** * @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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop) { return empty() ? null : *leading->begin(); } else if constexpr(Policy == deletion_policy::swap_only) { return empty() ? null : *(leading->end() - static_cast(leading->free_list())); } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); const auto it = begin(); return (it == end()) ? null : *it; } } /** * @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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) { return empty() ? null : *leading->rbegin(); } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); if(leading) { auto it = leading->rbegin(); const auto last = leading->rend(); for(; (it != last) && (*it == tombstone); ++it) {} return it == last ? null : *it; } return null; } } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->find(entt) : iterator{}; } else if constexpr(Policy == deletion_policy::swap_only) { const auto it = leading ? leading->find(entt) : iterator{}; return leading && (static_cast(it.index()) < leading->free_list()) ? it : iterator{}; } else { return leading ? iterator{leading->find(entt), {leading}, {}, 0u} : iterator{}; } } /** * @brief Checks if a view is fully initialized. * @return True if the view is fully initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (leading != nullptr); } /** * @brief Checks if a view contains an entity. * @param entt A valid identifier. * @return True if the view contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::in_place) { return leading && leading->contains(entt); } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return leading && leading->contains(entt) && (leading->index(entt) < leading->free_list()); } } private: const common_type *leading{}; }; /** * @brief Storage view specialization. * * This specialization offers a boost in terms of performance. It can access the * underlying data structure directly and avoid superfluous checks. * * @sa basic_view * * @tparam Get Type of storage iterated by the view. */ template class basic_view, exclude_t<>> : public basic_storage_view { using base_type = basic_storage_view; void storage_if(Get *value) noexcept { if(value != nullptr) { storage(*value); } } public: /*! @brief Common type among all storage types. */ using common_type = base_type::common_type; /*! @brief Underlying entity identifier. */ using entity_type = base_type::entity_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Random access iterator type. */ using iterator = base_type::iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = base_type::reverse_iterator; /*! @brief Iterable view type. */ using iterable = stl::conditional_t>, decltype(stl::declval().each())>; /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() noexcept : base_type{} {} /** * @brief Constructs a view from a storage class. * @param value The storage for the type to iterate. */ basic_view(Get &value) noexcept : base_type{&value} { } /** * @brief Constructs a view from a storage class. * @param value The storage for the type to iterate. */ basic_view(stl::tuple value, stl::tuple<> = {}) noexcept : basic_view{stl::get<0>(value)} {} /** * @brief Constructs a view from a convertible counterpart. * @tparam Args Storage types managed by the other view. * @param other A view to convert from. */ template requires (!stl::same_as>) basic_view(const basic_view &other) noexcept : base_type{} { storage_if(other.template storage()); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { static_assert(stl::is_same_v, typename Get::element_type>, "Invalid element type"); return storage<0>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { static_assert(Index == 0u, "Index out of bounds"); return static_cast(const_cast *>(base_type::handle())); } /** * @brief Assigns a storage to a view. * @param elem A storage to assign to the view. */ void storage(Get &elem) noexcept { storage<0>(elem); } /** * @brief Assigns a storage to a view. * @tparam Index Index of the storage to assign to the view. * @param elem A storage to assign to the view. */ template void storage(Get &elem) noexcept { static_assert(Index == 0u, "Index out of bounds"); *this = basic_view{elem}; } /** * @brief Returns a pointer to the underlying storage. * @return A pointer to the underlying storage. */ [[nodiscard]] Get *operator->() const noexcept { return storage(); } /** * @brief Returns the element assigned to the given entity. * @param entt A valid identifier. * @return The element assigned to the given entity. */ [[nodiscard]] decltype(auto) operator[](const entity_type entt) const { return storage()->get(entt); } /** * @brief Returns the element assigned to the given entity. * @tparam Elem Type of the element to get. * @param entt A valid identifier. * @return The element assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { static_assert(stl::is_same_v, typename Get::element_type>, "Invalid element type"); return get<0>(entt); } /** * @brief Returns the element assigned to the given entity. * @tparam Index Index of the element to get. * @param entt A valid identifier. * @return The element assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { if constexpr(sizeof...(Index) == 0) { return storage()->get_as_tuple(entt); } else { return storage()->get(entt); } } /** * @brief Iterates entities and elements and applies the given function * object to them. * * The signature of the function must be equivalent to one of the following * (non-empty types only, constness as requested): * * @code{.cpp} * void(const entity_type, Type &); * void(Type &); * @endcode * * @tparam Func Type of the function object to invoke. * @param func A valid function object. */ template void each(Func func) const { if constexpr(is_applicable_v{}, stl::declval().get({})))>) { for(const auto pack: each()) { stl::apply(func, pack); } } else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) { if constexpr(stl::is_void_v) { for(size_type pos = base_type::size(); pos; --pos) { func(); } } else { if(const auto len = static_cast(base_type::size()); len != 0) { for(auto last = storage()->end(), first = last - len; first != last; ++first) { func(*first); } } } } else { static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy"); for(const auto pack: each()) { stl::apply([&func](const auto, auto &&...elem) { func(stl::forward(elem)...); }, pack); } } } /** * @brief Returns an iterable object to use to _visit_ a view. * * The iterable object returns a tuple that contains the current entity and * a reference to its element if it's a non-empty one. The _constness_ of * the element is as requested. * * @return An iterable object to use to _visit_ the view. */ [[nodiscard]] iterable each() const noexcept { if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) { return base_type::handle() ? storage()->each() : iterable{}; } else { static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy"); return iterable{base_type::begin(), base_type::end()}; } } /** * @brief Combines a view and a storage in _more specific_ view. * @tparam OGet Type of storage to combine the view with. * @param other The storage for the type to combine the view with. * @return A more specific view. */ template OGet> [[nodiscard]] basic_view, exclude_t<>> operator|(OGet &other) const noexcept { return *this | basic_view, exclude_t<>>{other}; } /** * @brief Combines two views in a _more specific_ one. * @tparam OGet Element list of the view to combine with. * @tparam OExclude Filter list of the view to combine with. * @param other The view to combine with. * @return A more specific view. */ template... OGet, stl::derived_from... OExclude> [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { return internal::view_pack, exclude_t>>( *this, other, stl::index_sequence_for{}, stl::index_sequence_for<>{}, stl::index_sequence_for{}, stl::index_sequence_for{}); } }; /** * @brief Deduction guide. * @tparam Type Type of storage classes used to create the view. * @param storage The storage for the types to iterate. */ template basic_view(Type &...storage) -> basic_view, exclude_t<>>; /** * @brief Deduction guide. * @tparam Get Types of elements iterated by the view. * @tparam Exclude Types of elements used to filter the view. */ template basic_view(stl::tuple, stl::tuple = {}) -> basic_view, exclude_t>; } // namespace entt #endif namespace entt { /** * @brief Converts a registry to a view. * @tparam Registry Basic registry type. */ template class as_view { template [[nodiscard]] auto dispatch(get_t, exclude_t) const { return reg->template view...>(exclude_t...>{}); } public: /*! @brief Type of registry to convert. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /** * @brief Constructs a converter for a given registry. * @param source A valid reference to a registry. */ as_view(registry_type &source) noexcept : reg{&source} {} /** * @brief Conversion function from a registry to a view. * @tparam Get Type of storage used to construct the view. * @tparam Exclude Types of storage used to filter the view. * @return A newly created view. */ template operator basic_view() const { return dispatch(Get{}, Exclude{}); } private: registry_type *reg; }; /** * @brief Converts a registry to a group. * @tparam Registry Basic registry type. */ template class as_group { template [[nodiscard]] auto dispatch(owned_t, get_t, exclude_t) const { if constexpr(stl::is_const_v) { return reg->template group_if_exists(get_t{}, exclude_t{}); } else { return reg->template group...>(get_t...>{}, exclude_t...>{}); } } public: /*! @brief Type of registry to convert. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /** * @brief Constructs a converter for a given registry. * @param source A valid reference to a registry. */ as_group(registry_type &source) noexcept : reg{&source} {} /** * @brief Conversion function from a registry to a group. * @tparam Owned Types of _owned_ by the group. * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. * @return A newly created group. */ template operator basic_group() const { return dispatch(Owned{}, Get{}, Exclude{}); } private: registry_type *reg; }; /** * @brief Helper to create a listener that directly invokes a member function. * @tparam Member Member function to invoke on an element of the given type. * @tparam Registry Basic registry type. * @param reg A registry that contains the given entity and its elements. * @param entt Entity from which to get the element. */ template>> void invoke(Registry ®, const typename Registry::entity_type entt) { static_assert(stl::is_member_function_pointer_v, "Invalid pointer to non-static member function"); (reg.template get>(entt).*Member)(reg, entt); } /** * @brief Returns the entity associated with a given element. * * @warning * Currently, this function only works correctly with the default storage as it * makes assumptions about how the elements are laid out. * * @tparam Args Storage type template parameters. * @param storage A storage that contains the given element. * @param instance A valid element instance. * @return The entity associated with the given element. */ template basic_storage::entity_type to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) { using traits_type = component_traits::value_type, typename basic_storage::entity_type>; static_assert(traits_type::page_size != 0u, "Unexpected page size"); const auto *page = storage.raw(); // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(stl::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) { if(const auto dist = (stl::addressof(instance) - *page); dist >= 0 && dist < static_cast(traits_type::page_size)) { return *(static_cast::base_type &>(storage).rbegin() + static_cast(pos) + dist); } } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) return null; } /*! @brief Primary template isn't defined on purpose. */ template struct sigh_helper; /** * @brief Signal connection helper for registries. * @tparam Registry Basic registry type. */ template struct sigh_helper { /*! @brief Registry type. */ using registry_type = Registry; /** * @brief Constructs a helper for a given registry. * @param ref A valid reference to a registry. */ sigh_helper(registry_type &ref) : bucket{&ref} {} /** * @brief Binds a properly initialized helper to a given signal type. * @tparam Type Type of signal to bind the helper to. * @param id Optional name for the underlying storage to use. * @return A helper for a given registry and signal type. */ template auto with(const id_type id = type_hash::value()) noexcept { return sigh_helper{*bucket, id}; } /** * @brief Returns a reference to the underlying registry. * @return A reference to the underlying registry. */ [[nodiscard]] registry_type ®istry() noexcept { return *bucket; } private: registry_type *bucket; }; /** * @brief Signal connection helper for registries. * @tparam Registry Basic registry type. * @tparam Type Type of signal to connect listeners to. */ template struct sigh_helper final: sigh_helper { /*! @brief Registry type. */ using registry_type = Registry; /** * @brief Constructs a helper for a given registry. * @param ref A valid reference to a registry. * @param id Optional name for the underlying storage to use. */ sigh_helper(registry_type &ref, const id_type id = type_hash::value()) : sigh_helper{ref}, name{id} {} /** * @brief Forwards the call to `on_construct` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_construct(Args &&...args) { this->registry().template on_construct(name).template connect(stl::forward(args)...); return *this; } /** * @brief Forwards the call to `on_update` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_update(Args &&...args) { this->registry().template on_update(name).template connect(stl::forward(args)...); return *this; } /** * @brief Forwards the call to `on_destroy` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_destroy(Args &&...args) { this->registry().template on_destroy(name).template connect(stl::forward(args)...); return *this; } private: id_type name; }; /** * @brief Deduction guide. * @tparam Registry Basic registry type. */ template sigh_helper(Registry &) -> sigh_helper; } // namespace entt #endif // #include "entity/mixin.hpp" #ifndef ENTT_ENTITY_MIXIN_HPP #define ENTT_ENTITY_MIXIN_HPP // #include "../config/config.h" // #include "../core/any.hpp" // #include "../core/type_info.hpp" // #include "../signal/sigh.hpp" #ifndef ENTT_SIGNAL_SIGH_HPP #define ENTT_SIGNAL_SIGH_HPP // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "delegate.hpp" #ifndef ENTT_SIGNAL_DELEGATE_HPP #define ENTT_SIGNAL_DELEGATE_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" #ifndef ENTT_SIGNAL_FWD_HPP #define ENTT_SIGNAL_FWD_HPP // #include "../stl/memory.hpp" namespace entt { template class delegate; template> class basic_dispatcher; template> class emitter; class connection; struct scoped_connection; template class sink; template> class sigh; /*! @brief Alias declaration for the most common use case. */ using dispatcher = basic_dispatcher<>; /*! @brief Disambiguation tag for constructors and the like. */ template struct connect_arg_t { /*! @brief Default constructor. */ explicit connect_arg_t() = default; }; /** * @brief Constant of type connect_arg_t used to disambiguate calls. * @tparam Candidate Element to connect (likely a free or member function). */ template inline constexpr connect_arg_t connect_arg{}; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ 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 requires stl::is_member_object_pointer_v auto function_pointer(Type Class::*, Other &&...) -> Type (*)(); template using function_pointer_t = decltype(function_pointer(stl::declval()...)); template [[nodiscard]] ENTT_CONSTEVAL auto index_sequence_for(Ret (*)(Args...)) { return stl::index_sequence_for{}; } } // namespace internal /*! @endcond */ /** * @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 { using return_type = stl::remove_const_t; using delegate_type = return_type(const void *, Args...); template [[nodiscard]] auto wrap(stl::index_sequence) noexcept { return [](const void *, Args... args) -> return_type { [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, stl::forward>>(stl::get(arguments))...)); }; } template [[nodiscard]] auto wrap(Type &, stl::index_sequence) noexcept { return [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, *curr, stl::forward>>(stl::get(arguments))...)); }; } template [[nodiscard]] auto wrap(Type *, stl::index_sequence) noexcept { return [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, curr, stl::forward>>(stl::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() noexcept = default; /** * @brief Constructs a delegate with a given object or payload, if any. * @tparam Candidate Function or member to connect to the delegate. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance Optional valid object that fits the purpose. */ template delegate(connect_arg_t, Type &&...value_or_instance) noexcept { connect(stl::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) 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() noexcept { instance = nullptr; if constexpr(stl::is_invocable_r_v) { fn = [](const void *, Args... args) -> return_type { return Ret(stl::invoke(Candidate, stl::forward(args)...)); }; } else if constexpr(stl::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) noexcept { instance = &value_or_instance; if constexpr(stl::is_invocable_r_v) { fn = [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); return Ret(stl::invoke(Candidate, *curr, stl::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) noexcept { instance = value_or_instance; if constexpr(stl::is_invocable_r_v) { fn = [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); return Ret(stl::invoke(Candidate, curr, stl::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) noexcept { ENTT_ASSERT(function != nullptr, "Uninitialized function pointer"); instance = payload; fn = function; } /** * @brief Resets a delegate. * * After a reset, a delegate cannot be invoked anymore. */ void reset() noexcept { instance = nullptr; fn = nullptr; } /** * @brief Returns a pointer to the stored callable function target, if any. * @return An opaque pointer to the stored callable function target. */ [[nodiscard]] function_type *target() const noexcept { return fn; } /** * @brief Returns the instance or the payload linked to a delegate, if any. * @return An opaque pointer to the underlying data. */ [[nodiscard]] const void *data() const noexcept { return instance; } /** * @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(instance, stl::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 noexcept { // no need to also test instance 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 noexcept { return fn == other.fn && instance == other.instance; } private: const void *instance{}; delegate_type *fn{}; }; /** * @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; } // namespace entt #endif // #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 Type A valid signal handler 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 Type A valid function type. * @tparam Allocator Type of allocator used to manage memory and elements. */ 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class sigh { friend class sink>; using alloc_traits = stl::allocator_traits; using delegate_type = delegate; using container_type = stl::vector>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Sink type. */ using sink_type = sink>; /*! @brief Default constructor. */ sigh() noexcept(noexcept(allocator_type{})) : sigh{allocator_type{}} {} /** * @brief Constructs a signal handler with a given allocator. * @param allocator The allocator to use. */ explicit sigh(const allocator_type &allocator) noexcept : calls{allocator} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ sigh(const sigh &other) : calls{other.calls} {} /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ sigh(const sigh &other, const allocator_type &allocator) : calls{other.calls, allocator} {} /** * @brief Move constructor. * @param other The instance to move from. */ sigh(sigh &&other) noexcept : calls{stl::move(other.calls)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ sigh(sigh &&other, const allocator_type &allocator) : calls{stl::move(other.calls), allocator} {} /*! @brief Default destructor. */ ~sigh() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This signal handler. */ sigh &operator=(const sigh &other) { calls = other.calls; return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This signal handler. */ sigh &operator=(sigh &&other) noexcept { swap(other); return *this; } /** * @brief Exchanges the contents with those of a given signal handler. * @param other Signal handler to exchange the content with. */ void swap(sigh &other) noexcept { using stl::swap; swap(calls, other.calls); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return calls.get_allocator(); } /** * @brief Number of listeners connected to the signal. * @return Number of listeners currently connected. */ [[nodiscard]] size_type size() const 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 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 pos = calls.size(); pos; --pos) { calls[pos - 1u](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 pos = calls.size(); pos; --pos) { if constexpr(stl::is_void_v || !stl::is_invocable_v) { calls[pos - 1u](args...); if constexpr(stl::is_invocable_r_v) { if(func()) { break; } } else { func(); } } else if constexpr(stl::is_invocable_r_v) { if(func(calls[pos - 1u](args...))) { break; } } else { func(calls[pos - 1u](args...)); } } } private: container_type calls; }; /** * @brief Connection class. * * Opaque object the aim of which is to allow users to release an already * established connection without having to keep a reference to the signal or * the sink that generated it. */ class connection { template friend class sink; connection(delegate fn, void *ref) : disconnect{fn}, signal{ref} {} public: /*! @brief Default constructor. */ connection() : signal{} {} /** * @brief Checks whether a connection is properly initialized. * @return True if the connection is properly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const 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 * established 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 Move constructor. * @param other The scoped connection to move from. */ scoped_connection(scoped_connection &&other) noexcept : conn{stl::exchange(other.conn, {})} {} /*! @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 Move assignment operator. * @param other The scoped connection to move from. * @return This scoped connection. */ scoped_connection &operator=(scoped_connection &&other) noexcept { conn = stl::exchange(other.conn, {}); return *this; } /** * @brief Acquires a connection. * @param other The connection object to acquire. * @return This scoped connection. */ scoped_connection &operator=(connection other) { conn = 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 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class sink> { using signal_type = sigh; using delegate_type = signal_type::delegate_type; using difference_type = signal_type::container_type::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(); } template void disconnect_if(Func callback) { auto &ref = signal_or_assert(); for(auto pos = ref.calls.size(); pos; --pos) { if(auto &elem = ref.calls[pos - 1u]; callback(elem)) { elem = stl::move(ref.calls.back()); ref.calls.pop_back(); } } } [[nodiscard]] auto &signal_or_assert() const noexcept { ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal"); return *signal; } public: /*! @brief Constructs an invalid sink. */ sink() noexcept : signal{} {} /** * @brief Constructs a sink that is allowed to modify a given signal. * @param ref A valid reference to a signal object. */ sink(sigh &ref) noexcept : 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 noexcept { return signal_or_assert().calls.empty(); } /** * @brief Connects a free function or an unbound member to a signal. * @tparam Candidate Function or member to connect to the signal. * @return A properly initialized connection object. */ template connection connect() { disconnect(); delegate_type call{}; call.template connect(); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(); return {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.
* 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 reference that fits the purpose. * @return A properly initialized connection object. */ template connection connect(Type &value_or_instance) { disconnect(value_or_instance); delegate_type call{}; call.template connect(value_or_instance); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(value_or_instance); return {conn, signal}; } /** * @brief Connects a free function with payload or a bound member to a * signal. * * @sa connect(Type &) * * @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 pointer that fits the purpose. * @return A properly initialized connection object. */ template connection connect(Type *value_or_instance) { disconnect(value_or_instance); delegate_type call{}; call.template connect(value_or_instance); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(value_or_instance); return {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() { delegate_type call{}; call.template connect(); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects a free function with payload or a bound member from 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.
* 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 disconnect from the signal. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance A valid reference that fits the purpose. */ template void disconnect(Type &value_or_instance) { delegate_type call{}; call.template connect(value_or_instance); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects a free function with payload or a bound member from a * signal. * * @sa disconnect(Type &) * * @tparam Candidate Function or member to disconnect from the signal. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance A valid pointer that fits the purpose. */ template void disconnect(Type *value_or_instance) { delegate_type call{}; call.template connect(value_or_instance); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects free functions with payload or bound members from a * signal. * @param value_or_instance A valid object that fits the purpose. */ void disconnect(const void *value_or_instance) { ENTT_ASSERT(value_or_instance != nullptr, "Invalid value or instance"); disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; }); } /*! @brief Disconnects all the listeners from a signal. */ void disconnect() { signal_or_assert().calls.clear(); } /** * @brief Returns true if a sink is correctly initialized, false otherwise. * @return True if a sink is correctly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return signal != nullptr; } private: signal_type *signal; }; /** * @brief Deduction guide. * * It allows to deduce the signal handler 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template sink(sigh &) -> sink>; } // namespace entt #endif // #include "../stl/concepts.hpp" // #include "../stl/iterator.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_on_construct final: stl::false_type {}; template requires stl::invocable struct has_on_construct: stl::true_type {}; template struct has_on_update final: stl::false_type {}; template requires stl::invocable struct has_on_update: stl::true_type {}; template struct has_on_destroy final: stl::false_type {}; template requires stl::invocable struct has_on_destroy: stl::true_type {}; } // namespace internal /*! @endcond */ /** * @brief Mixin type used to add signal support to storage types. * * The function type of a listener is equivalent to: * * @code{.cpp} * void(basic_registry &, entity_type); * @endcode * * This applies to all signals made available. * * @tparam Type Underlying storage type. * @tparam Registry Basic registry type. */ template class basic_sigh_mixin final: public Type { using underlying_type = Type; using owner_type = Registry; using basic_registry_type = basic_registry; using sigh_type = sigh; using underlying_iterator = underlying_type::base_type::basic_iterator; static_assert(stl::is_base_of_v, "Invalid registry type"); [[nodiscard]] auto &owner_or_assert() const noexcept { ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); return static_cast(*owner); } private: void pop(underlying_iterator first, underlying_iterator last) final { if(auto ® = owner_or_assert(); destruction.empty()) { underlying_type::pop(first, last); } else { for(; first != last; ++first) { const auto entt = *first; destruction.publish(reg, entt); const auto it = underlying_type::find(entt); underlying_type::pop(it, it + 1u); } } } void pop_all() final { if(auto ® = owner_or_assert(); !destruction.empty()) { if constexpr(stl::is_same_v) { for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) { destruction.publish(reg, underlying_type::base_type::operator[](pos)); } } else { for(auto entt: static_cast(*this)) { if constexpr(underlying_type::storage_policy == deletion_policy::in_place) { if(entt != tombstone) { destruction.publish(reg, entt); } } else { destruction.publish(reg, entt); } } } } underlying_type::pop_all(); } underlying_iterator try_emplace(const underlying_type::entity_type entt, const bool force_back, const void *value) final { const auto it = underlying_type::try_emplace(entt, force_back, value); if(auto ® = owner_or_assert(); it != underlying_type::base_type::end()) { construction.publish(reg, *it); } return it; } void bind_any(any value) noexcept final { owner = any_cast(&value); if constexpr(!stl::is_same_v) { if(owner == nullptr) { owner = any_cast(&value); } } underlying_type::bind_any(stl::move(value)); } public: /*! @brief Allocator type. */ using allocator_type = underlying_type::allocator_type; /*! @brief Underlying entity identifier. */ using entity_type = underlying_type::entity_type; /*! @brief Expected registry type. */ using registry_type = owner_type; /*! @brief Default constructor. */ basic_sigh_mixin() : basic_sigh_mixin{allocator_type{}} {} /** * @brief Constructs an empty storage with a given allocator. * @param allocator The allocator to use. */ explicit basic_sigh_mixin(const allocator_type &allocator) : underlying_type{allocator}, owner{}, construction{allocator}, destruction{allocator}, update{allocator} { if constexpr(internal::has_on_construct::value) { sink{construction}.template connect<&underlying_type::element_type::on_construct>(); } if constexpr(internal::has_on_update::value) { sink{update}.template connect<&underlying_type::element_type::on_update>(); } if constexpr(internal::has_on_destroy::value) { sink{destruction}.template connect<&underlying_type::element_type::on_destroy>(); } } /*! @brief Default copy constructor, deleted on purpose. */ basic_sigh_mixin(const basic_sigh_mixin &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_sigh_mixin(basic_sigh_mixin &&other) noexcept : underlying_type{static_cast(other)}, owner{other.owner}, construction{stl::move(other.construction)}, destruction{stl::move(other.destruction)}, update{stl::move(other.update)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) : underlying_type{static_cast(other), allocator}, owner{other.owner}, construction{stl::move(other.construction), allocator}, destruction{stl::move(other.destruction), allocator}, update{stl::move(other.update), allocator} {} /*! @brief Default destructor. */ ~basic_sigh_mixin() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This mixin. */ basic_sigh_mixin &operator=(const basic_sigh_mixin &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This mixin. */ basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept { swap(other); return *this; } /** * @brief Exchanges the contents with those of a given storage. * @param other Storage to exchange the content with. */ void swap(basic_sigh_mixin &other) noexcept { using stl::swap; swap(owner, other.owner); swap(construction, other.construction); swap(destruction, other.destruction); swap(update, other.update); underlying_type::swap(other); } /** * @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.
* Listeners are invoked after the object has been assigned to the entity. * * @sa sink * * @return A temporary sink object. */ [[nodiscard]] auto on_construct() 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.
* Listeners are invoked after the object has been updated. * * @sa sink * * @return A temporary sink object. */ [[nodiscard]] auto on_update() 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.
* Listeners are invoked before the object has been removed from the entity. * * @sa sink * * @return A temporary sink object. */ [[nodiscard]] auto on_destroy() noexcept { return sink{destruction}; } /** * @brief Checks if a mixin refers to a valid registry. * @return True if the mixin refers to a valid registry, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (owner != nullptr); } /** * @brief Returns a pointer to the underlying registry, if any. * @return A pointer to the underlying registry, if any. */ [[nodiscard]] const registry_type ®istry() const noexcept { return owner_or_assert(); } /*! @copydoc registry */ [[nodiscard]] registry_type ®istry() noexcept { return owner_or_assert(); } /** * @brief Creates a new identifier or recycles a destroyed one. * @return A valid identifier. */ auto generate() { const auto entt = underlying_type::generate(); construction.publish(owner_or_assert(), entt); return entt; } /** * @brief Creates a new identifier or recycles a destroyed one. * @param hint Required identifier. * @return A valid identifier. */ entity_type generate(const entity_type hint) { const auto entt = underlying_type::generate(hint); construction.publish(owner_or_assert(), entt); return entt; } /** * @brief Assigns each element in a range an identifier. * @tparam It Type of output 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 It> void generate(It first, It last) { underlying_type::generate(first, last); if(auto ® = owner_or_assert(); !construction.empty()) { for(; first != last; ++first) { construction.publish(reg, *first); } } } /** * @brief Assigns an entity to a storage and constructs its object. * @tparam Args Types of arguments to forward to the underlying storage. * @param entt A valid identifier. * @param args Parameters to forward to the underlying storage. * @return A reference to the newly created object. */ template decltype(auto) emplace(const entity_type entt, Args &&...args) { underlying_type::emplace(entt, stl::forward(args)...); construction.publish(owner_or_assert(), entt); return this->get(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 identifier. * @param func Valid function objects. * @return A reference to the patched instance. */ template decltype(auto) patch(const entity_type entt, Func &&...func) { underlying_type::patch(entt, stl::forward(func)...); update.publish(owner_or_assert(), entt); return this->get(entt); } /** * @brief Assigns one or more entities to a storage and constructs their * objects from a given instance. * @tparam Args Types of arguments to forward to the underlying storage. * @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 forward to the underlying storage. */ template void insert(stl::input_iterator auto first, stl::input_iterator auto last, Args &&...args) { auto from = underlying_type::size(); underlying_type::insert(first, last, stl::forward(args)...); if(auto ® = owner_or_assert(); !construction.empty()) { // fine as long as insert passes force_back true to try_emplace for(const auto to = underlying_type::size(); from != to; ++from) { construction.publish(reg, underlying_type::operator[](from)); } } } private: basic_registry_type *owner; sigh_type construction; sigh_type destruction; sigh_type update; }; /** * @brief Mixin type used to add _reactive_ support to storage types. * @tparam Type Underlying storage type. * @tparam Registry Basic registry type. */ template class basic_reactive_mixin final: public Type { using underlying_type = Type; using owner_type = Registry; using alloc_traits = stl::allocator_traits; using basic_registry_type = basic_registry; using container_type = stl::vector>; static_assert(stl::is_base_of_v, "Invalid registry type"); [[nodiscard]] auto &owner_or_assert() const noexcept { ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); return static_cast(*owner); } void emplace_element(const Registry &, underlying_type::entity_type entity) { if(!underlying_type::contains(entity)) { underlying_type::emplace(entity); } } private: void bind_any(any value) noexcept final { owner = any_cast(&value); if constexpr(!stl::is_same_v) { if(owner == nullptr) { owner = any_cast(&value); } } underlying_type::bind_any(stl::move(value)); } public: /*! @brief Allocator type. */ using allocator_type = underlying_type::allocator_type; /*! @brief Underlying entity identifier. */ using entity_type = underlying_type::entity_type; /*! @brief Expected registry type. */ using registry_type = owner_type; /*! @brief Default constructor. */ basic_reactive_mixin() : basic_reactive_mixin{allocator_type{}} {} /** * @brief Constructs an empty storage with a given allocator. * @param allocator The allocator to use. */ explicit basic_reactive_mixin(const allocator_type &allocator) : underlying_type{allocator}, owner{}, conn{allocator} { } /*! @brief Default copy constructor, deleted on purpose. */ basic_reactive_mixin(const basic_reactive_mixin &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_reactive_mixin(basic_reactive_mixin &&other) noexcept : underlying_type{static_cast(other)}, owner{other.owner}, conn{stl::move(other.conn)} { } /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator) : underlying_type{static_cast(other), allocator}, owner{other.owner}, conn{stl::move(other.conn), allocator} { } /*! @brief Default destructor. */ ~basic_reactive_mixin() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This mixin. */ basic_reactive_mixin &operator=(const basic_reactive_mixin &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This mixin. */ basic_reactive_mixin &operator=(basic_reactive_mixin &&other) noexcept { underlying_type::swap(other); return *this; } /** * @brief Makes storage _react_ to creation of objects of the given type. * @tparam Clazz Type of element to _react_ to. * @tparam Candidate Function to use to _react_ to the event. * @param id Optional name used to map the storage within the registry. * @return This mixin. */ template basic_reactive_mixin &on_construct(const id_type id = type_hash::value()) { auto curr = owner_or_assert().template storage(id).on_construct().template connect(*this); conn.push_back(stl::move(curr)); return *this; } /** * @brief Makes storage _react_ to update of objects of the given type. * @tparam Clazz Type of element to _react_ to. * @tparam Candidate Function to use to _react_ to the event. * @param id Optional name used to map the storage within the registry. * @return This mixin. */ template basic_reactive_mixin &on_update(const id_type id = type_hash::value()) { auto curr = owner_or_assert().template storage(id).on_update().template connect(*this); conn.push_back(stl::move(curr)); return *this; } /** * @brief Makes storage _react_ to destruction of objects of the given type. * @tparam Clazz Type of element to _react_ to. * @tparam Candidate Function to use to _react_ to the event. * @param id Optional name used to map the storage within the registry. * @return This mixin. */ template basic_reactive_mixin &on_destroy(const id_type id = type_hash::value()) { auto curr = owner_or_assert().template storage(id).on_destroy().template connect(*this); conn.push_back(stl::move(curr)); return *this; } /** * @brief Checks if a mixin refers to a valid registry. * @return True if the mixin refers to a valid registry, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (owner != nullptr); } /** * @brief Returns a pointer to the underlying registry, if any. * @return A pointer to the underlying registry, if any. */ [[nodiscard]] const registry_type ®istry() const noexcept { return owner_or_assert(); } /*! @copydoc registry */ [[nodiscard]] registry_type ®istry() noexcept { return owner_or_assert(); } /** * @brief Returns a view that is filtered by the underlying storage. * @tparam Get Types of elements used to construct the view. * @tparam Exclude Types of elements used to filter the view. * @return A newly created view. */ template [[nodiscard]] basic_view...>, exclude_t...>> view(exclude_t = exclude_t{}) const { const owner_type &parent = owner_or_assert(); basic_view...>, exclude_t...>> elem{}; [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage>()..., parent.template storage>()..., this); return elem; } /*! @copydoc view */ template [[nodiscard]] basic_view...>, exclude_t...>> view(exclude_t = exclude_t{}) { stl::conditional_t<((stl::is_const_v && ...) && (stl::is_const_v && ...)), const owner_type, owner_type> &parent = owner_or_assert(); return {*this, parent.template storage>()..., parent.template storage>()...}; } /*! @brief Releases all connections to the underlying registry, if any. */ void reset() { for(auto &&curr: conn) { curr.release(); } conn.clear(); } private: basic_registry_type *owner; container_type conn; }; } // namespace entt #endif // #include "entity/organizer.hpp" #ifndef ENTT_ENTITY_ORGANIZER_HPP #define ENTT_ENTITY_ORGANIZER_HPP // #include "../core/type_info.hpp" // #include "../core/type_traits.hpp" // #include "../core/utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @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) 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) 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. */ constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) : func{stl::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 constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } private: Func func; }; } // namespace entt #endif // #include "../graph/adjacency_matrix.hpp" #ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP #define ENTT_GRAPH_ADJACENCY_MATRIX_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_GRAPH_FWD_HPP #define ENTT_GRAPH_FWD_HPP // #include "../core/fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" namespace entt { /*! @brief Undirected graph category tag. */ struct directed_tag {}; /*! @brief Directed graph category tag. */ struct undirected_tag: directed_tag {}; template, typename = stl::allocator> class adjacency_matrix; template> class basic_flow; /*! @brief Alias declaration for the most common use case. */ using flow = basic_flow<>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class edge_iterator { using size_type = stl::size_t; void find_next() noexcept { for(; pos != last && !it[static_cast(pos)]; pos += offset) {} } public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr edge_iterator() noexcept = default; // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept : it{stl::move(base)}, vert{vertices}, pos{from}, last{to}, offset{step} { find_next(); } constexpr edge_iterator &operator++() noexcept { pos += offset; find_next(); return *this; } constexpr edge_iterator operator++(int) noexcept { const edge_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr reference operator*() const noexcept { return *operator->(); } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::make_pair(pos / vert, pos % vert); } [[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept { return pos == other.pos; } private: It it{}; size_type vert{}; size_type pos{}; size_type last{}; size_type offset{}; }; } // namespace internal /*! @endcond */ /** * @brief Basic implementation of a directed adjacency matrix. * @tparam Category Either a directed or undirected category tag. * @tparam Allocator Type of allocator used to manage memory and elements. */ template Category, typename Allocator> class adjacency_matrix { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_type = stl::vector>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Vertex type. */ using vertex_type = size_type; /*! @brief Edge type. */ using edge_type = stl::pair; /*! @brief Vertex iterator type. */ using vertex_iterator = iota_iterator; /*! @brief Edge iterator type. */ using edge_iterator = internal::edge_iterator; /*! @brief Out-edge iterator type. */ using out_edge_iterator = edge_iterator; /*! @brief In-edge iterator type. */ using in_edge_iterator = edge_iterator; /*! @brief Graph category tag. */ using graph_category = Category; /*! @brief Default constructor. */ adjacency_matrix() noexcept(noexcept(allocator_type{})) : adjacency_matrix{0u} { } /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit adjacency_matrix(const allocator_type &allocator) noexcept : adjacency_matrix{0u, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied number of vertices. * @param vertices Number of vertices. * @param allocator The allocator to use. */ adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{}) : matrix{vertices * vertices, allocator}, vert{vertices} {} /*! @brief Default copy constructor. */ adjacency_matrix(const adjacency_matrix &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator) : matrix{other.matrix, allocator}, vert{other.vert} {} /*! @brief Default move constructor. */ adjacency_matrix(adjacency_matrix &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator) : matrix{stl::move(other.matrix), allocator}, vert{other.vert} {} /*! @brief Default destructor. */ ~adjacency_matrix() = default; /** * @brief Default copy assignment operator. * @return This container. */ adjacency_matrix &operator=(const adjacency_matrix &) = default; /** * @brief Default move assignment operator. * @return This container. */ adjacency_matrix &operator=(adjacency_matrix &&) noexcept = default; /** * @brief Exchanges the contents with those of a given adjacency matrix. * @param other Adjacency matrix to exchange the content with. */ void swap(adjacency_matrix &other) noexcept { using stl::swap; swap(matrix, other.matrix); swap(vert, other.vert); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return matrix.get_allocator(); } /*! @brief Clears the adjacency matrix. */ void clear() noexcept { matrix.clear(); vert = {}; } /** * @brief Returns true if an adjacency matrix is empty, false otherwise. * * @warning * Potentially expensive, try to avoid it on hot paths. * * @return True if the adjacency matrix is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { const auto iterable = edges(); return (iterable.begin() == iterable.end()); } /** * @brief Returns the number of vertices. * @return The number of vertices. */ [[nodiscard]] size_type size() const noexcept { return vert; } /** * @brief Returns an iterable object to visit all vertices of a matrix. * @return An iterable object to visit all vertices of a matrix. */ [[nodiscard]] iterable_adaptor vertices() const noexcept { return {0u, vert}; } /** * @brief Returns an iterable object to visit all edges of a matrix. * @return An iterable object to visit all edges of a matrix. */ [[nodiscard]] iterable_adaptor edges() const noexcept { const auto it = matrix.cbegin(); const auto sz = matrix.size(); return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}}; } /** * @brief Returns an iterable object to visit all out-edges of a vertex. * @param vertex The vertex of which to return all out-edges. * @return An iterable object to visit all out-edges of a vertex. */ [[nodiscard]] iterable_adaptor out_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex * vert; const auto to = from + vert; return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}}; } /** * @brief Returns an iterable object to visit all in-edges of a vertex. * @param vertex The vertex of which to return all in-edges. * @return An iterable object to visit all in-edges of a vertex. */ [[nodiscard]] iterable_adaptor in_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex; const auto to = vert * vert + from; return {{it, vert, from, to, vert}, {it, vert, to, to, vert}}; } /** * @brief Resizes an adjacency matrix. * @param vertices The new number of vertices. */ void resize(const size_type vertices) { adjacency_matrix other{vertices, get_allocator()}; for(auto [lhs, rhs]: edges()) { other.insert(lhs, rhs); } other.swap(*this); } /** * @brief Inserts an edge into the adjacency matrix, if it does not exist. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 1u; } const auto inserted = !stl::exchange(matrix[pos], 1u); return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted}; } /** * @brief Removes the edge associated with a pair of given vertices. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return Number of elements removed (either 0 or 1). */ size_type erase(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 0u; } return stl::exchange(matrix[pos], 0u); } /** * @brief Checks if an adjacency matrix contains a given edge. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return True if there is such an edge, false otherwise. */ [[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const { const auto pos = lhs * vert + rhs; return pos < matrix.size() && matrix[pos]; } private: container_type matrix; size_type vert; }; } // namespace entt #endif // #include "../graph/flow.hpp" #ifndef ENTT_GRAPH_FLOW_HPP #define ENTT_GRAPH_FLOW_HPP // #include "../config/config.h" // #include "../container/dense_map.hpp" #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" namespace entt { template< typename Key, typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator>> class dense_map; template< typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator> class dense_set; template class basic_table; /** * @brief Alias declaration for the most common use case. * @tparam Type Element types. */ template using table = basic_table...>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { using value_type = stl::pair; template dense_map_node(const stl::size_t pos, Args &&...args) : next{pos}, element{stl::forward(args)...} {} template dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) : next{pos}, element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, other.element)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} stl::size_t next; value_type element; }; template class dense_map_iterator final { template friend class dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr dense_map_iterator() noexcept : it{} {} constexpr dense_map_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_iterator(const dense_map_iterator &other) noexcept : it{other.it} {} constexpr dense_map_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_map_iterator operator++(int) noexcept { const dense_map_iterator orig = *this; return ++(*this), orig; } constexpr dense_map_iterator &operator--() noexcept { return --it, *this; } constexpr dense_map_iterator operator--(int) noexcept { const dense_map_iterator orig = *this; return operator--(), orig; } constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_map_iterator operator+(const difference_type value) const noexcept { dense_map_iterator copy = *this; return (copy += value); } constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_map_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].element.first, it[value].element.second}; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_map_local_iterator final { template friend class dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr dense_map_local_iterator() noexcept = default; constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_map_local_iterator &operator++() noexcept { return (offset = it[static_cast(offset)].next), *this; } constexpr dense_map_local_iterator operator++(int) noexcept { const dense_map_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { const auto idx = static_cast(offset); return {it[idx].element.first, it[idx].element.second}; } template [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_map_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for key-value pairs with unique keys. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on the hash of its key. Keys with the same hash * code appear in the same bucket. * * @tparam Key Key type of the associative container. * @tparam Type Mapped type of the associative container. * @tparam Hash Type of function to use to hash the keys. * @tparam KeyEqual Type of function to use to compare the keys for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_map { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; using node_type = internal::dense_map_node; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v>, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) return fast_mod(static_cast(sparse.second()(key)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } template [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { it->second = stl::forward(value); return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].next) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Key; /*! @brief Mapped type of the container. */ using mapped_type = Type; /*! @brief Key-value type of the container. */ using value_type = stl::pair; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the keys. */ using hasher = Hash; /*! @brief Type of function to use to compare the keys for equality. */ using key_equal = KeyEqual; /*! @brief Input iterator type. */ using iterator = internal::dense_map_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::dense_map_iterator; /*! @brief Input iterator type. */ using local_iterator = internal::dense_map_local_iterator; /*! @brief Constant input iterator type. */ using const_local_iterator = internal::dense_map_local_iterator; /*! @brief Default constructor. */ dense_map() : dense_map{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_map(const allocator_type &allocator) : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const allocator_type &allocator) : dense_map{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_map{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_map(const dense_map &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_map(const dense_map &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_map(dense_map &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_map(dense_map &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_map() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_map &operator=(const dense_map &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_map &operator=(dense_map &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_map &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if the key does not exist. * @param value A key-value pair eventually convertible to the value type. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value.first, value.second); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); } /** * @copydoc insert * @tparam Arg Type of the key-value pair to insert into the container. */ template requires stl::constructible_from stl::pair insert(Arg &&value) { return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); } /** * @brief Inserts elements into the container, if their keys do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Inserts an element into the container or assigns to the current * element if the key already exists. * @tparam Arg Type of the value to insert or assign. * @param key A key used both to look up and to insert if not found. * @param value A value to insert or assign. * @return A pair consisting of an iterator to the element and a bool * denoting whether the insertion took place. */ template stl::pair insert_or_assign(const key_type &key, Arg &&value) { return insert_or_overwrite(key, stl::forward(value)); } /*! @copydoc insert_or_assign */ template stl::pair insert_or_assign(key_type &&key, Arg &&value) { return insert_or_overwrite(stl::move(key), stl::forward(value)); } /** * @brief Constructs an element in-place, if the key does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace([[maybe_unused]] Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return insert_or_do_nothing(key_type{}); } else if constexpr(sizeof...(Args) == 1u) { return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); } else if constexpr(sizeof...(Args) == 2u) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); const auto index = key_to_bucket(node.element.first); if(auto it = constrained_find(node.element.first, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.next, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Inserts in-place if the key does not exist, does nothing if the * key exists. * @tparam Args Types of arguments to forward to the constructor of the * element. * @param key A key used both to look up and to insert if not found. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair try_emplace(const key_type &key, Args &&...args) { return insert_or_do_nothing(key, stl::forward(args)...); } /*! @copydoc try_emplace */ template stl::pair try_emplace(key_type &&key, Args &&...args) { return insert_or_do_nothing(stl::move(key), stl::forward(args)...); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(pos->first); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].element.first); } return (begin() + dist); } /** * @brief Removes the element associated with a given key. * @param key A key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const key_type &key) { for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { if(packed.second()(packed.first()[*curr].element.first, key)) { const auto index = *curr; *curr = packed.first()[*curr].next; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &at(const key_type &key) { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] const mapped_type &at(const key_type &key) const { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type const &at(const auto &key) const requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] mapped_type &at(const auto &key) requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](const key_type &key) { return insert_or_do_nothing(key).first->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](key_type &&key) { return insert_or_do_nothing(stl::move(key)).first->second; } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const key_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const key_type &key) { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const key_type &key) const { return constrained_find(key, key_to_bucket(key)); } /** * @brief Finds an element with a key that compares _equivalent_ to a given * key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &key) requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &key) const requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /** * @brief Returns a range containing all elements with a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const key_type &key) { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const key_type &key) const { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &key) requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &key) const requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given key. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const key_type &key) const { return (find(key) != cend()); } /** * @brief Checks if the container contains an element with a key that * compares _equivalent_ to a given value. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &key) const requires is_transparent_v && is_transparent_v { return (find(key) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given key. * @param key The value of the key to examine. * @return The bucket for the given key. */ [[nodiscard]] size_type bucket(const key_type &key) const { return key_to_bucket(key); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = key_to_bucket(packed.first()[pos].element.first); packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the keys. * @return The function used to hash the keys. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare keys for equality. * @return The function used to compare keys for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::true_type {}; } // namespace std /*! @endcond */ #endif // #include "../container/dense_set.hpp" #ifndef ENTT_CONTAINER_DENSE_SET_HPP #define ENTT_CONTAINER_DENSE_SET_HPP #include // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../core/compressed_pair.hpp" // #include "../core/type_traits.hpp" // #include "../stl/bit.hpp" // #include "../stl/cmath.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" // #include "../stl/iterator.hpp" // #include "../stl/limits.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits::max)(); template class dense_set_iterator final { template friend class dense_set_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); public: using value_type = stl::remove_const_t>::second_type; using pointer = const value_type *; using reference = const value_type &; using difference_type = stl::ptrdiff_t; using iterator_category = stl::random_access_iterator_tag; constexpr dense_set_iterator() noexcept : it{} {} constexpr dense_set_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_set_iterator(const dense_set_iterator &other) noexcept : it{other.it} {} constexpr dense_set_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_set_iterator operator++(int) noexcept { const dense_set_iterator orig = *this; return ++(*this), orig; } constexpr dense_set_iterator &operator--() noexcept { return --it, *this; } constexpr dense_set_iterator operator--(int) noexcept { const dense_set_iterator orig = *this; return operator--(), orig; } constexpr dense_set_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_set_iterator operator+(const difference_type value) const noexcept { dense_set_iterator copy = *this; return (copy += value); } constexpr dense_set_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_set_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return it[value].second; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(operator[](0)); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_set_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_set_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_set_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_set_local_iterator final { template friend class dense_set_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); public: using value_type = stl::remove_const_t>::second_type; using pointer = const value_type *; using reference = const value_type &; using difference_type = stl::ptrdiff_t; using iterator_category = stl::forward_iterator_tag; constexpr dense_set_local_iterator() noexcept = default; constexpr dense_set_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_set_local_iterator(const dense_set_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_set_local_iterator &operator++() noexcept { return offset = it[static_cast(offset)].first, *this; } constexpr dense_set_local_iterator operator++(int) noexcept { const dense_set_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(it[static_cast(offset)].second); } [[nodiscard]] constexpr reference operator*() const noexcept { return *operator->(); } template [[nodiscard]] constexpr bool operator==(const dense_set_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_set_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for unique objects of a given type. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on its hash. Elements with the same hash code * appear in the same bucket. * * @tparam Type Value type of the associative container. * @tparam Hash Type of function to use to hash the values. * @tparam KeyEqual Type of function to use to compare the values for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_set { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_set_placeholder_position; using node_type = stl::pair; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t value_to_bucket(const auto &value) const noexcept { return fast_mod(static_cast(sparse.second()(value)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { if(packed.second()(packed.first()[offset].second, value)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { if(packed.second()(packed.first()[offset].second, value)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&value) { const auto index = value_to_bucket(value); if(auto it = constrained_find(value, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[value_to_bucket(packed.first().back().second)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].first) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Type; /*! @brief Value type of the container. */ using value_type = Type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the elements. */ using hasher = Hash; /*! @brief Type of function to use to compare the elements for equality. */ using key_equal = KeyEqual; /*! @brief Random access iterator type. */ using iterator = internal::dense_set_iterator; /*! @brief Constant random access iterator type. */ using const_iterator = internal::dense_set_iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = stl::reverse_iterator; /*! @brief Forward iterator type. */ using local_iterator = internal::dense_set_local_iterator; /*! @brief Constant forward iterator type. */ using const_local_iterator = internal::dense_set_local_iterator; /*! @brief Default constructor. */ dense_set() : dense_set{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_set(const allocator_type &allocator) : dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_set(const size_type cnt, const allocator_type &allocator) : dense_set{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_set{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_set(const dense_set &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_set(const dense_set &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_set(dense_set &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_set(dense_set &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_set() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_set &operator=(const dense_set &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_set &operator=(dense_set &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_set &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Returns a reverse iterator to the beginning. * * If the array 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 noexcept { return stl::make_reverse_iterator(cend()); } /*! @copydoc crbegin */ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @copydoc rbegin */ [[nodiscard]] reverse_iterator rbegin() noexcept { return stl::make_reverse_iterator(end()); } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last instance of the * reversed internal array. */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return stl::make_reverse_iterator(cbegin()); } /*! @copydoc crend */ [[nodiscard]] const_reverse_iterator rend() const noexcept { return crend(); } /*! @copydoc rend */ [[nodiscard]] reverse_iterator rend() noexcept { return stl::make_reverse_iterator(begin()); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if it does not exist. * @param value An element to insert into the container. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value)); } /** * @brief Inserts elements into the container, if they do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Constructs an element in-place, if it does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace(Args &&...args) { if constexpr(((sizeof...(Args) == 1u) && ... && stl::is_same_v, value_type>)) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(stl::piecewise_construct, stl::make_tuple(packed.first().size()), stl::forward_as_tuple(stl::forward(args)...)); const auto index = value_to_bucket(node.second); if(auto it = constrained_find(node.second, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.first, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(*pos); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].second); } return (begin() + dist); } /** * @brief Removes the element associated with a given value. * @param value Value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const value_type &value) { for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != placeholder_position; curr = &packed.first()[*curr].first) { if(packed.second()(packed.first()[*curr].second, value)) { const auto index = *curr; *curr = packed.first()[*curr].first; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Returns the number of elements matching a value (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const value_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given value. * @param value Value of an element to search for. * @return An iterator to an element with the given value. If no such * element is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const value_type &value) { return constrained_find(value, value_to_bucket(value)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const value_type &value) const { return constrained_find(value, value_to_bucket(value)); } /** * @brief Finds an element that compares _equivalent_ to a given value. * @param value Value of an element to search for. * @return An iterator to an element with the given value. If no such * element is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &value) requires is_transparent_v && is_transparent_v { return constrained_find(value, value_to_bucket(value)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &value) const requires is_transparent_v && is_transparent_v { return constrained_find(value, value_to_bucket(value)); } /** * @brief Returns a range containing all elements with a given value. * @param value Value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const value_type &value) { const auto it = find(value); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const value_type &value) const { const auto it = find(value); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given value. * @param value Value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &value) requires is_transparent_v && is_transparent_v { const auto it = find(value); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &value) const requires is_transparent_v && is_transparent_v { const auto it = find(value); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given value. * @param value Value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const value_type &value) const { return (find(value) != cend()); } /** * @brief Checks if the container contains an element that compares * _equivalent_ to a given value. * @param value Value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &value) const requires is_transparent_v && is_transparent_v { return (find(value) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given element. * @param value The value of the element to examine. * @return The bucket for the given element. */ [[nodiscard]] size_type bucket(const value_type &value) const { return value_to_bucket(value); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = value_to_bucket(packed.first()[pos].second); packed.first()[pos].first = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the elements. * @return The function used to hash the elements. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare elements for equality. * @return The function used to compare elements for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" // #include "../stl/algorithm.hpp" #ifndef ENTT_STL_ALGORITHM_HPP #define ENTT_STL_ALGORITHM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::all_of; using std::any_of; using std::find_if; using std::none_of; using std::sort; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "adjacency_matrix.hpp" #ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP #define ENTT_GRAPH_ADJACENCY_MATRIX_HPP // #include "../config/config.h" // #include "../core/iterator.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class edge_iterator { using size_type = stl::size_t; void find_next() noexcept { for(; pos != last && !it[static_cast(pos)]; pos += offset) {} } public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr edge_iterator() noexcept = default; // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept : it{stl::move(base)}, vert{vertices}, pos{from}, last{to}, offset{step} { find_next(); } constexpr edge_iterator &operator++() noexcept { pos += offset; find_next(); return *this; } constexpr edge_iterator operator++(int) noexcept { const edge_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr reference operator*() const noexcept { return *operator->(); } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::make_pair(pos / vert, pos % vert); } [[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept { return pos == other.pos; } private: It it{}; size_type vert{}; size_type pos{}; size_type last{}; size_type offset{}; }; } // namespace internal /*! @endcond */ /** * @brief Basic implementation of a directed adjacency matrix. * @tparam Category Either a directed or undirected category tag. * @tparam Allocator Type of allocator used to manage memory and elements. */ template Category, typename Allocator> class adjacency_matrix { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_type = stl::vector>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Vertex type. */ using vertex_type = size_type; /*! @brief Edge type. */ using edge_type = stl::pair; /*! @brief Vertex iterator type. */ using vertex_iterator = iota_iterator; /*! @brief Edge iterator type. */ using edge_iterator = internal::edge_iterator; /*! @brief Out-edge iterator type. */ using out_edge_iterator = edge_iterator; /*! @brief In-edge iterator type. */ using in_edge_iterator = edge_iterator; /*! @brief Graph category tag. */ using graph_category = Category; /*! @brief Default constructor. */ adjacency_matrix() noexcept(noexcept(allocator_type{})) : adjacency_matrix{0u} { } /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit adjacency_matrix(const allocator_type &allocator) noexcept : adjacency_matrix{0u, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied number of vertices. * @param vertices Number of vertices. * @param allocator The allocator to use. */ adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{}) : matrix{vertices * vertices, allocator}, vert{vertices} {} /*! @brief Default copy constructor. */ adjacency_matrix(const adjacency_matrix &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator) : matrix{other.matrix, allocator}, vert{other.vert} {} /*! @brief Default move constructor. */ adjacency_matrix(adjacency_matrix &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator) : matrix{stl::move(other.matrix), allocator}, vert{other.vert} {} /*! @brief Default destructor. */ ~adjacency_matrix() = default; /** * @brief Default copy assignment operator. * @return This container. */ adjacency_matrix &operator=(const adjacency_matrix &) = default; /** * @brief Default move assignment operator. * @return This container. */ adjacency_matrix &operator=(adjacency_matrix &&) noexcept = default; /** * @brief Exchanges the contents with those of a given adjacency matrix. * @param other Adjacency matrix to exchange the content with. */ void swap(adjacency_matrix &other) noexcept { using stl::swap; swap(matrix, other.matrix); swap(vert, other.vert); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return matrix.get_allocator(); } /*! @brief Clears the adjacency matrix. */ void clear() noexcept { matrix.clear(); vert = {}; } /** * @brief Returns true if an adjacency matrix is empty, false otherwise. * * @warning * Potentially expensive, try to avoid it on hot paths. * * @return True if the adjacency matrix is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { const auto iterable = edges(); return (iterable.begin() == iterable.end()); } /** * @brief Returns the number of vertices. * @return The number of vertices. */ [[nodiscard]] size_type size() const noexcept { return vert; } /** * @brief Returns an iterable object to visit all vertices of a matrix. * @return An iterable object to visit all vertices of a matrix. */ [[nodiscard]] iterable_adaptor vertices() const noexcept { return {0u, vert}; } /** * @brief Returns an iterable object to visit all edges of a matrix. * @return An iterable object to visit all edges of a matrix. */ [[nodiscard]] iterable_adaptor edges() const noexcept { const auto it = matrix.cbegin(); const auto sz = matrix.size(); return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}}; } /** * @brief Returns an iterable object to visit all out-edges of a vertex. * @param vertex The vertex of which to return all out-edges. * @return An iterable object to visit all out-edges of a vertex. */ [[nodiscard]] iterable_adaptor out_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex * vert; const auto to = from + vert; return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}}; } /** * @brief Returns an iterable object to visit all in-edges of a vertex. * @param vertex The vertex of which to return all in-edges. * @return An iterable object to visit all in-edges of a vertex. */ [[nodiscard]] iterable_adaptor in_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex; const auto to = vert * vert + from; return {{it, vert, from, to, vert}, {it, vert, to, to, vert}}; } /** * @brief Resizes an adjacency matrix. * @param vertices The new number of vertices. */ void resize(const size_type vertices) { adjacency_matrix other{vertices, get_allocator()}; for(auto [lhs, rhs]: edges()) { other.insert(lhs, rhs); } other.swap(*this); } /** * @brief Inserts an edge into the adjacency matrix, if it does not exist. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 1u; } const auto inserted = !stl::exchange(matrix[pos], 1u); return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted}; } /** * @brief Removes the edge associated with a pair of given vertices. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return Number of elements removed (either 0 or 1). */ size_type erase(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 0u; } return stl::exchange(matrix[pos], 0u); } /** * @brief Checks if an adjacency matrix contains a given edge. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return True if there is such an edge, false otherwise. */ [[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const { const auto pos = lhs * vert + rhs; return pos < matrix.size() && matrix[pos]; } private: container_type matrix; size_type vert; }; } // namespace entt #endif // #include "fwd.hpp" namespace entt { /** * @brief Utility class for creating task graphs. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_flow { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using task_container_type = dense_set, typename alloc_traits::template rebind_alloc>; using ro_rw_container_type = stl::vector, typename alloc_traits::template rebind_alloc>>; using deps_container_type = dense_map, typename alloc_traits::template rebind_alloc>>; using adjacency_matrix_type = adjacency_matrix>; void emplace(const id_type res, const bool is_rw) { ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); if(!deps.contains(res) && sync_on != vertices.size()) { deps[res].emplace_back(sync_on, true); } deps[res].emplace_back(index.first(), is_rw); } void setup_graph(adjacency_matrix_type &matrix) const { for(const auto &elem: deps) { const auto last = elem.second.cend(); auto it = elem.second.cbegin(); while(it != last) { if(it->second) { // rw item if(auto curr = it++; it != last) { if(it->second) { matrix.insert(curr->first, it->first); } else if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { for(; it != next; ++it) { matrix.insert(curr->first, it->first); matrix.insert(it->first, next->first); } } else { for(; it != next; ++it) { matrix.insert(curr->first, it->first); } } } } else { // ro item (first iteration only) if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { for(; it != next; ++it) { matrix.insert(it->first, next->first); } } else { it = last; } } } } } void transitive_closure(adjacency_matrix_type &matrix) const { const auto length = matrix.size(); for(stl::size_t vk{}; vk < length; ++vk) { for(stl::size_t vi{}; vi < length; ++vi) { for(stl::size_t vj{}; vj < length; ++vj) { if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) { matrix.insert(vi, vj); } } } } } void transitive_reduction(adjacency_matrix_type &matrix) const { const auto length = matrix.size(); for(stl::size_t vert{}; vert < length; ++vert) { matrix.erase(vert, vert); } for(stl::size_t vj{}; vj < length; ++vj) { for(stl::size_t vi{}; vi < length; ++vi) { if(matrix.contains(vi, vj)) { for(stl::size_t vk{}; vk < length; ++vk) { if(matrix.contains(vj, vk)) { matrix.erase(vi, vk); } } } } } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Iterable task list. */ using iterable = iterable_adaptor; /*! @brief Adjacency matrix type. */ using graph_type = adjacency_matrix_type; /*! @brief Default constructor. */ basic_flow() : basic_flow{allocator_type{}} {} /** * @brief Constructs a flow builder with a given allocator. * @param allocator The allocator to use. */ explicit basic_flow(const allocator_type &allocator) : index{0u, allocator}, vertices{allocator}, deps{allocator} {} /*! @brief Default copy constructor. */ basic_flow(const basic_flow &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ basic_flow(const basic_flow &other, const allocator_type &allocator) : index{other.index.first(), allocator}, vertices{other.vertices, allocator}, deps{other.deps, allocator}, sync_on{other.sync_on} {} /*! @brief Default move constructor. */ basic_flow(basic_flow &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_flow(basic_flow &&other, const allocator_type &allocator) : index{other.index.first(), allocator}, vertices{stl::move(other.vertices), allocator}, deps{stl::move(other.deps), allocator}, sync_on{other.sync_on} {} /*! @brief Default destructor. */ ~basic_flow() = default; /** * @brief Default copy assignment operator. * @return This flow builder. */ basic_flow &operator=(const basic_flow &) = default; /** * @brief Default move assignment operator. * @return This flow builder. */ basic_flow &operator=(basic_flow &&) noexcept = default; /** * @brief Exchanges the contents with those of a given flow builder. * @param other Flow builder to exchange the content with. */ void swap(basic_flow &other) noexcept { using stl::swap; swap(index, other.index); swap(vertices, other.vertices); swap(deps, other.deps); swap(sync_on, other.sync_on); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return allocator_type{index.second()}; } /** * @brief Returns the identifier at specified location. * @param pos Position of the identifier to return. * @return The requested identifier. */ [[nodiscard]] id_type operator[](const size_type pos) const { return vertices.cbegin()[static_cast(pos)]; } /*! @brief Clears the flow builder. */ void clear() noexcept { index.first() = {}; vertices.clear(); deps.clear(); sync_on = {}; } /** * @brief Returns true if a flow builder contains no tasks, false otherwise. * @return True if the flow builder contains no tasks, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return vertices.empty(); } /** * @brief Returns the number of tasks. * @return The number of tasks. */ [[nodiscard]] size_type size() const noexcept { return vertices.size(); } /** * @brief Binds a task to a flow builder. * @param value Task identifier. * @return This flow builder. */ basic_flow &bind(const id_type value) { sync_on += (sync_on == vertices.size()); const auto it = vertices.emplace(value).first; index.first() = size_type(it - vertices.begin()); return *this; } /** * @brief Turns the current task into a sync point. * @return This flow builder. */ basic_flow &sync() { ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); sync_on = index.first(); for(const auto &elem: deps) { elem.second.emplace_back(sync_on, true); } return *this; } /** * @brief Assigns a resource to the current task with a given access mode. * @param res Resource identifier. * @param is_rw Access mode. * @return This flow builder. */ basic_flow &set(const id_type res, bool is_rw = false) { emplace(res, is_rw); return *this; } /** * @brief Assigns a read-only resource to the current task. * @param res Resource identifier. * @return This flow builder. */ basic_flow &ro(const id_type res) { emplace(res, false); return *this; } /** * @brief Assigns a range of read-only resources to the current task. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return This flow builder. */ basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { emplace(*first, false); } return *this; } /** * @brief Assigns a writable resource to the current task. * @param res Resource identifier. * @return This flow builder. */ basic_flow &rw(const id_type res) { emplace(res, true); return *this; } /** * @brief Assigns a range of writable resources to the current task. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return This flow builder. */ basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { emplace(*first, true); } return *this; } /** * @brief Generates a task graph for the current content. * @return The adjacency matrix of the task graph. */ [[nodiscard]] graph_type graph() const { graph_type matrix{vertices.size(), get_allocator()}; setup_graph(matrix); transitive_closure(matrix); transitive_reduction(matrix); return matrix; } private: compressed_pair index; task_container_type vertices; deps_container_type deps; size_type sync_on{}; }; } // namespace entt #endif // #include "../stl/cstddef.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "fwd.hpp" // #include "helper.hpp" #ifndef ENTT_ENTITY_HELPER_HPP #define ENTT_ENTITY_HELPER_HPP // #include "../core/fwd.hpp" // #include "../core/type_traits.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "component.hpp" // #include "fwd.hpp" // #include "group.hpp" // #include "storage.hpp" // #include "view.hpp" namespace entt { /** * @brief Converts a registry to a view. * @tparam Registry Basic registry type. */ template class as_view { template [[nodiscard]] auto dispatch(get_t, exclude_t) const { return reg->template view...>(exclude_t...>{}); } public: /*! @brief Type of registry to convert. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /** * @brief Constructs a converter for a given registry. * @param source A valid reference to a registry. */ as_view(registry_type &source) noexcept : reg{&source} {} /** * @brief Conversion function from a registry to a view. * @tparam Get Type of storage used to construct the view. * @tparam Exclude Types of storage used to filter the view. * @return A newly created view. */ template operator basic_view() const { return dispatch(Get{}, Exclude{}); } private: registry_type *reg; }; /** * @brief Converts a registry to a group. * @tparam Registry Basic registry type. */ template class as_group { template [[nodiscard]] auto dispatch(owned_t, get_t, exclude_t) const { if constexpr(stl::is_const_v) { return reg->template group_if_exists(get_t{}, exclude_t{}); } else { return reg->template group...>(get_t...>{}, exclude_t...>{}); } } public: /*! @brief Type of registry to convert. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /** * @brief Constructs a converter for a given registry. * @param source A valid reference to a registry. */ as_group(registry_type &source) noexcept : reg{&source} {} /** * @brief Conversion function from a registry to a group. * @tparam Owned Types of _owned_ by the group. * @tparam Get Types of storage _observed_ by the group. * @tparam Exclude Types of storage used to filter the group. * @return A newly created group. */ template operator basic_group() const { return dispatch(Owned{}, Get{}, Exclude{}); } private: registry_type *reg; }; /** * @brief Helper to create a listener that directly invokes a member function. * @tparam Member Member function to invoke on an element of the given type. * @tparam Registry Basic registry type. * @param reg A registry that contains the given entity and its elements. * @param entt Entity from which to get the element. */ template>> void invoke(Registry ®, const typename Registry::entity_type entt) { static_assert(stl::is_member_function_pointer_v, "Invalid pointer to non-static member function"); (reg.template get>(entt).*Member)(reg, entt); } /** * @brief Returns the entity associated with a given element. * * @warning * Currently, this function only works correctly with the default storage as it * makes assumptions about how the elements are laid out. * * @tparam Args Storage type template parameters. * @param storage A storage that contains the given element. * @param instance A valid element instance. * @return The entity associated with the given element. */ template basic_storage::entity_type to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) { using traits_type = component_traits::value_type, typename basic_storage::entity_type>; static_assert(traits_type::page_size != 0u, "Unexpected page size"); const auto *page = storage.raw(); // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(stl::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) { if(const auto dist = (stl::addressof(instance) - *page); dist >= 0 && dist < static_cast(traits_type::page_size)) { return *(static_cast::base_type &>(storage).rbegin() + static_cast(pos) + dist); } } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) return null; } /*! @brief Primary template isn't defined on purpose. */ template struct sigh_helper; /** * @brief Signal connection helper for registries. * @tparam Registry Basic registry type. */ template struct sigh_helper { /*! @brief Registry type. */ using registry_type = Registry; /** * @brief Constructs a helper for a given registry. * @param ref A valid reference to a registry. */ sigh_helper(registry_type &ref) : bucket{&ref} {} /** * @brief Binds a properly initialized helper to a given signal type. * @tparam Type Type of signal to bind the helper to. * @param id Optional name for the underlying storage to use. * @return A helper for a given registry and signal type. */ template auto with(const id_type id = type_hash::value()) noexcept { return sigh_helper{*bucket, id}; } /** * @brief Returns a reference to the underlying registry. * @return A reference to the underlying registry. */ [[nodiscard]] registry_type ®istry() noexcept { return *bucket; } private: registry_type *bucket; }; /** * @brief Signal connection helper for registries. * @tparam Registry Basic registry type. * @tparam Type Type of signal to connect listeners to. */ template struct sigh_helper final: sigh_helper { /*! @brief Registry type. */ using registry_type = Registry; /** * @brief Constructs a helper for a given registry. * @param ref A valid reference to a registry. * @param id Optional name for the underlying storage to use. */ sigh_helper(registry_type &ref, const id_type id = type_hash::value()) : sigh_helper{ref}, name{id} {} /** * @brief Forwards the call to `on_construct` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_construct(Args &&...args) { this->registry().template on_construct(name).template connect(stl::forward(args)...); return *this; } /** * @brief Forwards the call to `on_update` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_update(Args &&...args) { this->registry().template on_update(name).template connect(stl::forward(args)...); return *this; } /** * @brief Forwards the call to `on_destroy` on the underlying storage. * @tparam Candidate Function or member to connect. * @tparam Args Type of class or type of payload, if any. * @param args A valid object that fits the purpose, if any. * @return This helper. */ template auto on_destroy(Args &&...args) { this->registry().template on_destroy(name).template connect(stl::forward(args)...); return *this; } private: id_type name; }; /** * @brief Deduction guide. * @tparam Registry Basic registry type. */ template sigh_helper(Registry &) -> sigh_helper; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct is_view: stl::false_type {}; template struct is_view>: stl::true_type {}; template inline constexpr bool is_view_v = is_view::value; template struct is_group: stl::false_type {}; template struct is_group>: stl::true_type {}; template inline constexpr bool is_group_v = is_group::value; template struct unpack_type { using ro = stl::conditional_t< type_list_contains_v || (stl::is_const_v && !type_list_contains_v>), type_list>, type_list<>>; using rw = stl::conditional_t< type_list_contains_v> || (!stl::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, exclude_t>, type_list> { using ro = type_list_cat_t, typename unpack_type, type_list>::ro...>; using rw = type_list_cat_t, type_list>::rw...>; }; template struct unpack_type, exclude_t>, type_list> : unpack_type, exclude_t>, type_list> {}; template struct unpack_type, get_t, exclude_t>, type_list> { using ro = type_list_cat_t, typename unpack_type, type_list>::ro..., typename unpack_type, type_list>::ro...>; using rw = type_list_cat_t, type_list>::rw..., typename unpack_type, type_list>::rw...>; }; template struct unpack_type, get_t, exclude_t>, type_list> : unpack_type, get_t, exclude_t>, type_list> {}; template struct resource_traits; template struct resource_traits, 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...>; static constexpr auto sync_point = (stl::is_same_v || ...); }; template resource_traits...>, type_list> free_function_to_resource_traits(Ret (*)(Args...)); template resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (*)(Type &, Args...)); template resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (Class::*)(Args...)); template resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const); } // namespace internal /*! @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 Registry Basic registry type. */ template class basic_organizer final { using callback_type = void(const void *, Registry &); using prepare_type = void(Registry &); using dependency_type = stl::size_t(const bool, const type_info **, const stl::size_t); struct vertex_data final { stl::size_t ro_count{}; stl::size_t rw_count{}; const char *name{}; const void *payload{}; callback_type *callback{}; dependency_type *dependency{}; prepare_type *prepare{}; const type_info *info{}; }; template [[nodiscard]] static decltype(auto) extract(Registry ®) { if constexpr(stl::is_same_v) { return reg; } else if constexpr(internal::is_view_v) { return static_cast(as_view{reg}); } else if constexpr(internal::is_group_v) { return static_cast(as_group{reg}); } else { return reg.ctx().template emplace>(); } } template [[nodiscard]] static auto to_args(Registry ®, type_list) { return stl::tuple(reg))...>(extract(reg)...); } template [[nodiscard]] static stl::size_t fill_dependencies(type_list, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const stl::size_t count) { if constexpr(sizeof...(Type) == 0u) { return {}; } else { // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) const type_info *info[]{&type_id()...}; const auto length = count < sizeof...(Type) ? count : sizeof...(Type); for(stl::size_t pos{}; pos < length; ++pos) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) buffer[pos] = info[pos]; } return length; } } template void track_dependencies(stl::size_t index, const bool sync_point, type_list, type_list) { builder.bind(static_cast(index)); builder.set(type_hash::value(), sync_point || (sizeof...(RO) + sizeof...(RW) == 0u)); (builder.ro(type_hash::value()), ...); (builder.rw(type_hash::value()), ...); } public: /*! Basic registry type. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /*! @brief Unsigned integer type. */ using size_type = stl::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 data The data associated with the vertex. * @param from List of in-edges of the vertex. * @param to List of out-edges of the vertex. */ vertex(vertex_data data, stl::vector from, stl::vector to) : node{stl::move(data)}, in{stl::move(from)}, out{stl::move(to)} {} /** * @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. */ [[nodiscard]] size_type ro_dependency(const type_info **buffer, const stl::size_t length) const 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. */ [[nodiscard]] size_type rw_dependency(const type_info **buffer, const stl::size_t length) const 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. */ [[nodiscard]] size_type ro_count() const noexcept { return node.ro_count; } /** * @brief Returns the number of writable resources of a vertex. * @return The number of writable resources of the vertex. */ [[nodiscard]] size_type rw_count() const 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. */ [[nodiscard]] bool top_level() const noexcept { return in.empty(); } /** * @brief Returns a type info object associated with a vertex. * @return A properly initialized type info object. */ [[nodiscard]] const type_info &info() const 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. */ [[nodiscard]] const char *name() const noexcept { return node.name; } /** * @brief Returns the function associated with a vertex. * @return The function associated with the vertex. */ [[nodiscard]] function_type *callback() const noexcept { return node.callback; } /** * @brief Returns the payload associated with a vertex, if any. * @return The payload associated with the vertex, if any. */ [[nodiscard]] const void *data() const noexcept { return node.payload; } /** * @brief Returns the list of in-edges of a vertex. * @return The list of in-edges of a vertex. */ [[nodiscard]] const stl::vector &in_edges() const noexcept { return in; } /** * @brief Returns the list of out-edges of a vertex. * @return The list of out-edges of a vertex. */ [[nodiscard]] const stl::vector &out_edges() const noexcept { return out; } /** * @brief Prepares a registry and assures that all required resources * are properly instantiated before using them. * @param reg A valid registry. */ void prepare(registry_type ®) const { node.prepare ? node.prepare(reg) : void(); } private: vertex_data node; stl::vector in; stl::vector out; }; /** * @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_traits(Candidate)); callback_type *callback = +[](const void *, registry_type ®) { stl::apply(Candidate, to_args(reg, typename resource_type::args{})); }; vertex_data vdata{ resource_type::ro::size, resource_type::rw::size, name, nullptr, callback, +[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); }, &type_id>()}; track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{}); vertices.push_back(stl::move(vdata)); } /** * @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_traits(Candidate)); callback_type *callback = +[](const void *payload, registry_type ®) { Type *curr = static_cast(const_cast *>(payload)); stl::apply(Candidate, stl::tuple_cat(stl::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{}))); }; vertex_data vdata{ resource_type::ro::size, resource_type::rw::size, name, &value_or_instance, callback, +[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); }, &type_id>()}; track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{}); vertices.push_back(stl::move(vdata)); } /** * @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_traits, type_list>; track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{}); vertex_data vdata{ resource_type::ro::size, resource_type::rw::size, name, payload, func, +[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, nullptr, &type_id()}; vertices.push_back(stl::move(vdata)); } /** * @brief Generates a task graph for the current content. * @return The adjacency list of the task graph. */ [[nodiscard]] stl::vector graph() const { stl::vector adjacency_list{}; adjacency_list.reserve(vertices.size()); for(auto adjacency_matrix = builder.graph(); auto curr: adjacency_matrix.vertices()) { stl::vector in{}; stl::vector out{}; for(auto &&edge: adjacency_matrix.in_edges(curr)) { in.push_back(edge.first); } for(auto &&edge: adjacency_matrix.out_edges(curr)) { out.push_back(edge.second); } adjacency_list.emplace_back(vertices[curr], stl::move(in), stl::move(out)); } return adjacency_list; } /*! @brief Erases all elements from a container. */ void clear() { builder.clear(); vertices.clear(); } private: stl::vector vertices; flow builder; }; } // namespace entt #endif // #include "entity/ranges.hpp" #ifndef ENTT_ENTITY_RANGES_HPP #define ENTT_ENTITY_RANGES_HPP #include #if defined(__cpp_lib_ranges) # include // # include "fwd.hpp" namespace std::ranges { template inline constexpr bool enable_borrowed_range>{true}; template inline constexpr bool enable_borrowed_range>{true}; template inline constexpr bool enable_view>{true}; template inline constexpr bool enable_view>{true}; } // namespace std::ranges #endif #endif // #include "entity/registry.hpp" #ifndef ENTT_ENTITY_REGISTRY_HPP #define ENTT_ENTITY_REGISTRY_HPP #include // #include "../config/config.h" // #include "../container/dense_map.hpp" #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" namespace entt { template< typename Key, typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator>> class dense_map; template< typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator> class dense_set; template class basic_table; /** * @brief Alias declaration for the most common use case. * @tparam Type Element types. */ template using table = basic_table...>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { using value_type = stl::pair; template dense_map_node(const stl::size_t pos, Args &&...args) : next{pos}, element{stl::forward(args)...} {} template dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) : next{pos}, element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, other.element)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} stl::size_t next; value_type element; }; template class dense_map_iterator final { template friend class dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr dense_map_iterator() noexcept : it{} {} constexpr dense_map_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_iterator(const dense_map_iterator &other) noexcept : it{other.it} {} constexpr dense_map_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_map_iterator operator++(int) noexcept { const dense_map_iterator orig = *this; return ++(*this), orig; } constexpr dense_map_iterator &operator--() noexcept { return --it, *this; } constexpr dense_map_iterator operator--(int) noexcept { const dense_map_iterator orig = *this; return operator--(), orig; } constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_map_iterator operator+(const difference_type value) const noexcept { dense_map_iterator copy = *this; return (copy += value); } constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_map_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].element.first, it[value].element.second}; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_map_local_iterator final { template friend class dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr dense_map_local_iterator() noexcept = default; constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_map_local_iterator &operator++() noexcept { return (offset = it[static_cast(offset)].next), *this; } constexpr dense_map_local_iterator operator++(int) noexcept { const dense_map_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { const auto idx = static_cast(offset); return {it[idx].element.first, it[idx].element.second}; } template [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_map_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for key-value pairs with unique keys. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on the hash of its key. Keys with the same hash * code appear in the same bucket. * * @tparam Key Key type of the associative container. * @tparam Type Mapped type of the associative container. * @tparam Hash Type of function to use to hash the keys. * @tparam KeyEqual Type of function to use to compare the keys for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_map { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; using node_type = internal::dense_map_node; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v>, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) return fast_mod(static_cast(sparse.second()(key)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } template [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { it->second = stl::forward(value); return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].next) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Key; /*! @brief Mapped type of the container. */ using mapped_type = Type; /*! @brief Key-value type of the container. */ using value_type = stl::pair; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the keys. */ using hasher = Hash; /*! @brief Type of function to use to compare the keys for equality. */ using key_equal = KeyEqual; /*! @brief Input iterator type. */ using iterator = internal::dense_map_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::dense_map_iterator; /*! @brief Input iterator type. */ using local_iterator = internal::dense_map_local_iterator; /*! @brief Constant input iterator type. */ using const_local_iterator = internal::dense_map_local_iterator; /*! @brief Default constructor. */ dense_map() : dense_map{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_map(const allocator_type &allocator) : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const allocator_type &allocator) : dense_map{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_map{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_map(const dense_map &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_map(const dense_map &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_map(dense_map &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_map(dense_map &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_map() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_map &operator=(const dense_map &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_map &operator=(dense_map &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_map &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if the key does not exist. * @param value A key-value pair eventually convertible to the value type. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value.first, value.second); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); } /** * @copydoc insert * @tparam Arg Type of the key-value pair to insert into the container. */ template requires stl::constructible_from stl::pair insert(Arg &&value) { return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); } /** * @brief Inserts elements into the container, if their keys do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Inserts an element into the container or assigns to the current * element if the key already exists. * @tparam Arg Type of the value to insert or assign. * @param key A key used both to look up and to insert if not found. * @param value A value to insert or assign. * @return A pair consisting of an iterator to the element and a bool * denoting whether the insertion took place. */ template stl::pair insert_or_assign(const key_type &key, Arg &&value) { return insert_or_overwrite(key, stl::forward(value)); } /*! @copydoc insert_or_assign */ template stl::pair insert_or_assign(key_type &&key, Arg &&value) { return insert_or_overwrite(stl::move(key), stl::forward(value)); } /** * @brief Constructs an element in-place, if the key does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace([[maybe_unused]] Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return insert_or_do_nothing(key_type{}); } else if constexpr(sizeof...(Args) == 1u) { return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); } else if constexpr(sizeof...(Args) == 2u) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); const auto index = key_to_bucket(node.element.first); if(auto it = constrained_find(node.element.first, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.next, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Inserts in-place if the key does not exist, does nothing if the * key exists. * @tparam Args Types of arguments to forward to the constructor of the * element. * @param key A key used both to look up and to insert if not found. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair try_emplace(const key_type &key, Args &&...args) { return insert_or_do_nothing(key, stl::forward(args)...); } /*! @copydoc try_emplace */ template stl::pair try_emplace(key_type &&key, Args &&...args) { return insert_or_do_nothing(stl::move(key), stl::forward(args)...); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(pos->first); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].element.first); } return (begin() + dist); } /** * @brief Removes the element associated with a given key. * @param key A key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const key_type &key) { for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { if(packed.second()(packed.first()[*curr].element.first, key)) { const auto index = *curr; *curr = packed.first()[*curr].next; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &at(const key_type &key) { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] const mapped_type &at(const key_type &key) const { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type const &at(const auto &key) const requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] mapped_type &at(const auto &key) requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](const key_type &key) { return insert_or_do_nothing(key).first->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](key_type &&key) { return insert_or_do_nothing(stl::move(key)).first->second; } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const key_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const key_type &key) { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const key_type &key) const { return constrained_find(key, key_to_bucket(key)); } /** * @brief Finds an element with a key that compares _equivalent_ to a given * key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &key) requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &key) const requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /** * @brief Returns a range containing all elements with a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const key_type &key) { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const key_type &key) const { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &key) requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &key) const requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given key. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const key_type &key) const { return (find(key) != cend()); } /** * @brief Checks if the container contains an element with a key that * compares _equivalent_ to a given value. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &key) const requires is_transparent_v && is_transparent_v { return (find(key) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given key. * @param key The value of the key to examine. * @return The bucket for the given key. */ [[nodiscard]] size_type bucket(const key_type &key) const { return key_to_bucket(key); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = key_to_bucket(packed.first()[pos].element.first); packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the keys. * @return The function used to hash the keys. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare keys for equality. * @return The function used to compare keys for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::true_type {}; } // namespace std /*! @endcond */ #endif // #include "../core/algorithm.hpp" // #include "../core/any.hpp" // #include "../core/concepts.hpp" // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" // #include "../core/memory.hpp" // #include "../core/type_info.hpp" // #include "../core/type_traits.hpp" // #include "../stl/algorithm.hpp" #ifndef ENTT_STL_ALGORITHM_HPP #define ENTT_STL_ALGORITHM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::all_of; using std::any_of; using std::find_if; using std::none_of; using std::sort; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/array.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "entity.hpp" // #include "fwd.hpp" // #include "group.hpp" // #include "mixin.hpp" #ifndef ENTT_ENTITY_MIXIN_HPP #define ENTT_ENTITY_MIXIN_HPP // #include "../config/config.h" // #include "../core/any.hpp" // #include "../core/type_info.hpp" // #include "../signal/sigh.hpp" // #include "../stl/concepts.hpp" // #include "../stl/iterator.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_on_construct final: stl::false_type {}; template requires stl::invocable struct has_on_construct: stl::true_type {}; template struct has_on_update final: stl::false_type {}; template requires stl::invocable struct has_on_update: stl::true_type {}; template struct has_on_destroy final: stl::false_type {}; template requires stl::invocable struct has_on_destroy: stl::true_type {}; } // namespace internal /*! @endcond */ /** * @brief Mixin type used to add signal support to storage types. * * The function type of a listener is equivalent to: * * @code{.cpp} * void(basic_registry &, entity_type); * @endcode * * This applies to all signals made available. * * @tparam Type Underlying storage type. * @tparam Registry Basic registry type. */ template class basic_sigh_mixin final: public Type { using underlying_type = Type; using owner_type = Registry; using basic_registry_type = basic_registry; using sigh_type = sigh; using underlying_iterator = underlying_type::base_type::basic_iterator; static_assert(stl::is_base_of_v, "Invalid registry type"); [[nodiscard]] auto &owner_or_assert() const noexcept { ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); return static_cast(*owner); } private: void pop(underlying_iterator first, underlying_iterator last) final { if(auto ® = owner_or_assert(); destruction.empty()) { underlying_type::pop(first, last); } else { for(; first != last; ++first) { const auto entt = *first; destruction.publish(reg, entt); const auto it = underlying_type::find(entt); underlying_type::pop(it, it + 1u); } } } void pop_all() final { if(auto ® = owner_or_assert(); !destruction.empty()) { if constexpr(stl::is_same_v) { for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) { destruction.publish(reg, underlying_type::base_type::operator[](pos)); } } else { for(auto entt: static_cast(*this)) { if constexpr(underlying_type::storage_policy == deletion_policy::in_place) { if(entt != tombstone) { destruction.publish(reg, entt); } } else { destruction.publish(reg, entt); } } } } underlying_type::pop_all(); } underlying_iterator try_emplace(const underlying_type::entity_type entt, const bool force_back, const void *value) final { const auto it = underlying_type::try_emplace(entt, force_back, value); if(auto ® = owner_or_assert(); it != underlying_type::base_type::end()) { construction.publish(reg, *it); } return it; } void bind_any(any value) noexcept final { owner = any_cast(&value); if constexpr(!stl::is_same_v) { if(owner == nullptr) { owner = any_cast(&value); } } underlying_type::bind_any(stl::move(value)); } public: /*! @brief Allocator type. */ using allocator_type = underlying_type::allocator_type; /*! @brief Underlying entity identifier. */ using entity_type = underlying_type::entity_type; /*! @brief Expected registry type. */ using registry_type = owner_type; /*! @brief Default constructor. */ basic_sigh_mixin() : basic_sigh_mixin{allocator_type{}} {} /** * @brief Constructs an empty storage with a given allocator. * @param allocator The allocator to use. */ explicit basic_sigh_mixin(const allocator_type &allocator) : underlying_type{allocator}, owner{}, construction{allocator}, destruction{allocator}, update{allocator} { if constexpr(internal::has_on_construct::value) { sink{construction}.template connect<&underlying_type::element_type::on_construct>(); } if constexpr(internal::has_on_update::value) { sink{update}.template connect<&underlying_type::element_type::on_update>(); } if constexpr(internal::has_on_destroy::value) { sink{destruction}.template connect<&underlying_type::element_type::on_destroy>(); } } /*! @brief Default copy constructor, deleted on purpose. */ basic_sigh_mixin(const basic_sigh_mixin &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_sigh_mixin(basic_sigh_mixin &&other) noexcept : underlying_type{static_cast(other)}, owner{other.owner}, construction{stl::move(other.construction)}, destruction{stl::move(other.destruction)}, update{stl::move(other.update)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) : underlying_type{static_cast(other), allocator}, owner{other.owner}, construction{stl::move(other.construction), allocator}, destruction{stl::move(other.destruction), allocator}, update{stl::move(other.update), allocator} {} /*! @brief Default destructor. */ ~basic_sigh_mixin() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This mixin. */ basic_sigh_mixin &operator=(const basic_sigh_mixin &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This mixin. */ basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept { swap(other); return *this; } /** * @brief Exchanges the contents with those of a given storage. * @param other Storage to exchange the content with. */ void swap(basic_sigh_mixin &other) noexcept { using stl::swap; swap(owner, other.owner); swap(construction, other.construction); swap(destruction, other.destruction); swap(update, other.update); underlying_type::swap(other); } /** * @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.
* Listeners are invoked after the object has been assigned to the entity. * * @sa sink * * @return A temporary sink object. */ [[nodiscard]] auto on_construct() 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.
* Listeners are invoked after the object has been updated. * * @sa sink * * @return A temporary sink object. */ [[nodiscard]] auto on_update() 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.
* Listeners are invoked before the object has been removed from the entity. * * @sa sink * * @return A temporary sink object. */ [[nodiscard]] auto on_destroy() noexcept { return sink{destruction}; } /** * @brief Checks if a mixin refers to a valid registry. * @return True if the mixin refers to a valid registry, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (owner != nullptr); } /** * @brief Returns a pointer to the underlying registry, if any. * @return A pointer to the underlying registry, if any. */ [[nodiscard]] const registry_type ®istry() const noexcept { return owner_or_assert(); } /*! @copydoc registry */ [[nodiscard]] registry_type ®istry() noexcept { return owner_or_assert(); } /** * @brief Creates a new identifier or recycles a destroyed one. * @return A valid identifier. */ auto generate() { const auto entt = underlying_type::generate(); construction.publish(owner_or_assert(), entt); return entt; } /** * @brief Creates a new identifier or recycles a destroyed one. * @param hint Required identifier. * @return A valid identifier. */ entity_type generate(const entity_type hint) { const auto entt = underlying_type::generate(hint); construction.publish(owner_or_assert(), entt); return entt; } /** * @brief Assigns each element in a range an identifier. * @tparam It Type of output 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 It> void generate(It first, It last) { underlying_type::generate(first, last); if(auto ® = owner_or_assert(); !construction.empty()) { for(; first != last; ++first) { construction.publish(reg, *first); } } } /** * @brief Assigns an entity to a storage and constructs its object. * @tparam Args Types of arguments to forward to the underlying storage. * @param entt A valid identifier. * @param args Parameters to forward to the underlying storage. * @return A reference to the newly created object. */ template decltype(auto) emplace(const entity_type entt, Args &&...args) { underlying_type::emplace(entt, stl::forward(args)...); construction.publish(owner_or_assert(), entt); return this->get(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 identifier. * @param func Valid function objects. * @return A reference to the patched instance. */ template decltype(auto) patch(const entity_type entt, Func &&...func) { underlying_type::patch(entt, stl::forward(func)...); update.publish(owner_or_assert(), entt); return this->get(entt); } /** * @brief Assigns one or more entities to a storage and constructs their * objects from a given instance. * @tparam Args Types of arguments to forward to the underlying storage. * @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 forward to the underlying storage. */ template void insert(stl::input_iterator auto first, stl::input_iterator auto last, Args &&...args) { auto from = underlying_type::size(); underlying_type::insert(first, last, stl::forward(args)...); if(auto ® = owner_or_assert(); !construction.empty()) { // fine as long as insert passes force_back true to try_emplace for(const auto to = underlying_type::size(); from != to; ++from) { construction.publish(reg, underlying_type::operator[](from)); } } } private: basic_registry_type *owner; sigh_type construction; sigh_type destruction; sigh_type update; }; /** * @brief Mixin type used to add _reactive_ support to storage types. * @tparam Type Underlying storage type. * @tparam Registry Basic registry type. */ template class basic_reactive_mixin final: public Type { using underlying_type = Type; using owner_type = Registry; using alloc_traits = stl::allocator_traits; using basic_registry_type = basic_registry; using container_type = stl::vector>; static_assert(stl::is_base_of_v, "Invalid registry type"); [[nodiscard]] auto &owner_or_assert() const noexcept { ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); return static_cast(*owner); } void emplace_element(const Registry &, underlying_type::entity_type entity) { if(!underlying_type::contains(entity)) { underlying_type::emplace(entity); } } private: void bind_any(any value) noexcept final { owner = any_cast(&value); if constexpr(!stl::is_same_v) { if(owner == nullptr) { owner = any_cast(&value); } } underlying_type::bind_any(stl::move(value)); } public: /*! @brief Allocator type. */ using allocator_type = underlying_type::allocator_type; /*! @brief Underlying entity identifier. */ using entity_type = underlying_type::entity_type; /*! @brief Expected registry type. */ using registry_type = owner_type; /*! @brief Default constructor. */ basic_reactive_mixin() : basic_reactive_mixin{allocator_type{}} {} /** * @brief Constructs an empty storage with a given allocator. * @param allocator The allocator to use. */ explicit basic_reactive_mixin(const allocator_type &allocator) : underlying_type{allocator}, owner{}, conn{allocator} { } /*! @brief Default copy constructor, deleted on purpose. */ basic_reactive_mixin(const basic_reactive_mixin &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_reactive_mixin(basic_reactive_mixin &&other) noexcept : underlying_type{static_cast(other)}, owner{other.owner}, conn{stl::move(other.conn)} { } /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator) : underlying_type{static_cast(other), allocator}, owner{other.owner}, conn{stl::move(other.conn), allocator} { } /*! @brief Default destructor. */ ~basic_reactive_mixin() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This mixin. */ basic_reactive_mixin &operator=(const basic_reactive_mixin &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This mixin. */ basic_reactive_mixin &operator=(basic_reactive_mixin &&other) noexcept { underlying_type::swap(other); return *this; } /** * @brief Makes storage _react_ to creation of objects of the given type. * @tparam Clazz Type of element to _react_ to. * @tparam Candidate Function to use to _react_ to the event. * @param id Optional name used to map the storage within the registry. * @return This mixin. */ template basic_reactive_mixin &on_construct(const id_type id = type_hash::value()) { auto curr = owner_or_assert().template storage(id).on_construct().template connect(*this); conn.push_back(stl::move(curr)); return *this; } /** * @brief Makes storage _react_ to update of objects of the given type. * @tparam Clazz Type of element to _react_ to. * @tparam Candidate Function to use to _react_ to the event. * @param id Optional name used to map the storage within the registry. * @return This mixin. */ template basic_reactive_mixin &on_update(const id_type id = type_hash::value()) { auto curr = owner_or_assert().template storage(id).on_update().template connect(*this); conn.push_back(stl::move(curr)); return *this; } /** * @brief Makes storage _react_ to destruction of objects of the given type. * @tparam Clazz Type of element to _react_ to. * @tparam Candidate Function to use to _react_ to the event. * @param id Optional name used to map the storage within the registry. * @return This mixin. */ template basic_reactive_mixin &on_destroy(const id_type id = type_hash::value()) { auto curr = owner_or_assert().template storage(id).on_destroy().template connect(*this); conn.push_back(stl::move(curr)); return *this; } /** * @brief Checks if a mixin refers to a valid registry. * @return True if the mixin refers to a valid registry, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (owner != nullptr); } /** * @brief Returns a pointer to the underlying registry, if any. * @return A pointer to the underlying registry, if any. */ [[nodiscard]] const registry_type ®istry() const noexcept { return owner_or_assert(); } /*! @copydoc registry */ [[nodiscard]] registry_type ®istry() noexcept { return owner_or_assert(); } /** * @brief Returns a view that is filtered by the underlying storage. * @tparam Get Types of elements used to construct the view. * @tparam Exclude Types of elements used to filter the view. * @return A newly created view. */ template [[nodiscard]] basic_view...>, exclude_t...>> view(exclude_t = exclude_t{}) const { const owner_type &parent = owner_or_assert(); basic_view...>, exclude_t...>> elem{}; [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage>()..., parent.template storage>()..., this); return elem; } /*! @copydoc view */ template [[nodiscard]] basic_view...>, exclude_t...>> view(exclude_t = exclude_t{}) { stl::conditional_t<((stl::is_const_v && ...) && (stl::is_const_v && ...)), const owner_type, owner_type> &parent = owner_or_assert(); return {*this, parent.template storage>()..., parent.template storage>()...}; } /*! @brief Releases all connections to the underlying registry, if any. */ void reset() { for(auto &&curr: conn) { curr.release(); } conn.clear(); } private: basic_registry_type *owner; container_type conn; }; } // namespace entt #endif // #include "sparse_set.hpp" // #include "storage.hpp" // #include "view.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class registry_storage_iterator final { template friend class registry_storage_iterator; using mapped_type = stl::remove_reference_t()->second)>; public: using value_type = stl::pair &>; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr registry_storage_iterator() noexcept : it{} {} constexpr registry_storage_iterator(It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr registry_storage_iterator(const registry_storage_iterator &other) noexcept : registry_storage_iterator{other.it} {} constexpr registry_storage_iterator &operator++() noexcept { return ++it, *this; } constexpr registry_storage_iterator operator++(int) noexcept { const registry_storage_iterator orig = *this; return ++(*this), orig; } constexpr registry_storage_iterator &operator--() noexcept { return --it, *this; } constexpr registry_storage_iterator operator--(int) noexcept { const registry_storage_iterator orig = *this; return operator--(), orig; } constexpr registry_storage_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr registry_storage_iterator operator+(const difference_type value) const noexcept { registry_storage_iterator copy = *this; return (copy += value); } constexpr registry_storage_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr registry_storage_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].first, *it[value].second}; } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const registry_storage_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const registry_storage_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const registry_storage_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class registry_context { using alloc_traits = stl::allocator_traits; using allocator_type = alloc_traits::template rebind_alloc>>; public: explicit registry_context(const allocator_type &allocator) : ctx{allocator} {} void clear() noexcept { ctx.clear(); } template Type &emplace_as(const id_type id, Args &&...args) { return any_cast(ctx.try_emplace(id, stl::in_place_type, stl::forward(args)...).first->second); } template Type &emplace(Args &&...args) { return emplace_as(type_id().hash(), stl::forward(args)...); } template Type &insert_or_assign(const id_type id, Type &&value) { return any_cast &>(ctx.insert_or_assign(id, stl::forward(value)).first->second); } template Type &insert_or_assign(Type &&value) { return insert_or_assign(type_id().hash(), stl::forward(value)); } template bool erase(const id_type id = type_id().hash()) { const auto it = ctx.find(id); return it != ctx.end() && it->second.info() == type_id() ? (ctx.erase(it), true) : false; } template [[nodiscard]] const Type &get(const id_type id = type_id().hash()) const { return any_cast(ctx.at(id)); } template [[nodiscard]] Type &get(const id_type id = type_id().hash()) { return any_cast(ctx.at(id)); } template [[nodiscard]] const Type *find(const id_type id = type_id().hash()) const { const auto it = ctx.find(id); return it != ctx.cend() ? any_cast(&it->second) : nullptr; } template [[nodiscard]] Type *find(const id_type id = type_id().hash()) { const auto it = ctx.find(id); return it != ctx.end() ? any_cast(&it->second) : nullptr; } template [[nodiscard]] bool contains(const id_type id = type_id().hash()) const { const auto it = ctx.find(id); return it != ctx.cend() && it->second.info() == type_id(); } private: dense_map, stl::identity, stl::equal_to<>, allocator_type> ctx; }; } // namespace internal /*! @endcond */ /** * @brief Fast and reliable entity-component system. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_registry { using base_type = basic_sparse_set; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); // stl::shared_ptr because of its type erased allocator which is useful here using pool_container_type = dense_map, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc>>>; using group_container_type = dense_map, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc>>>; using traits_type = entt_traits; template [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash::value()) { if constexpr(stl::is_same_v) { ENTT_ASSERT(id == type_hash::value(), "User entity storage not allowed"); return entities; } else { using storage_type = storage_for_type; if(auto it = pools.find(id); it != pools.cend()) { ENTT_ASSERT(it->second->info() == type_id(), "Unexpected type"); return static_cast(*it->second); } typename pool_container_type::mapped_type cpool = stl::allocate_shared(get_allocator(), get_allocator()); pools.emplace(id, cpool); cpool->bind(*this); return static_cast(*cpool); } } template [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash::value()) const { if constexpr(stl::is_same_v) { ENTT_ASSERT(id == type_hash::value(), "User entity storage not allowed"); return &entities; } else { if(const auto it = pools.find(id); it != pools.cend()) { ENTT_ASSERT(it->second->info() == type_id(), "Unexpected type"); return static_cast *>(it->second.get()); } return static_cast *>(nullptr); } } void rebind() { entities.bind(*this); for(auto &&curr: pools) { curr.second->bind(*this); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Underlying entity identifier. */ using entity_type = traits_type::value_type; /*! @brief Underlying version type. */ using version_type = traits_type::version_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Common type among all storage types. */ using common_type = base_type; /*! @brief Context type. */ using context = internal::registry_context; /*! @brief Iterable registry type. */ using iterable = iterable_adaptor>; /*! @brief Constant iterable registry type. */ using const_iterable = iterable_adaptor>; /** * @copybrief storage_for * @tparam Type Storage value type, eventually const. */ template using storage_for_type = storage_for>>::type; /*! @brief Default constructor. */ basic_registry() : basic_registry{allocator_type{}} {} /** * @brief Constructs an empty registry with a given allocator. * @param allocator The allocator to use. */ explicit basic_registry(const allocator_type &allocator) : basic_registry{0u, allocator} {} /** * @brief Allocates enough memory upon construction to store `count` pools. * @param count The number of pools to allocate memory for. * @param allocator The allocator to use. */ basic_registry(const size_type count, const allocator_type &allocator = allocator_type{}) : vars{allocator}, pools{allocator}, groups{allocator}, entities{allocator} { pools.reserve(count); rebind(); } /*! @brief Default copy constructor, deleted on purpose. */ basic_registry(const basic_registry &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_registry(basic_registry &&other) noexcept : vars{stl::move(other.vars)}, pools{stl::move(other.pools)}, groups{stl::move(other.groups)}, entities{stl::move(other.entities)} { rebind(); } /*! @brief Default destructor. */ ~basic_registry() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This mixin. */ basic_registry &operator=(const basic_registry &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This registry. */ basic_registry &operator=(basic_registry &&other) noexcept { swap(other); return *this; } /** * @brief Exchanges the contents with those of a given registry. * @param other Registry to exchange the content with. */ void swap(basic_registry &other) noexcept { using stl::swap; swap(vars, other.vars); swap(pools, other.pools); swap(groups, other.groups); swap(entities, other.entities); rebind(); other.rebind(); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return entities.get_allocator(); } /** * @brief Returns an iterable object to use to _visit_ a registry. * * The iterable object returns a pair that contains the name and a reference * to the current storage. * * @return An iterable object to use to _visit_ the registry. */ [[nodiscard]] iterable storage() noexcept { return iterable{pools.begin(), pools.end()}; } /*! @copydoc storage */ [[nodiscard]] const_iterable storage() const noexcept { return const_iterable{pools.cbegin(), pools.cend()}; } /** * @brief Finds the storage associated with a given name, if any. * @param id Name used to map the storage within the registry. * @return A pointer to the storage if it exists, a null pointer otherwise. */ [[nodiscard]] common_type *storage(const id_type id) { return const_cast(stl::as_const(*this).storage(id)); } /** * @brief Finds the storage associated with a given name, if any. * @param id Name used to map the storage within the registry. * @return A pointer to the storage if it exists, a null pointer otherwise. */ [[nodiscard]] const common_type *storage(const id_type id) const { const auto it = pools.find(id); return it == pools.cend() ? nullptr : it->second.get(); } /** * @brief Returns the storage for a given element type. * @tparam Type Type of element of which to return the storage. * @param id Optional name used to map the storage within the registry. * @return The storage for the given element type. */ template storage_for_type &storage(const id_type id = type_hash::value()) { return assure>(id); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @param id Optional name used to map the storage within the registry. * @return The storage for the given element type. */ template [[nodiscard]] const storage_for_type *storage(const id_type id = type_hash::value()) const { return assure>(id); } /** * @brief Discards the storage associated with a given name, if any. * @param id Name used to map the storage within the registry. * @return True in case of success, false otherwise. */ bool reset(const id_type id) { ENTT_ASSERT(id != type_hash::value(), "Cannot reset entity storage"); return !(pools.erase(id) == 0u); } /** * @brief Checks if an identifier refers to a valid entity. * @param entt An identifier, either valid or not. * @return True if the identifier is valid, false otherwise. */ [[nodiscard]] bool valid(const entity_type entt) const { return static_cast(entities.find(entt).index()) < entities.free_list(); } /** * @brief Returns the actual version for an identifier. * @param entt A valid identifier. * @return The version for the given identifier if valid, the tombstone * version otherwise. */ [[nodiscard]] version_type current(const entity_type entt) const { return entities.current(entt); } /** * @brief Creates a new entity or recycles a destroyed one. * @return A valid identifier. */ [[nodiscard]] entity_type create() { return entities.generate(); } /** * @copybrief create * * If the requested entity isn't in use, the suggested identifier is used. * Otherwise, a new identifier is generated. * * @param hint Required identifier. * @return A valid identifier. */ [[nodiscard]] entity_type create(const entity_type hint) { return entities.generate(hint); } /** * @brief Assigns each element in a range an identifier. * * @sa create * * @tparam It Type of output 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 It> void create(It first, It last) { entities.generate(stl::move(first), stl::move(last)); } /** * @brief Destroys an entity and releases its identifier. * * @warning * Adding or removing elements to an entity that is being destroyed can * result in undefined behavior. * * @param entt A valid identifier. * @return The version of the recycled entity. */ version_type destroy(const entity_type entt) { for(size_type pos = pools.size(); pos != 0u; --pos) { pools.begin()[static_cast(pos - 1u)].second->remove(entt); } entities.erase(entt); return entities.current(entt); } /** * @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 entt A valid identifier. * @param version A desired version upon destruction. * @return The version actually assigned to the entity. */ version_type destroy(const entity_type entt, const version_type version) { destroy(entt); const auto elem = traits_type::construct(traits_type::to_entity(entt), version); return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem); } /** * @brief Destroys all entities in a range and releases their identifiers. * * @sa destroy * * @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. */ void destroy(stl::input_iterator auto first, stl::input_iterator auto last) { const auto to = entities.sort_as(first, last); const auto from = entities.cend() - static_cast(entities.free_list()); for(auto &&curr: pools) { curr.second->remove(from, to); } entities.erase(from, to); } /** * @brief Assigns the given element to an entity. * * The element must have a proper constructor or be of aggregate type. * * @warning * Attempting to assign an element to an entity that already owns it results * in undefined behavior. * * @tparam Type Type of element to create. * @tparam Args Types of arguments to use to construct the element. * @param entt A valid identifier. * @param args Parameters to use to initialize the element. * @return A reference to the newly created element. */ template decltype(auto) emplace(const entity_type entt, Args &&...args) { ENTT_ASSERT(valid(entt), "Invalid entity"); return assure().emplace(entt, stl::forward(args)...); } /** * @brief Assigns each entity in a range the given element. * * @sa emplace * * @tparam Type Type of element to create. * @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 element to assign. */ template void insert(stl::input_iterator auto first, stl::input_iterator auto last, const Type &value = {}) { ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity"); assure().insert(stl::move(first), stl::move(last), value); } /** * @brief Assigns each entity in a range the given elements. * * @sa emplace * * @tparam Type Type of element 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 elements. */ template requires stl::same_as::value_type, Type> void insert(EIt first, EIt last, CIt from) { ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity"); assure().insert(first, last, from); } /** * @brief Assigns or replaces the given element for an entity. * * @sa emplace * @sa replace * * @tparam Type Type of element to assign or replace. * @tparam Args Types of arguments to use to construct the element. * @param entt A valid identifier. * @param args Parameters to use to initialize the element. * @return A reference to the newly created element. */ template decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) { auto &cpool = assure(); ENTT_ASSERT(valid(entt), "Invalid entity"); return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward(args)...}), ...); }) : cpool.emplace(entt, stl::forward(args)...); } /** * @brief Patches the given element for an entity. * * The signature of the function should be equivalent to the following: * * @code{.cpp} * void(Type &); * @endcode * * @warning * Attempting to patch an element of an entity that doesn't own it results * in undefined behavior. * * @tparam Type Type of element to patch. * @tparam Func Types of the function objects to invoke. * @param entt A valid identifier. * @param func Valid function objects. * @return A reference to the patched element. */ template decltype(auto) patch(const entity_type entt, Func &&...func) { return assure().patch(entt, stl::forward(func)...); } /** * @brief Replaces the given element for an entity. * * The element must have a proper constructor or be of aggregate type. * * @warning * Attempting to replace an element of an entity that doesn't own it results * in undefined behavior. * * @tparam Type Type of element to replace. * @tparam Args Types of arguments to use to construct the element. * @param entt A valid identifier. * @param args Parameters to use to initialize the element. * @return A reference to the element being replaced. */ template decltype(auto) replace(const entity_type entt, Args &&...args) { return patch(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward(args)...}), ...); }); } /** * @brief Removes the given elements from an entity. * @tparam Type Type of element to remove. * @tparam Other Other types of elements to remove. * @param entt A valid identifier. * @return The number of elements actually removed. */ template size_type remove(const entity_type entt) { return (assure().remove(entt) + ... + assure().remove(entt)); } /** * @brief Removes the given elements from all the entities in a range. * * @sa remove * * @tparam Type Type of element to remove. * @tparam Other Other types of elements 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 elements actually removed. */ template size_type remove(It first, It last) { size_type count{}; if constexpr(stl::is_same_v) { stl::array cpools{static_cast(&assure()), static_cast(&assure())...}; for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) { if constexpr(sizeof...(Other) != 0u) { if((*from)->data() == first.data()) { stl::swap((*from), cpools.back()); } } count += (*from)->remove(first, last); } } else { for(auto cpools = stl::forward_as_tuple(assure(), assure()...); first != last; ++first) { count += stl::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools); } } return count; } /** * @brief Erases the given elements from an entity. * * @warning * Attempting to erase an element from an entity that doesn't own it results * in undefined behavior. * * @tparam Type Types of elements to erase. * @tparam Other Other types of elements to erase. * @param entt A valid identifier. */ template void erase(const entity_type entt) { (assure().erase(entt), (assure().erase(entt), ...)); } /** * @brief Erases the given elements from all the entities in a range. * * @sa erase * * @tparam Type Types of elements to erase. * @tparam Other Other types of elements 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) { if constexpr(stl::is_same_v) { stl::array cpools{static_cast(&assure()), static_cast(&assure())...}; for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) { if constexpr(sizeof...(Other) != 0u) { if((*from)->data() == first.data()) { stl::swap(*from, cpools.back()); } } (*from)->erase(first, last); } } else { for(auto cpools = stl::forward_as_tuple(assure(), assure()...); first != last; ++first) { stl::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools); } } } /** * @brief Erases elements satisfying specific criteria from an entity. * * The function type is equivalent to: * * @code{.cpp} * void(const id_type, typename basic_registry::common_type &); * @endcode * * Only storage where the entity exists are passed to the function. * * @tparam Func Type of the function object to invoke. * @param entt A valid identifier. * @param func A valid function object. */ template void erase_if(const entity_type entt, Func func) { for(auto [id, cpool]: storage()) { if(cpool.contains(entt) && func(id, stl::as_const(cpool))) { cpool.erase(entt); } } } /** * @brief Removes all tombstones from a registry or only the pools for the * given elements. * @tparam Type Types of elements for which to clear all tombstones. */ template void compact() { if constexpr(sizeof...(Type) == 0u) { for(auto &&curr: pools) { curr.second->compact(); } } else { (assure().compact(), ...); } } /** * @brief Check if an entity is part of all the given storage. * @tparam Type Type of storage to check for. * @param entt A valid identifier. * @return True if the entity is part of all the storage, false otherwise. */ template [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const { if constexpr(sizeof...(Type) == 1u) { auto *cpool = assure...>(); return cpool && cpool->contains(entt); } else { return (all_of(entt) && ...); } } /** * @brief Check if an entity is part of at least one given storage. * @tparam Type Type of storage to check for. * @param entt A valid identifier. * @return True if the entity is part of at least one storage, false * otherwise. */ template [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const { return (all_of(entt) || ...); } /** * @brief Returns references to the given elements for an entity. * * @warning * Attempting to get an element from an entity that doesn't own it results * in undefined behavior. * * @tparam Type Types of elements to get. * @param entt A valid identifier. * @return References to the elements owned by the entity. */ template [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const { if constexpr(sizeof...(Type) == 1u) { return (assure>()->get(entt), ...); } else { return stl::forward_as_tuple(get(entt)...); } } /*! @copydoc get */ template [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) { if constexpr(sizeof...(Type) == 1u) { return (static_cast &>(assure>()).get(entt), ...); } else { return stl::forward_as_tuple(get(entt)...); } } /** * @brief Returns a reference to the given element for an entity. * * In case the entity doesn't own the element, the parameters provided are * used to construct it. * * @sa get * @sa emplace * * @tparam Type Type of element to get. * @tparam Args Types of arguments to use to construct the element. * @param entt A valid identifier. * @param args Parameters to use to initialize the element. * @return Reference to the element owned by the entity. */ template [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) { auto &cpool = assure(); ENTT_ASSERT(valid(entt), "Invalid entity"); return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, stl::forward(args)...); } /** * @brief Returns pointers to the given elements for an entity. * * @note * The registry retains ownership of the pointed-to elements. * * @tparam Type Types of elements to get. * @param entt A valid identifier. * @return Pointers to the elements owned by the entity. */ template [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const { if constexpr(sizeof...(Type) == 1u) { const auto *cpool = assure...>(); return (cpool && cpool->contains(entt)) ? stl::addressof(cpool->get(entt)) : nullptr; } else { return stl::make_tuple(try_get(entt)...); } } /*! @copydoc try_get */ template [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) { if constexpr(sizeof...(Type) == 1u) { return (const_cast(stl::as_const(*this).template try_get(entt)), ...); } else { return stl::make_tuple(try_get(entt)...); } } /** * @brief Clears a whole registry or the pools for the given elements. * @tparam Type Types of elements to remove from their entities. */ template void clear() { if constexpr(sizeof...(Type) == 0u) { for(size_type pos = pools.size(); pos; --pos) { pools.begin()[static_cast(pos - 1u)].second->clear(); } const auto elem = entities.each(); entities.erase(elem.begin().base(), elem.end().base()); } else { (assure().clear(), ...); } } /** * @brief Checks if an entity has elements assigned. * @param entt A valid identifier. * @return True if the entity has no elements assigned, false otherwise. */ [[nodiscard]] bool orphan(const entity_type entt) const { return stl::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); }); } /** * @brief Returns a sink object for the given element. * * Use this function to receive notifications whenever a new instance of the * given element 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** assigning the element to the entity. * * @sa sink * * @tparam Type Type of element of which to get the sink. * @param id Optional name used to map the storage within the registry. * @return A temporary sink object. */ template [[nodiscard]] auto on_construct(const id_type id = type_hash::value()) { return assure(id).on_construct(); } /** * @brief Returns a sink object for the given element. * * Use this function to receive notifications whenever an instance of the * given element is explicitly updated.
* The function type for a listener is equivalent to: * * @code{.cpp} * void(basic_registry &, Entity); * @endcode * * Listeners are invoked **after** updating the element. * * @sa sink * * @tparam Type Type of element of which to get the sink. * @param id Optional name used to map the storage within the registry. * @return A temporary sink object. */ template [[nodiscard]] auto on_update(const id_type id = type_hash::value()) { return assure(id).on_update(); } /** * @brief Returns a sink object for the given element. * * Use this function to receive notifications whenever an instance of the * given element 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** removing the element from the entity. * * @sa sink * * @tparam Type Type of element of which to get the sink. * @param id Optional name used to map the storage within the registry. * @return A temporary sink object. */ template [[nodiscard]] auto on_destroy(const id_type id = type_hash::value()) { return assure(id).on_destroy(); } /** * @brief Returns a view for the given elements. * @tparam Type Type of element used to construct the view. * @tparam Other Other types of elements used to construct the view. * @tparam Exclude Types of elements used to filter the view. * @return A newly created view. */ template [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> view(exclude_t = exclude_t{}) const { basic_view, storage_for_type...>, exclude_t...>> elem{}; [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure>()..., assure>()..., assure>()); return elem; } /*! @copydoc view */ template [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> view(exclude_t = exclude_t{}) { return {assure>(), assure>()..., assure>()...}; } /** * @brief Returns a group for the given elements. * @tparam Owned Types of storage _owned_ by the group. * @tparam Get Types of storage _observed_ by the group, if any. * @tparam Exclude Types of storage used to filter the group, if any. * @return A newly created group. */ template basic_group...>, get_t...>, exclude_t...>> group(get_t = get_t{}, exclude_t = exclude_t{}) { using group_type = basic_group...>, get_t...>, exclude_t...>>; using handler_type = group_type::handler; if(auto it = groups.find(group_type::group_id()); it != groups.cend()) { return {*stl::static_pointer_cast(it->second)}; } stl::shared_ptr handler{}; if constexpr(sizeof...(Owned) == 0u) { handler = stl::allocate_shared(get_allocator(), get_allocator(), stl::forward_as_tuple(assure>()...), stl::forward_as_tuple(assure>()...)); } else { handler = stl::allocate_shared(get_allocator(), stl::forward_as_tuple(assure>()..., assure>()...), stl::forward_as_tuple(assure>()...)); ENTT_ASSERT(stl::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id().hash()) || ...); }), "Conflicting groups"); } groups.emplace(group_type::group_id(), handler); return {*handler}; } /*! @copydoc group */ template [[nodiscard]] basic_group...>, get_t...>, exclude_t...>> group_if_exists(get_t = get_t{}, exclude_t = exclude_t{}) const { using group_type = basic_group...>, get_t...>, exclude_t...>>; using handler_type = group_type::handler; if(auto it = groups.find(group_type::group_id()); it != groups.cend()) { return {*stl::static_pointer_cast(it->second)}; } return {}; } /** * @brief Checks whether the given elements belong to any group. * @tparam Type Types of elements in which one is interested. * @return True if the pools of the given elements are _free_, false * otherwise. */ template [[nodiscard]] bool owned() const { return stl::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id().hash()) || ...); }); } /** * @brief Sorts the elements of a given element. * * The comparison function object returns `true` if the first element is * _less_ than the second one, `false` otherwise. Its signature is also * equivalent to one of the following: * * @code{.cpp} * bool(const Entity, const Entity); * bool(const Type &, const Type &); * @endcode * * Moreover, it shall induce a _strict weak ordering_ on the values.
* The sort function object offers an `operator()` that accepts: * * * 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 object to use to compare the elements. * * The comparison function object hasn't necessarily the type of the one * passed along with the other parameters to this member function. * * @warning * Pools of elements owned by a group cannot be sorted. * * @tparam Type Type of elements 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(!owned(), "Cannot sort owned storage"); auto &cpool = assure(); if constexpr(stl::is_invocable_v) { auto comp = [&cpool, compare = stl::move(compare)](const auto lhs, const auto rhs) { return compare(stl::as_const(cpool.get(lhs)), stl::as_const(cpool.get(rhs))); }; cpool.sort(stl::move(comp), stl::move(algo), stl::forward(args)...); } else { cpool.sort(stl::move(compare), stl::move(algo), stl::forward(args)...); } } /** * @brief Sorts two pools of elements in the same way. * * Entities and elements in `To` which are part of both storage are sorted * internally with the order they have in `From`. The others follow in no * particular order. * * @warning * Pools of elements owned by a group cannot be sorted. * * @tparam To Type of elements to sort. * @tparam From Type of elements to use to sort. */ template void sort() { ENTT_ASSERT(!owned(), "Cannot sort owned storage"); const base_type &cpool = assure(); assure().sort_as(cpool.begin(), cpool.end()); } /** * @brief Returns the context object, that is, a general purpose container. * @return The context object, that is, a general purpose container. */ [[nodiscard]] context &ctx() noexcept { return vars; } /*! @copydoc ctx */ [[nodiscard]] const context &ctx() const noexcept { return vars; } private: context vars; pool_container_type pools; group_container_type groups; storage_for_type entities; }; } // namespace entt #endif // #include "entity/runtime_view.hpp" #ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP #define ENTT_ENTITY_RUNTIME_VIEW_HPP // #include "../stl/algorithm.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class runtime_view_iterator final { using iterator_type = Set::iterator; using iterator_traits = stl::iterator_traits; [[nodiscard]] bool valid() const { return (!tombstone_check || *it != tombstone) && stl::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); }) && stl::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); }); } public: using value_type = iterator_traits::value_type; using pointer = iterator_traits::pointer; using reference = iterator_traits::reference; using difference_type = iterator_traits::difference_type; using iterator_category = stl::bidirectional_iterator_tag; constexpr runtime_view_iterator() noexcept : pools{}, filter{}, it{}, tombstone_check{} {} runtime_view_iterator(const stl::vector &cpools, iterator_type curr, const stl::vector &ignore) noexcept : pools{&cpools}, filter{&ignore}, it{curr}, tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} { if(it != (*pools)[0]->end() && !valid()) { ++(*this); } } runtime_view_iterator &operator++() { ++it; for(const auto last = (*pools)[0]->end(); it != last && !valid(); ++it) {} return *this; } runtime_view_iterator operator++(int) { const runtime_view_iterator orig = *this; return ++(*this), orig; } runtime_view_iterator &operator--() { --it; for(const auto first = (*pools)[0]->begin(); it != first && !valid(); --it) {} return *this; } runtime_view_iterator operator--(int) { const runtime_view_iterator orig = *this; return operator--(), orig; } [[nodiscard]] pointer operator->() const noexcept { return it.operator->(); } [[nodiscard]] reference operator*() const noexcept { return *operator->(); } [[nodiscard]] constexpr bool operator==(const runtime_view_iterator &other) const noexcept { return it == other.it; } private: const stl::vector *pools; const stl::vector *filter; iterator_type it; bool tombstone_check; }; } // namespace internal /*! @endcond */ /** * @brief Generic runtime view. * * Runtime views iterate over those entities that are at least in the given * storage. During initialization, a runtime view looks at the number of * entities available for each element and uses the smallest set in order to get * a performance boost when iterating. * * @b Important * * Iterators aren't invalidated if: * * * New elements are added to the storage. * * The entity currently pointed is modified (for example, elements are added * or removed from it). * * The entity currently pointed is destroyed. * * In all other cases, modifying the storage iterated by the view in any way * invalidates all the iterators. * * @tparam Type Common base type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_runtime_view { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_type = stl::vector; [[nodiscard]] auto offset() const noexcept { ENTT_ASSERT(!pools.empty(), "Invalid view"); const auto &leading = *pools.front(); return (leading.policy() == deletion_policy::swap_only) ? leading.free_list() : leading.size(); } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Underlying entity identifier. */ using entity_type = Type::entity_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Common type among all storage types. */ using common_type = Type; /*! @brief Bidirectional iterator type. */ using iterator = internal::runtime_view_iterator; /*! @brief Default constructor to use to create empty, invalid views. */ basic_runtime_view() noexcept : basic_runtime_view{allocator_type{}} {} /** * @brief Constructs an empty, invalid view with a given allocator. * @param allocator The allocator to use. */ explicit basic_runtime_view(const allocator_type &allocator) : pools{allocator}, filter{allocator} {} /*! @brief Default copy constructor. */ basic_runtime_view(const basic_runtime_view &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ basic_runtime_view(const basic_runtime_view &other, const allocator_type &allocator) : pools{other.pools, allocator}, filter{other.filter, allocator} {} /*! @brief Default move constructor. */ basic_runtime_view(basic_runtime_view &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator) : pools{stl::move(other.pools), allocator}, filter{stl::move(other.filter), allocator} {} /*! @brief Default destructor. */ ~basic_runtime_view() = default; /** * @brief Default copy assignment operator. * @return This runtime view. */ basic_runtime_view &operator=(const basic_runtime_view &) = default; /** * @brief Default move assignment operator. * @return This runtime view. */ basic_runtime_view &operator=(basic_runtime_view &&) noexcept = default; /** * @brief Exchanges the contents with those of a given view. * @param other View to exchange the content with. */ void swap(basic_runtime_view &other) noexcept { using stl::swap; swap(pools, other.pools); swap(filter, other.filter); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return pools.get_allocator(); } /*! @brief Clears the view. */ void clear() { pools.clear(); filter.clear(); } /** * @brief Appends an opaque storage object to a runtime view. * @param base An opaque reference to a storage object. * @return This runtime view. */ basic_runtime_view &iterate(common_type &base) { if(pools.empty() || !(base.size() < pools.front()->size())) { pools.push_back(&base); } else { pools.push_back(stl::exchange(pools.front(), &base)); } return *this; } /** * @brief Adds an opaque storage object as a filter of a runtime view. * @param base An opaque reference to a storage object. * @return This runtime view. */ basic_runtime_view &exclude(common_type &base) { filter.push_back(&base); return *this; } /** * @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 pools.empty() ? size_type{} : offset(); } /** * @brief Returns an iterator to the first entity that has the given * elements. * * If the view is empty, the returned iterator will be equal to `end()`. * * @return An iterator to the first entity that has the given elements. */ [[nodiscard]] iterator begin() const { return pools.empty() ? iterator{} : iterator{pools, pools.front()->end() - static_cast(offset()), filter}; } /** * @brief Returns an iterator that is past the last entity that has the * given elements. * @return An iterator to the entity following the last entity that has the * given elements. */ [[nodiscard]] iterator end() const { return pools.empty() ? iterator{} : iterator{pools, pools.front()->end(), filter}; } /** * @brief Checks whether a view is initialized or not. * @return True if the view is initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return !(pools.empty() && filter.empty()); } /** * @brief Checks if a view contains an entity. * @param entt A valid identifier. * @return True if the view contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const { return !pools.empty() && stl::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); }) && stl::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); }) && pools.front()->index(entt) < offset(); } /** * @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.
* 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: container_type pools; container_type filter; }; } // namespace entt #endif // #include "entity/snapshot.hpp" #ifndef ENTT_ENTITY_SNAPSHOT_HPP #define ENTT_ENTITY_SNAPSHOT_HPP // #include "../config/config.h" // #include "../container/dense_map.hpp" // #include "../core/type_traits.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "entity.hpp" // #include "fwd.hpp" // #include "view.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template void orphans(Registry ®istry) { for(auto &storage = registry.template storage(); auto entt: storage) { if(registry.orphan(entt)) { storage.erase(entt); } } } } // namespace internal /*! @endcond */ /** * @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 elements of interest.
* This type can be used in both cases if provided with a correctly configured * output archive. * * @tparam Registry Basic registry type. */ template class basic_snapshot { static_assert(!stl::is_const_v, "Non-const registry type required"); using traits_type = entt_traits; public: /*! Basic registry type. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /** * @brief Constructs an instance that is bound to a given registry. * @param source A valid reference to a registry. */ basic_snapshot(const registry_type &source) noexcept : reg{&source} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_snapshot(const basic_snapshot &) = delete; /*! @brief Default move constructor. */ basic_snapshot(basic_snapshot &&) noexcept = default; /*! @brief Default destructor. */ ~basic_snapshot() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This snapshot. */ basic_snapshot &operator=(const basic_snapshot &) = delete; /** * @brief Default move assignment operator. * @return This snapshot. */ basic_snapshot &operator=(basic_snapshot &&) noexcept = default; /** * @brief Serializes all elements of a type with associated identifiers. * @tparam Type Type of elements to serialize. * @tparam Archive Type of output archive. * @param archive A valid reference to an output archive. * @param id Optional name used to map the storage within the registry. * @return An object of this type to continue creating the snapshot. */ template const basic_snapshot &get(Archive &archive, const id_type id = type_hash::value()) const { if(const auto *storage = reg->template storage(id); storage) { const typename registry_type::common_type &base = *storage; archive(static_cast(storage->size())); if constexpr(stl::is_same_v) { archive(static_cast(storage->free_list())); for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) { archive(*first); } } else if constexpr(registry_type::template storage_for_type::storage_policy == deletion_policy::in_place) { for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) { if(const auto entt = *it; entt == tombstone) { archive(static_cast(null)); } else { archive(entt); stl::apply([&archive](auto &&...args) { (archive(stl::forward(args)), ...); }, storage->get_as_tuple(entt)); } } } else { for(auto elem: storage->reach()) { stl::apply([&archive](auto &&...args) { (archive(stl::forward(args)), ...); }, elem); } } } else { archive(typename traits_type::entity_type{}); } return *this; } /** * @brief Serializes all elements of a type with associated identifiers for * the entities in a range. * @tparam Type Type of elements to serialize. * @tparam Archive Type of output archive. * @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. * @param id Optional name used to map the storage within the registry. * @return An object of this type to continue creating the snapshot. */ template const basic_snapshot &get(Archive &archive, stl::input_iterator auto first, stl::input_iterator auto last, const id_type id = type_hash::value()) const { static_assert(!stl::is_same_v, "Entity types not supported"); if(const auto *storage = reg->template storage(id); storage && !storage->empty()) { archive(static_cast(stl::distance(first, last))); for(; first != last; ++first) { if(const auto entt = *first; storage->contains(entt)) { archive(entt); stl::apply([&archive](auto &&...args) { (archive(stl::forward(args)), ...); }, storage->get_as_tuple(entt)); } else { archive(static_cast(null)); } } } else { archive(typename traits_type::entity_type{}); } return *this; } private: const registry_type *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 Registry Basic registry type. */ template class basic_snapshot_loader { static_assert(!stl::is_const_v, "Non-const registry type required"); using traits_type = entt_traits; public: /*! Basic registry type. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /** * @brief Constructs an instance that is bound to a given registry. * @param source A valid reference to a registry. */ basic_snapshot_loader(registry_type &source) noexcept : reg{&source} { // restoring a snapshot as a whole requires a clean registry ENTT_ASSERT(reg->template storage().free_list() == 0u, "Registry must be empty"); } /*! @brief Default copy constructor, deleted on purpose. */ basic_snapshot_loader(const basic_snapshot_loader &) = delete; /*! @brief Default move constructor. */ basic_snapshot_loader(basic_snapshot_loader &&) noexcept = default; /*! @brief Default destructor. */ ~basic_snapshot_loader() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This loader. */ basic_snapshot_loader &operator=(const basic_snapshot_loader &) = delete; /** * @brief Default move assignment operator. * @return This loader. */ basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default; /** * @brief Restores all elements of a type with associated identifiers. * @tparam Type Type of elements to restore. * @tparam Archive Type of input archive. * @param archive A valid reference to an input archive. * @param id Optional name used to map the storage within the registry. * @return A valid loader to continue restoring data. */ template basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash::value()) { auto &storage = reg->template storage(id); typename traits_type::entity_type length{}; archive(length); if constexpr(stl::is_same_v) { typename traits_type::entity_type count{}; entity_type placeholder{}; storage.reserve(length); archive(count); for(entity_type entity = null; length; --length) { archive(entity); storage.generate(entity); placeholder = (entity > placeholder) ? entity : placeholder; } storage.start_from(traits_type::next(placeholder)); storage.free_list(count); } else { auto &other = reg->template storage(); entity_type entt{null}; while(length--) { if(archive(entt); entt != null) { const auto entity = other.contains(entt) ? entt : other.generate(entt); ENTT_ASSERT(entity == entt, "Entity not available for use"); if constexpr(stl::tuple_size_v == 0u) { storage.emplace(entity); } else { Type elem{}; archive(elem); storage.emplace(entity, stl::move(elem)); } } } } return *this; } /** * @brief Destroys those entities that have no elements. * * In case all the entities were serialized but only part of the elements * was saved, it could happen that some of the entities have no elements * once restored.
* This function helps to identify and destroy those entities. * * @return A valid loader to continue restoring data. */ basic_snapshot_loader &orphans() { internal::orphans(*reg); return *this; } private: registry_type *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 application with * the requirement of transferring somehow parts of the representation side to * side. * * @tparam Registry Basic registry type. */ template class basic_continuous_loader { static_assert(!stl::is_const_v, "Non-const registry type required"); using traits_type = entt_traits; void restore(Registry::entity_type entt) { if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) { if(!reg->valid(remloc[entity].second)) { remloc[entity].second = reg->create(); } } else { remloc.insert_or_assign(entity, stl::make_pair(entt, reg->create())); } } template auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) { // map like container Container other; for(auto &&pair: container) { using first_type = stl::remove_const_t::first_type>; using second_type = stl::decay_t::second_type; if constexpr(stl::is_same_v && stl::is_same_v) { other.emplace(map(pair.first), map(pair.second)); } else if constexpr(stl::is_same_v) { other.emplace(map(pair.first), stl::move(pair.second)); } else { static_assert(stl::is_same_v, "Neither the key nor the value are of entity type"); other.emplace(stl::move(pair.first), map(pair.second)); } } using stl::swap; swap(container, other); } template auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) { // vector like container static_assert(stl::is_same_v, "Invalid value type"); for(auto &&entt: container) { entt = map(entt); } } template void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) { if constexpr(!stl::is_same_v) { return; } else if constexpr(stl::is_same_v) { instance.*member = map(instance.*member); } else { // maybe a container? let's try... update(0, instance.*member); } } public: /*! Basic registry type. */ using registry_type = Registry; /*! @brief Underlying entity identifier. */ using entity_type = registry_type::entity_type; /** * @brief Constructs an instance that is bound to a given registry. * @param source A valid reference to a registry. */ basic_continuous_loader(registry_type &source) noexcept : remloc{source.get_allocator()}, reg{&source} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_continuous_loader(const basic_continuous_loader &) = delete; /*! @brief Default move constructor. */ basic_continuous_loader(basic_continuous_loader &&) noexcept = default; /*! @brief Default destructor. */ ~basic_continuous_loader() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This loader. */ basic_continuous_loader &operator=(const basic_continuous_loader &) = delete; /** * @brief Default move assignment operator. * @return This loader. */ basic_continuous_loader &operator=(basic_continuous_loader &&) noexcept = default; /** * @brief Restores all elements of a type with associated identifiers. * * It creates local counterparts for remote elements as needed.
* Members are either data members of type entity_type or containers of * entities. In both cases, a loader visits them and replaces entities with * their local counterpart. * * @tparam Type Type of elements to restore. * @tparam Archive Type of input archive. * @param archive A valid reference to an input archive. * @param id Optional name used to map the storage within the registry. * @return A valid loader to continue restoring data. */ template basic_continuous_loader &get(Archive &archive, const id_type id = type_hash::value()) { auto &storage = reg->template storage(id); typename traits_type::entity_type length{}; entity_type entt{null}; archive(length); if constexpr(stl::is_same_v) { typename traits_type::entity_type in_use{}; storage.reserve(length); archive(in_use); for(stl::size_t pos{}; pos < in_use; ++pos) { archive(entt); restore(entt); } for(stl::size_t pos = in_use; pos < length; ++pos) { archive(entt); if(const auto entity = to_entity(entt); remloc.contains(entity)) { if(reg->valid(remloc[entity].second)) { reg->destroy(remloc[entity].second); } remloc.erase(entity); } } } else { for(auto &&ref: remloc) { storage.remove(ref.second.second); } while(length--) { if(archive(entt); entt != null) { restore(entt); if constexpr(stl::tuple_size_v == 0u) { storage.emplace(map(entt)); } else { Type elem{}; archive(elem); storage.emplace(map(entt), stl::move(elem)); } } } } return *this; } /** * @brief Destroys those entities that have no elements. * * In case all the entities were serialized but only part of the elements * was saved, it could happen that some of the entities have no elements * once restored.
* This function helps to identify and destroy those entities. * * @return A non-const reference to this loader. */ basic_continuous_loader &orphans() { internal::orphans(*reg); return *this; } /** * @brief Tests if a loader knows about a given entity. * @param entt A valid identifier. * @return True if `entity` is managed by the loader, false otherwise. */ [[nodiscard]] bool contains(entity_type entt) const noexcept { const auto it = remloc.find(to_entity(entt)); return it != remloc.cend() && it->second.first == entt; } /** * @brief Returns the identifier to which an entity refers. * @param entt A valid identifier. * @return The local identifier if any, the null entity otherwise. */ [[nodiscard]] entity_type map(entity_type entt) const noexcept { if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) { return it->second.second; } return null; } private: dense_map> remloc; registry_type *reg; }; } // namespace entt #endif // #include "entity/sparse_set.hpp" #ifndef ENTT_ENTITY_SPARSE_SET_HPP #define ENTT_ENTITY_SPARSE_SET_HPP #include // #include "../config/config.h" // #include "../core/algorithm.hpp" // #include "../core/any.hpp" // #include "../core/bit.hpp" // #include "../core/type_info.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct sparse_set_iterator final { using value_type = Container::value_type; using pointer = Container::const_pointer; using reference = Container::const_reference; using difference_type = Container::difference_type; using iterator_category = stl::random_access_iterator_tag; constexpr sparse_set_iterator() noexcept : packed{}, offset{} {} constexpr sparse_set_iterator(const Container &ref, const difference_type idx) noexcept : packed{&ref}, offset{idx} {} constexpr sparse_set_iterator &operator++() noexcept { return --offset, *this; } constexpr sparse_set_iterator operator++(int) noexcept { const sparse_set_iterator orig = *this; return ++(*this), orig; } constexpr sparse_set_iterator &operator--() noexcept { return ++offset, *this; } constexpr sparse_set_iterator operator--(int) noexcept { const sparse_set_iterator orig = *this; return operator--(), orig; } constexpr sparse_set_iterator &operator+=(const difference_type value) noexcept { offset -= value; return *this; } constexpr sparse_set_iterator operator+(const difference_type value) const noexcept { sparse_set_iterator copy = *this; return (copy += value); } constexpr sparse_set_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr sparse_set_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return (*packed)[static_cast(index() - value)]; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(operator[](0)); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } [[nodiscard]] constexpr stl::ptrdiff_t operator-(const sparse_set_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset - offset; } [[nodiscard]] constexpr bool operator==(const sparse_set_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr auto operator<=>(const sparse_set_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset <=> offset; } [[nodiscard]] constexpr pointer data() const noexcept { return packed ? packed->data() : nullptr; } [[nodiscard]] constexpr difference_type index() const noexcept { return offset - 1; } private: const Container *packed; difference_type offset; }; } // namespace internal /*! @endcond */ /** * @brief 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 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_sparse_set { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector; using traits_type = entt_traits; static constexpr auto max_size = static_cast(traits_type::to_entity(null)); // it could be auto but gcc complains and emits a warning due to a false positive [[nodiscard]] stl::size_t policy_to_head() const noexcept { return static_cast(max_size * static_cast>(mode != deletion_policy::swap_only)); } [[nodiscard]] auto entity_to_pos(const Entity entt) const noexcept { return static_cast(traits_type::to_entity(entt)); } [[nodiscard]] auto pos_to_page(const stl::size_t pos) const noexcept { return static_cast(pos / traits_type::page_size); } [[nodiscard]] auto sparse_ptr(const Entity entt) const { const auto pos = entity_to_pos(entt); const auto page = pos_to_page(pos); return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, traits_type::page_size)) : nullptr; } [[nodiscard]] auto &sparse_ref(const Entity entt) const { ENTT_ASSERT(sparse_ptr(entt), "Invalid element"); const auto pos = entity_to_pos(entt); return sparse[pos_to_page(pos)][fast_mod(pos, traits_type::page_size)]; } [[nodiscard]] auto to_iterator(const Entity entt) const { return --(end() - static_cast(index(entt))); } [[nodiscard]] auto &assure_at_least(const Entity entt) { const auto pos = entity_to_pos(entt); const auto page = pos_to_page(pos); if(!(page < sparse.size())) { sparse.resize(page + 1u, nullptr); } if(!sparse[page]) { constexpr entity_type init = null; auto page_allocator{packed.get_allocator()}; sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size); stl::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init); } return sparse[page][fast_mod(pos, traits_type::page_size)]; } void release_sparse_pages() { for(auto page_allocator{packed.get_allocator()}; auto &&page: sparse) { if(page != nullptr) { stl::destroy(page, page + traits_type::page_size); alloc_traits::deallocate(page_allocator, page, traits_type::page_size); page = nullptr; } } } void swap_at(const stl::size_t lhs, const stl::size_t rhs) { auto &from = packed[lhs]; auto &to = packed[rhs]; sparse_ref(from) = traits_type::combine(static_cast(rhs), traits_type::to_integral(from)); sparse_ref(to) = traits_type::combine(static_cast(lhs), traits_type::to_integral(to)); stl::swap(from, to); } private: [[nodiscard]] virtual const void *get_at(const stl::size_t) const { return nullptr; } virtual void swap_or_move([[maybe_unused]] const stl::size_t lhs, [[maybe_unused]] const stl::size_t rhs) { ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < head) == (rhs < head)), "Cross swapping is not supported"); } protected: /*! @brief Random access iterator type. */ using basic_iterator = internal::sparse_set_iterator; /** * @brief Erases an entity from a sparse set. * @param entt A valid identifier for the element to pop. */ void swap_only(const Entity entt) { ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch"); const auto pos = index(entt); bump(traits_type::next(entt)); swap_at(pos, head -= (pos < head)); } /** * @brief Erases an entity from a sparse set. * @param entt A valid identifier for the element to pop. */ void swap_and_pop(const Entity entt) { ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatch"); auto &self = sparse_ref(entt); const auto pos = traits_type::to_entity(self); sparse_ref(packed.back()) = traits_type::combine(pos, traits_type::to_integral(packed.back())); packed[static_cast(pos)] = packed.back(); // unnecessary but it helps to detect nasty bugs // NOLINTNEXTLINE(bugprone-assert-side-effect) ENTT_ASSERT((packed.back() = null, true), ""); // lazy self-assignment guard self = null; packed.pop_back(); } /** * @brief Erases an entity from a sparse set. * @param entt A valid identifier for the element to pop. */ void in_place_pop(const Entity entt) { ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch"); const auto pos = entity_to_pos(stl::exchange(sparse_ref(entt), null)); packed[pos] = traits_type::combine(static_cast(stl::exchange(head, pos)), tombstone); } /** * @brief Erases entities from a sparse set. * @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. */ virtual void pop(basic_iterator first, basic_iterator last) { switch(mode) { case deletion_policy::swap_and_pop: for(; first != last; ++first) { swap_and_pop(*first); } break; case deletion_policy::in_place: for(; first != last; ++first) { in_place_pop(*first); } break; case deletion_policy::swap_only: for(; first != last; ++first) { swap_only(*first); } break; } } /*! @brief Erases all entities of a sparse set. */ virtual void pop_all() { if(!packed.empty()) { // suboptimal with few entities, but exploits cache way more with many for(auto &&elem: sparse) { if(elem) { for(size_type pos{}; pos < traits_type::page_size; ++pos) { elem[pos] = null; } } } } head = policy_to_head(); packed.clear(); } /** * @brief Assigns an entity to a sparse set. * @param entt A valid identifier. * @param force_back Force back insertion. * @return Iterator pointing to the emplaced element. */ virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) { ENTT_ASSERT(entt != null && entt != tombstone, "Invalid element"); auto &elem = assure_at_least(entt); auto pos = size(); switch(mode) { case deletion_policy::in_place: if(head != max_size && !force_back) { pos = head; ENTT_ASSERT(elem == null, "Slot not available"); elem = traits_type::combine(static_cast(head), traits_type::to_integral(entt)); head = entity_to_pos(stl::exchange(packed[pos], entt)); break; } [[fallthrough]]; case deletion_policy::swap_and_pop: packed.push_back(entt); ENTT_ASSERT(elem == null, "Slot not available"); elem = traits_type::combine(static_cast(packed.size() - 1u), traits_type::to_integral(entt)); break; case deletion_policy::swap_only: if(elem == null) { packed.push_back(entt); elem = traits_type::combine(static_cast(packed.size() - 1u), traits_type::to_integral(entt)); } else { ENTT_ASSERT(!(entity_to_pos(elem) < head), "Slot not available"); bump(entt); } pos = head++; swap_at(entity_to_pos(elem), pos); break; } return iterator{packed, static_cast(++pos)}; } /*! @brief Forwards variables to derived classes, if any. */ // NOLINTNEXTLINE(performance-unnecessary-value-param) virtual void bind_any(any) noexcept {} public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Underlying entity identifier. */ using entity_type = traits_type::value_type; /*! @brief Underlying version type. */ using version_type = traits_type::version_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Pointer type to contained entities. */ using pointer = packed_container_type::const_pointer; /*! @brief Random access iterator type. */ using iterator = basic_iterator; /*! @brief Constant random access iterator type. */ using const_iterator = iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = stl::reverse_iterator; /*! @brief Default constructor. */ basic_sparse_set() : basic_sparse_set{type_id()} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit basic_sparse_set(const allocator_type &allocator) : basic_sparse_set{deletion_policy::swap_and_pop, allocator} {} /** * @brief Constructs an empty container with the given policy and allocator. * @param pol Type of deletion policy. * @param allocator The allocator to use (possibly default-constructed). */ explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {}) : basic_sparse_set{type_id(), pol, allocator} {} /** * @brief Constructs an empty container with the given value type, policy * and allocator. * @param elem Returned value type, if any. * @param pol Type of deletion policy. * @param allocator The allocator to use (possibly default-constructed). */ explicit basic_sparse_set(const type_info &elem, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {}) : sparse{allocator}, packed{allocator}, descriptor{&elem}, mode{pol}, head{policy_to_head()} { ENTT_ASSERT(traits_type::version_mask || mode != deletion_policy::in_place, "Policy does not support zero-sized versions"); } /*! @brief Default copy constructor, deleted on purpose. */ basic_sparse_set(const basic_sparse_set &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_sparse_set(basic_sparse_set &&other) noexcept : sparse{stl::move(other.sparse)}, packed{stl::move(other.packed)}, descriptor{other.descriptor}, mode{other.mode}, head{stl::exchange(other.head, policy_to_head())} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) : sparse{stl::move(other.sparse), allocator}, packed{stl::move(other.packed), allocator}, descriptor{other.descriptor}, mode{other.mode}, head{stl::exchange(other.head, policy_to_head())} { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed"); } /*! @brief Default destructor. */ virtual ~basic_sparse_set() { release_sparse_pages(); } /** * @brief Default copy assignment operator, deleted on purpose. * @return This sparse set. */ basic_sparse_set &operator=(const basic_sparse_set &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This sparse set. */ basic_sparse_set &operator=(basic_sparse_set &&other) noexcept { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed"); swap(other); return *this; } /** * @brief Exchanges the contents with those of a given sparse set. * @param other Sparse set to exchange the content with. */ void swap(basic_sparse_set &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(descriptor, other.descriptor); swap(mode, other.mode); swap(head, other.head); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return packed.get_allocator(); } /** * @brief Returns the deletion policy of a sparse set. * @return The deletion policy of the sparse set. */ [[nodiscard]] deletion_policy policy() const noexcept { return mode; } /** * @brief Returns data on the free list whose meaning depends on the mode. * @return Free list information that is mode dependent. */ [[nodiscard]] size_type free_list() const noexcept { return head; } /** * @brief Sets data on the free list whose meaning depends on the mode. * @param value Free list information that is mode dependent. */ void free_list(const size_type value) noexcept { ENTT_ASSERT((mode == deletion_policy::swap_only) && !(value > packed.size()), "Invalid value"); head = value; } /** * @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. */ virtual void reserve(const size_type cap) { packed.reserve(cap); } /** * @brief Returns the number of elements that a sparse set has currently * allocated space for. * @return Capacity of the sparse set. */ [[nodiscard]] virtual size_type capacity() const noexcept { return packed.capacity(); } /*! @brief Requests the removal of unused capacity. */ virtual void shrink_to_fit() { sparse_container_type other{sparse.get_allocator()}; const auto len = sparse.size(); other.reserve(len); for(size_type cnt{}; auto &&elem: stl::as_const(packed)) { if(elem != tombstone) { if(const auto page = pos_to_page(entity_to_pos(elem)); sparse[page] != nullptr) { if(const auto sz = page + 1u; sz > other.size()) { other.resize(sz, nullptr); } other[page] = stl::exchange(sparse[page], nullptr); if(++cnt == len) { // early exit due to lack of pages break; } } } } release_sparse_pages(); sparse.swap(other); 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 all pages have been allocated, nor that the * internal packed array is be the same size. * * @return Extent of the sparse set. */ [[nodiscard]] size_type extent() const noexcept { return sparse.size() * traits_type::page_size; } /** * @brief Returns the number of elements in a sparse set. * * The number of elements is also the size of the internal packed array. * There is no guarantee that the internal sparse array has the same size. * Usually the size of the internal sparse array is equal or greater than * the one of the internal packed array. * * @return Number of elements. */ [[nodiscard]] size_type size() const noexcept { return packed.size(); } /** * @brief Checks whether a sparse set is empty. * @return True if the sparse set is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.empty(); } /** * @brief Checks whether a sparse set is fully packed. * @return True if the sparse set is fully packed, false otherwise. */ [[nodiscard]] bool contiguous() const noexcept { return (mode != deletion_policy::in_place) || (head == max_size); } /** * @brief Direct access to the internal packed array. * @return A pointer to the internal packed array. */ [[nodiscard]] pointer data() const noexcept { return packed.data(); } /** * @brief Returns an iterator to the beginning. * * If the sparse set is empty, the returned iterator will be equal to * `end()`. * * @return An iterator to the first entity of the sparse set. */ [[nodiscard]] iterator begin() const noexcept { const auto pos = static_cast(packed.size()); return iterator{packed, pos}; } /*! @copydoc begin */ [[nodiscard]] const_iterator cbegin() const noexcept { return begin(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last entity of a sparse * set. */ [[nodiscard]] iterator end() const noexcept { return iterator{packed, {}}; } /*! @copydoc end */ [[nodiscard]] const_iterator cend() const noexcept { return end(); } /** * @brief Returns a reverse iterator to the beginning. * * 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 noexcept { return stl::make_reverse_iterator(end()); } /*! @copydoc rbegin */ [[nodiscard]] const_reverse_iterator crbegin() const noexcept { return rbegin(); } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last entity of the * reversed sparse set. */ [[nodiscard]] reverse_iterator rend() const noexcept { return stl::make_reverse_iterator(begin()); } /*! @copydoc rend */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return rend(); } /** * @brief Finds an entity. * @param entt A valid identifier. * @return An iterator to the given entity if it's found, past the end * iterator otherwise. */ [[nodiscard]] const_iterator find(const entity_type entt) const noexcept { return contains(entt) ? to_iterator(entt) : end(); } /** * @brief Checks if a sparse set contains an entity. * @param entt A valid identifier. * @return True if the sparse set contains the entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { const auto *elem = sparse_ptr(entt); constexpr auto cap = traits_type::entity_mask; constexpr auto mask = traits_type::to_integral(null) & ~cap; // testing versions permits to avoid accessing the packed array return elem && (((mask & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap); } /** * @brief Returns the contained version for an identifier. * @param entt A valid identifier. * @return The version for the given identifier if present, the tombstone * version otherwise. */ [[nodiscard]] version_type current(const entity_type entt) const noexcept { const auto *elem = sparse_ptr(entt); constexpr auto fallback = traits_type::to_version(tombstone); return elem ? traits_type::to_version(*elem) : fallback; } /** * @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 identifier. * @return The position of the entity in the sparse set. */ [[nodiscard]] size_type index(const entity_type entt) const noexcept { ENTT_ASSERT(contains(entt), "Set does not contain entity"); return entity_to_pos(sparse_ref(entt)); } /** * @brief Returns the entity at specified location. * @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 noexcept { ENTT_ASSERT(pos < packed.size(), "Index out of bounds"); return packed[pos]; } /** * @brief Returns the element assigned to an entity, if any. * * @warning * Attempting to use an entity that doesn't belong to the sparse set results * in undefined behavior. * * @param entt A valid identifier. * @return An opaque pointer to the element assigned to the entity, if any. */ [[nodiscard]] const void *value(const entity_type entt) const noexcept { return get_at(index(entt)); } /*! @copydoc value */ [[nodiscard]] void *value(const entity_type entt) noexcept { return const_cast(stl::as_const(*this).value(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. * * @param entt A valid identifier. * @param elem Optional opaque element to forward to mixins, if any. * @return Iterator pointing to the emplaced element in case of success, the * `end()` iterator otherwise. */ iterator push(const entity_type entt, const void *elem = nullptr) { return try_emplace(entt, false, elem); } /** * @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. * * @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 Iterator pointing to the first element inserted in case of * success, the `end()` iterator otherwise. */ iterator push(stl::input_iterator auto first, stl::input_iterator auto last) { auto curr = end(); for(; first != last; ++first) { curr = try_emplace(*first, true); } return curr; } /** * @brief Bump the version number of an entity. * * @warning * Attempting to bump the version of an entity that doesn't belong to the * sparse set results in undefined behavior. * * @param entt A valid identifier. * @return The version of the given identifier. */ version_type bump(const entity_type entt) { auto &elem = sparse_ref(entt); ENTT_ASSERT(entt != null && elem != tombstone, "Cannot set the required version"); elem = traits_type::combine(traits_type::to_integral(elem), traits_type::to_integral(entt)); packed[entity_to_pos(elem)] = entt; return traits_type::to_version(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 identifier. */ void erase(const entity_type entt) { const auto it = to_iterator(entt); pop(it, it + 1u); } /** * @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. */ template void erase(It first, It last) { if constexpr(stl::is_same_v) { pop(first, last); } else { for(; first != last; ++first) { erase(*first); } } } /** * @brief Removes an entity from a sparse set if it exists. * @param entt A valid identifier. * @return True if the entity is actually removed, false otherwise. */ bool remove(const entity_type entt) { return contains(entt) && (erase(entt), 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. * @return The number of entities actually removed. */ template size_type remove(It first, It last) { size_type count{}; if constexpr(stl::is_same_v) { while(first != last) { while(first != last && !contains(*first)) { ++first; } const auto it = first; while(first != last && contains(*first)) { ++first; } count += static_cast(stl::distance(it, first)); erase(it, first); } } else { for(; first != last; ++first) { count += remove(*first); } } return count; } /*! @brief Removes all tombstones from a sparse set. */ void compact() { if(mode == deletion_policy::in_place) { size_type from = packed.size(); size_type pos = stl::exchange(head, max_size); for(; from && packed[from - 1u] == tombstone; --from) {} while(pos != max_size) { if(const auto to = stl::exchange(pos, entity_to_pos(packed[pos])); to < from) { --from; swap_or_move(from, to); packed[to] = packed[from]; const auto elem = static_cast(to); sparse_ref(packed[to]) = traits_type::combine(elem, traits_type::to_integral(packed[to])); for(; from && packed[from - 1u] == tombstone; --from) {} } } packed.erase(packed.begin() + static_cast(from), packed.end()); } } /** * @brief Swaps two entities in a sparse set. * * 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 identifier. * @param rhs A valid identifier. */ void swap_elements(const entity_type lhs, const entity_type rhs) { const auto from = index(lhs); const auto to = index(rhs); // basic no-leak guarantee if swapping throws swap_or_move(from, to); swap_at(from, to); } /** * @brief Sort the first count elements according to the given comparison * function. * * The comparison function object must return `true` if the first element * is _less_ than the second one, `false` otherwise. The signature of the * comparison function should be equivalent to the following: * * @code{.cpp} * bool(const Entity, const Entity); * @endcode * * Moreover, the comparison function object shall induce a * _strict weak ordering_ on the values. * * The sort function object must offer a member function template * `operator()` that accepts three arguments: * * * An iterator to the first element of the range to sort. * * An iterator past the last element of the range to sort. * * A comparison function to use to compare the elements. * * @tparam Compare Type of comparison function object. * @tparam Sort Type of sort function object. * @tparam Args Types of arguments to forward to the sort function object. * @param 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) { ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements"); algo(packed.rend() - static_cast(length), packed.rend(), stl::move(compare), stl::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_or_move(next, idx); const auto elem = static_cast(curr); sparse_ref(entt) = traits_type::combine(elem, traits_type::to_integral(packed[curr])); curr = stl::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) { const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size(); sort_n(len, stl::move(compare), stl::move(algo), stl::forward(args)...); } /** * @brief Sort entities according to their order in a range. * * Entities that are part of both the sparse set and the range are ordered * internally according to the order they have in the range.
* All other entities goes to the end of the sparse set and there are no * guarantees on their order. * * @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 An iterator past the last of the elements actually shared. */ template iterator sort_as(It first, It last) { ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size(); auto it = end() - static_cast(len); for(const auto other = end(); (it != other) && (first != last); ++first) { if(const auto curr = *first; contains(curr)) { if(const auto entt = *it; entt != curr) { // basic no-leak guarantee (with invalid state) if swapping throws swap_elements(entt, curr); } ++it; } } return it; } /*! @brief Clears a sparse set. */ void clear() { pop_all(); // sanity check to avoid subtle issues due to storage classes ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set"); head = policy_to_head(); packed.clear(); } /** * @brief Returns a type info object for the value type, if any. * @return A type info object for the value type, if any. */ [[nodiscard]] const type_info &info() const noexcept { return *descriptor; } /** * @brief Forwards variables to derived classes, if any. * @tparam Type Type of the element to forward. * @param value The element to forward. */ template void bind(Type &&value) noexcept { bind_any(forward_as_any(stl::forward(value))); } private: sparse_container_type sparse; packed_container_type packed; const type_info *descriptor; deletion_policy mode; size_type head; }; } // namespace entt #endif // #include "entity/storage.hpp" #ifndef ENTT_ENTITY_STORAGE_HPP #define ENTT_ENTITY_STORAGE_HPP #include // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../core/iterator.hpp" // #include "../core/memory.hpp" // #include "../core/type_info.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "component.hpp" // #include "entity.hpp" // #include "fwd.hpp" // #include "sparse_set.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class storage_iterator final { template friend class storage_iterator; using container_type = stl::remove_const_t; using alloc_traits = stl::allocator_traits; using iterator_traits = stl::iterator_traits, typename alloc_traits::template rebind_traits::element_type>::const_pointer, typename alloc_traits::template rebind_traits::element_type>::pointer>>; public: using value_type = iterator_traits::value_type; using pointer = iterator_traits::pointer; using reference = iterator_traits::reference; using difference_type = iterator_traits::difference_type; using iterator_category = stl::random_access_iterator_tag; constexpr storage_iterator() noexcept = default; constexpr storage_iterator(Container *ref, const difference_type idx) noexcept : payload{ref}, offset{idx} {} template> Other> requires stl::is_const_v constexpr storage_iterator(const storage_iterator &other) noexcept : storage_iterator{other.payload, other.offset} {} constexpr storage_iterator &operator++() noexcept { return --offset, *this; } constexpr storage_iterator operator++(int) noexcept { const storage_iterator orig = *this; return ++(*this), orig; } constexpr storage_iterator &operator--() noexcept { return ++offset, *this; } constexpr storage_iterator operator--(int) noexcept { const storage_iterator orig = *this; return operator--(), orig; } constexpr storage_iterator &operator+=(const difference_type value) noexcept { offset -= value; return *this; } constexpr storage_iterator operator+(const difference_type value) const noexcept { storage_iterator copy = *this; return (copy += value); } constexpr storage_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr storage_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { const auto pos = static_cast(index() - value); return (*payload)[pos / Page][fast_mod(static_cast(pos), Page)]; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(operator[](0)); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const storage_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset - offset; } template [[nodiscard]] constexpr bool operator==(const storage_iterator &other) const noexcept { return offset == other.offset; } template [[nodiscard]] constexpr auto operator<=>(const storage_iterator &other) const noexcept { // intentionally reversed due to backward iteration return other.offset <=> offset; } [[nodiscard]] constexpr difference_type index() const noexcept { return offset - 1; } private: Container *payload; difference_type offset; }; template class extended_storage_iterator final { template friend class extended_storage_iterator; public: using iterator_type = It; using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::forward_as_tuple(*stl::declval()...))); using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr extended_storage_iterator() : it{} {} constexpr extended_storage_iterator(iterator_type base, Other... other) : it{base, other...} {} template requires (!stl::same_as && ...) && (stl::constructible_from && ...) constexpr extended_storage_iterator(const extended_storage_iterator &other) : it{other.it} {} constexpr extended_storage_iterator &operator++() noexcept { return ++stl::get(it), (++stl::get(it), ...), *this; } constexpr extended_storage_iterator operator++(int) noexcept { const extended_storage_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return {*stl::get(it), *stl::get(it)...}; } [[nodiscard]] constexpr iterator_type base() const noexcept { return stl::get(it); } template [[nodiscard]] constexpr bool operator==(const extended_storage_iterator &other) const noexcept { return stl::get<0>(it) == stl::get<0>(other.it); } private: stl::tuple it; }; } // namespace internal /*! @endcond */ /** * @brief Storage implementation. * * 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. * * @tparam Type Element type. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_storage: public basic_sparse_set::template rebind_alloc> { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_type = stl::vector>; using underlying_type = basic_sparse_set>; using underlying_iterator = underlying_type::basic_iterator; using traits_type = component_traits; [[nodiscard]] auto &element_at(const stl::size_t pos) const { return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)]; } auto assure_at_least(const stl::size_t pos) { const auto idx = pos / traits_type::page_size; if(!(idx < payload.size())) { auto curr = payload.size(); allocator_type allocator{get_allocator()}; payload.resize(idx + 1u, nullptr); ENTT_TRY { for(const auto last = payload.size(); curr < last; ++curr) { payload[curr] = alloc_traits::allocate(allocator, traits_type::page_size); } } ENTT_CATCH { payload.resize(curr); ENTT_THROW; } } return payload[idx] + fast_mod(pos, traits_type::page_size); } template auto emplace_element(const Entity entt, const bool force_back, Args &&...args) { const auto it = base_type::try_emplace(entt, force_back); ENTT_TRY { auto *elem = stl::to_address(assure_at_least(static_cast(it.index()))); entt::uninitialized_construct_using_allocator(elem, get_allocator(), stl::forward(args)...); } ENTT_CATCH { base_type::pop(it, it + 1u); ENTT_THROW; } return it; } void shrink_to_size(const stl::size_t sz) { const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size; allocator_type allocator{get_allocator()}; if constexpr(!stl::is_trivially_destructible_v) { for(auto pos = sz, length = base_type::size(); pos < length; ++pos) { if constexpr(traits_type::in_place_delete) { if(base_type::data()[pos] != tombstone) { alloc_traits::destroy(allocator, stl::addressof(element_at(pos))); } } else { alloc_traits::destroy(allocator, stl::addressof(element_at(pos))); } } } for(auto pos = from, last = payload.size(); pos < last; ++pos) { alloc_traits::deallocate(allocator, payload[pos], traits_type::page_size); } payload.resize(from); payload.shrink_to_fit(); } void swap_at(const stl::size_t lhs, const stl::size_t rhs) { using stl::swap; swap(element_at(lhs), element_at(rhs)); } void move_to(const stl::size_t lhs, const stl::size_t rhs) { auto &elem = element_at(lhs); allocator_type allocator{get_allocator()}; entt::uninitialized_construct_using_allocator(stl::to_address(assure_at_least(rhs)), allocator, stl::move(elem)); alloc_traits::destroy(allocator, stl::addressof(elem)); } private: [[nodiscard]] const void *get_at(const stl::size_t pos) const final { return stl::addressof(element_at(pos)); } void swap_or_move([[maybe_unused]] const stl::size_t from, [[maybe_unused]] const stl::size_t to) override { static constexpr bool is_pinned_type = !(stl::is_move_constructible_v && stl::is_move_assignable_v); // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy ENTT_ASSERT((from + 1u) && !is_pinned_type, "Pinned type"); if constexpr(!is_pinned_type) { if constexpr(traits_type::in_place_delete) { (base_type::operator[](to) == tombstone) ? move_to(from, to) : swap_at(from, to); } else { swap_at(from, to); } } } protected: /** * @brief Erases entities from a storage. * @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. */ void pop(underlying_iterator first, underlying_iterator last) override { for(allocator_type allocator{get_allocator()}; first != last; ++first) { // cannot use first.index() because it would break with cross iterators auto &elem = element_at(base_type::index(*first)); if constexpr(traits_type::in_place_delete) { base_type::in_place_pop(*first); alloc_traits::destroy(allocator, stl::addressof(elem)); } else if constexpr(stl::is_trivially_destructible_v) { elem = stl::move(element_at(base_type::size() - 1u)); base_type::swap_and_pop(*first); } else { auto &other = element_at(base_type::size() - 1u); // destroying on exit allows reentrant destructors [[maybe_unused]] auto unused = stl::exchange(elem, stl::move(other)); alloc_traits::destroy(allocator, stl::addressof(other)); base_type::swap_and_pop(*first); } } } /*! @brief Erases all entities of a storage. */ void pop_all() override { if constexpr(stl::is_trivially_destructible_v) { base_type::pop_all(); } else { allocator_type allocator{get_allocator()}; for(auto first = base_type::begin(); !(first.index() < 0); ++first) { if constexpr(traits_type::in_place_delete) { if(*first != tombstone) { base_type::in_place_pop(*first); alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast(first.index())))); } } else { base_type::swap_and_pop(*first); alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast(first.index())))); } } } } /** * @brief Assigns an entity to a storage. * @param entt A valid identifier. * @param value Optional opaque value. * @param force_back Force back insertion. * @return Iterator pointing to the emplaced element. */ underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override { if(value != nullptr) { if constexpr(stl::is_copy_constructible_v) { return emplace_element(entt, force_back, *static_cast(value)); } else { return base_type::end(); } } else { if constexpr(stl::is_default_constructible_v) { return emplace_element(entt, force_back); } else { return base_type::end(); } } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Base type. */ using base_type = underlying_type; /*! @brief Element type. */ using element_type = Type; /*! @brief Type of the objects assigned to entities. */ using value_type = element_type; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Pointer type to contained elements. */ using pointer = container_type::pointer; /*! @brief Constant pointer type to contained elements. */ using const_pointer = alloc_traits::template rebind_traits::const_pointer; /*! @brief Random access iterator type. */ using iterator = internal::storage_iterator; /*! @brief Constant random access iterator type. */ using const_iterator = internal::storage_iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = stl::reverse_iterator; /*! @brief Extended iterable storage proxy. */ using iterable = iterable_adaptor>; /*! @brief Constant extended iterable storage proxy. */ using const_iterable = iterable_adaptor>; /*! @brief Extended reverse iterable storage proxy. */ using reverse_iterable = iterable_adaptor>; /*! @brief Constant extended reverse iterable storage proxy. */ using const_reverse_iterable = iterable_adaptor>; /*! @brief Storage deletion policy. */ static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; /*! @brief Default constructor. */ basic_storage() : basic_storage{allocator_type{}} {} /** * @brief Constructs an empty storage with a given allocator. * @param allocator The allocator to use. */ explicit basic_storage(const allocator_type &allocator) : base_type{type_id(), storage_policy, allocator}, payload{allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_storage(const basic_storage &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_storage(basic_storage &&other) noexcept : base_type{static_cast(other)}, payload{stl::move(other.payload)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_storage(basic_storage &&other, const allocator_type &allocator) : base_type{static_cast(other), allocator}, payload{stl::move(other.payload), allocator} { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed"); } /*! @brief Default destructor. */ // NOLINTNEXTLINE(bugprone-exception-escape) ~basic_storage() override { shrink_to_size(0u); } /** * @brief Default copy assignment operator, deleted on purpose. * @return This storage. */ basic_storage &operator=(const basic_storage &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This storage. */ basic_storage &operator=(basic_storage &&other) noexcept { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed"); swap(other); return *this; } /** * @brief Exchanges the contents with those of a given storage. * @param other Storage to exchange the content with. */ void swap(basic_storage &other) noexcept { using stl::swap; swap(payload, other.payload); base_type::swap(other); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return payload.get_allocator(); } /** * @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) override { if(cap != 0u) { base_type::reserve(cap); assure_at_least(cap - 1u); } } /** * @brief Returns the number of elements that a storage has currently * allocated space for. * @return Capacity of the storage. */ [[nodiscard]] size_type capacity() const noexcept override { return payload.size() * traits_type::page_size; } /*! @brief Requests the removal of unused capacity. */ void shrink_to_fit() override { base_type::shrink_to_fit(); shrink_to_size(base_type::size()); } /** * @brief Direct access to the array of objects. * @return A pointer to the array of objects. */ [[nodiscard]] const_pointer raw() const noexcept { return payload.data(); } /*! @copydoc raw */ [[nodiscard]] pointer raw() noexcept { return payload.data(); } /** * @brief Returns an iterator to the beginning. * * 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 noexcept { const auto pos = static_cast(base_type::size()); return const_iterator{&payload, pos}; } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { const auto pos = static_cast(base_type::size()); return iterator{&payload, pos}; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return const_iterator{&payload, {}}; } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return iterator{&payload, {}}; } /** * @brief Returns a reverse iterator to the beginning. * * 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 noexcept { return stl::make_reverse_iterator(cend()); } /*! @copydoc crbegin */ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @copydoc rbegin */ [[nodiscard]] reverse_iterator rbegin() noexcept { return stl::make_reverse_iterator(end()); } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last instance of the * reversed internal array. */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return stl::make_reverse_iterator(cbegin()); } /*! @copydoc crend */ [[nodiscard]] const_reverse_iterator rend() const noexcept { return crend(); } /*! @copydoc rend */ [[nodiscard]] reverse_iterator rend() noexcept { return stl::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 identifier. * @return The object assigned to the entity. */ [[nodiscard]] const value_type &get(const entity_type entt) const noexcept { return element_at(base_type::index(entt)); } /*! @copydoc get */ [[nodiscard]] value_type &get(const entity_type entt) noexcept { return const_cast(stl::as_const(*this).get(entt)); } /** * @brief Returns the object assigned to an entity as a tuple. * @param entt A valid identifier. * @return The object assigned to the entity as a tuple. */ [[nodiscard]] stl::tuple get_as_tuple(const entity_type entt) const noexcept { return stl::forward_as_tuple(get(entt)); } /*! @copydoc get_as_tuple */ [[nodiscard]] stl::tuple get_as_tuple(const entity_type entt) noexcept { return stl::forward_as_tuple(get(entt)); } /** * @brief Assigns an entity to a storage and constructs its object. * * @warning * Attempting to use an entity that already belongs to the storage results * in undefined behavior. * * @tparam Args Types of arguments to use to construct the object. * @param entt A valid identifier. * @param args Parameters to use to construct an object for the entity. * @return A reference to the newly created object. */ template value_type &emplace(const entity_type entt, Args &&...args) { if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { const auto it = emplace_element(entt, false, Type{stl::forward(args)...}); return element_at(static_cast(it.index())); } else { const auto it = emplace_element(entt, false, stl::forward(args)...); return element_at(static_cast(it.index())); } } /** * @brief Updates the instance assigned to a given entity in-place. * @tparam Func Types of the function objects to invoke. * @param entt A valid identifier. * @param func Valid function objects. * @return A reference to the updated instance. */ template value_type &patch(const entity_type entt, Func &&...func) { const auto idx = base_type::index(entt); auto &elem = element_at(idx); (stl::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. * * @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. * @return Iterator pointing to the first element inserted, if any. */ iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value = {}) { for(; first != last; ++first) { emplace_element(*first, true, value); } return begin(); } /** * @brief Assigns one or more entities to a storage and constructs their * objects from a given range. * * @sa construct * * @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 from An iterator to the first element of the range of objects. * @return Iterator pointing to the first element inserted, if any. */ template requires stl::same_as::value_type, value_type> iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from) { for(; first != last; ++first, ++from) { emplace_element(*first, true, *from); } return begin(); } /** * @brief Returns an iterable object to use to _visit_ a storage. * * The iterable object returns a tuple that contains the current entity and * a reference to its element. * * @return An iterable object to use to _visit_ the storage. */ [[nodiscard]] iterable each() noexcept { return iterable{{base_type::begin(), begin()}, {base_type::end(), end()}}; } /*! @copydoc each */ [[nodiscard]] const_iterable each() const noexcept { return const_iterable{{base_type::cbegin(), cbegin()}, {base_type::cend(), cend()}}; } /** * @brief Returns a reverse iterable object to use to _visit_ a storage. * * @sa each * * @return A reverse iterable object to use to _visit_ the storage. */ [[nodiscard]] reverse_iterable reach() noexcept { return reverse_iterable{{base_type::rbegin(), rbegin()}, {base_type::rend(), rend()}}; } /*! @copydoc reach */ [[nodiscard]] const_reverse_iterable reach() const noexcept { return const_reverse_iterable{{base_type::crbegin(), crbegin()}, {base_type::crend(), crend()}}; } private: container_type payload; }; /*! @copydoc basic_storage */ template requires (component_traits::page_size == 0u) class basic_storage : public basic_sparse_set::template rebind_alloc> { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using traits_type = component_traits; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Base type. */ using base_type = basic_sparse_set>; /*! @brief Element type. */ using element_type = Type; /*! @brief Type of the objects assigned to entities. */ using value_type = void; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Extended iterable storage proxy. */ using iterable = iterable_adaptor>; /*! @brief Constant extended iterable storage proxy. */ using const_iterable = iterable_adaptor>; /*! @brief Extended reverse iterable storage proxy. */ using reverse_iterable = iterable_adaptor>; /*! @brief Constant extended reverse iterable storage proxy. */ using const_reverse_iterable = iterable_adaptor>; /*! @brief Storage deletion policy. */ static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; /*! @brief Default constructor. */ basic_storage() : basic_storage{allocator_type{}} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit basic_storage(const allocator_type &allocator) : base_type{type_id(), storage_policy, allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_storage(const basic_storage &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_storage(basic_storage &&other) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_storage(basic_storage &&other, const allocator_type &allocator) : base_type{stl::move(other), allocator} {} /*! @brief Default destructor. */ ~basic_storage() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This storage. */ basic_storage &operator=(const basic_storage &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This storage. */ basic_storage &operator=(basic_storage &&other) noexcept = default; /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return allocator_type{base_type::get_allocator()}; } /** * @brief Returns the object assigned to an entity, that is `void`. * * @warning * Attempting to use an entity that doesn't belong to the storage results in * undefined behavior. * * @param entt A valid identifier. */ void get([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); } /** * @brief Returns an empty tuple. * @param entt A valid identifier. * @return Returns an empty tuple. */ [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); return stl::tuple{}; } /** * @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. * * @param entt A valid identifier. */ void emplace(const entity_type entt, const auto &...) { base_type::try_emplace(entt, false); } /** * @brief Updates the instance assigned to a given entity in-place. * @tparam Func Types of the function objects to invoke. * @param entt A valid identifier. * @param func Valid function objects. */ template void patch([[maybe_unused]] const entity_type entt, Func &&...func) { ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); (stl::forward(func)(), ...); } /** * @brief Assigns entities to a storage. * @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. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...) { for(; first != last; ++first) { base_type::try_emplace(*first, true); } } /** * @brief Returns an iterable object to use to _visit_ a storage. * * The iterable object returns a tuple that contains the current entity. * * @return An iterable object to use to _visit_ the storage. */ [[nodiscard]] iterable each() noexcept { return iterable{base_type::begin(), base_type::end()}; } /*! @copydoc each */ [[nodiscard]] const_iterable each() const noexcept { return const_iterable{base_type::cbegin(), base_type::cend()}; } /** * @brief Returns a reverse iterable object to use to _visit_ a storage. * * @sa each * * @return A reverse iterable object to use to _visit_ the storage. */ [[nodiscard]] reverse_iterable reach() noexcept { return reverse_iterable{{base_type::rbegin()}, {base_type::rend()}}; } /*! @copydoc reach */ [[nodiscard]] const_reverse_iterable reach() const noexcept { return const_reverse_iterable{{base_type::crbegin()}, {base_type::crend()}}; } }; /** * @brief Swap-only entity storage specialization. * @tparam Entity A valid entity type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_storage : public basic_sparse_set { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using underlying_iterator = basic_sparse_set::basic_iterator; using traits_type = entt_traits; auto from_placeholder() noexcept { const auto entt = traits_type::combine(static_cast(placeholder), {}); ENTT_ASSERT(entt != null, "No more entities available"); placeholder += static_cast(entt != null); return entt; } auto next() noexcept { entity_type entt = from_placeholder(); while(base_type::current(entt) != traits_type::to_version(tombstone) && entt != null) { entt = from_placeholder(); } return entt; } protected: /*! @brief Erases all entities of a storage. */ void pop_all() override { base_type::pop_all(); placeholder = {}; } /** * @brief Assigns an entity to a storage. * @param hint A valid identifier. * @return Iterator pointing to the emplaced element. */ underlying_iterator try_emplace(const Entity hint, const bool, const void *) override { return base_type::find(generate(hint)); } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Base type. */ using base_type = basic_sparse_set; /*! @brief Element type. */ using element_type = Entity; /*! @brief Type of the objects assigned to entities. */ using value_type = void; /*! @brief Underlying entity identifier. */ using entity_type = Entity; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Extended iterable storage proxy. */ using iterable = iterable_adaptor>; /*! @brief Constant extended iterable storage proxy. */ using const_iterable = iterable_adaptor>; /*! @brief Extended reverse iterable storage proxy. */ using reverse_iterable = iterable_adaptor>; /*! @brief Constant extended reverse iterable storage proxy. */ using const_reverse_iterable = iterable_adaptor>; /*! @brief Storage deletion policy. */ static constexpr deletion_policy storage_policy = deletion_policy::swap_only; /*! @brief Default constructor. */ basic_storage() : basic_storage{allocator_type{}} { } /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit basic_storage(const allocator_type &allocator) : base_type{type_id(), storage_policy, allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_storage(const basic_storage &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) basic_storage(basic_storage &&other) noexcept : base_type{static_cast(other)}, placeholder{other.placeholder} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) basic_storage(basic_storage &&other, const allocator_type &allocator) : base_type{static_cast(other), allocator}, placeholder{other.placeholder} {} /*! @brief Default destructor. */ ~basic_storage() override = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This storage. */ basic_storage &operator=(const basic_storage &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This storage. */ basic_storage &operator=(basic_storage &&other) noexcept { placeholder = other.placeholder; base_type::operator=(stl::move(other)); return *this; } /** * @brief Exchanges the contents with those of a given storage. * @param other Storage to exchange the content with. */ void swap(basic_storage &other) noexcept { using stl::swap; swap(placeholder, other.placeholder); base_type::swap(other); } /** * @brief Returns the object assigned to an entity, that is `void`. * * @warning * Attempting to use an entity that doesn't belong to the storage results in * undefined behavior. * * @param entt A valid identifier. */ void get([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); } /** * @brief Returns an empty tuple. * @param entt A valid identifier. * @return Returns an empty tuple. */ [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept { ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); return stl::tuple{}; } /** * @brief Creates a new identifier or recycles a destroyed one. * @return A valid identifier. */ entity_type generate() { const auto len = base_type::free_list(); const auto entt = (len == base_type::size()) ? next() : base_type::data()[len]; return *base_type::try_emplace(entt, true); } /** * @brief Creates a new identifier or recycles a destroyed one. * * If the requested identifier isn't in use, the suggested one is used. * Otherwise, a new identifier is returned. * * @param hint Required identifier. * @return A valid identifier. */ entity_type generate(const entity_type hint) { if(hint != null && hint != tombstone) { if(const auto curr = traits_type::construct(traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone || !(base_type::index(curr) < base_type::free_list())) { return *base_type::try_emplace(hint, true); } } return generate(); } /** * @brief Assigns each element in a range an identifier. * @tparam It Type of output 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 It> void generate(It first, It last) { for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) { *first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true); } for(; first != last; ++first) { *first = *base_type::try_emplace(next(), true); } } /** * @brief Updates a given identifier. * @tparam Func Types of the function objects to invoke. * @param entt A valid identifier. * @param func Valid function objects. */ template void patch([[maybe_unused]] const entity_type entt, Func &&...func) { ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); (stl::forward(func)(), ...); } /** * @brief Returns an iterable object to use to _visit_ a storage. * * The iterable object returns a tuple that contains the current entity. * * @return An iterable object to use to _visit_ the storage. */ [[nodiscard]] iterable each() noexcept { return stl::as_const(*this).each(); } /*! @copydoc each */ [[nodiscard]] const_iterable each() const noexcept { const auto it = base_type::cend(); const auto offset = static_cast(base_type::free_list()); return const_iterable{it - offset, it}; } /** * @brief Returns a reverse iterable object to use to _visit_ a storage. * * @sa each * * @return A reverse iterable object to use to _visit_ the storage. */ [[nodiscard]] reverse_iterable reach() noexcept { return stl::as_const(*this).reach(); } /*! @copydoc reach */ [[nodiscard]] const_reverse_iterable reach() const noexcept { const auto it = base_type::crbegin(); const auto offset = static_cast(base_type::free_list()); return const_reverse_iterable{it, it + offset}; } /** * @brief Sets the starting identifier for generation. * * The version is ignored, regardless of the value. * * @param hint A valid identifier. */ void start_from(const entity_type hint) { placeholder = static_cast(traits_type::to_entity(hint)); } private: size_type placeholder{}; }; } // namespace entt #endif // #include "entity/view.hpp" #ifndef ENTT_ENTITY_VIEW_HPP #define ENTT_ENTITY_VIEW_HPP // #include "../config/config.h" // #include "../core/concepts.hpp" // #include "../core/iterator.hpp" // #include "../core/type_traits.hpp" // #include "../stl/array.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "entity.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template // NOLINTNEXTLINE(misc-redundant-expression) static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place)); template const Type *view_placeholder() { static const Type placeholder{}; return &placeholder; } [[nodiscard]] bool all_of(auto first, const auto last, const auto entt) noexcept { for(; (first != last) && (*first)->contains(entt); ++first) {} return first == last; } [[nodiscard]] bool none_of(auto first, const auto last, const auto entt) noexcept { for(; (first != last) && !(*first)->contains(entt); ++first) {} return first == last; } template [[nodiscard]] bool fully_initialized(It first, const It last, const stl::remove_pointer_t::value_type> *placeholder) noexcept { for(; (first != last) && *first != placeholder; ++first) {} return first == last; } template [[nodiscard]] Result view_pack(const View &view, const Other &other, stl::index_sequence, stl::index_sequence, stl::index_sequence, stl::index_sequence) { Result elem{}; // friend-initialization, avoid multiple calls to refresh elem.pools = {view.template storage()..., other.template storage()...}; [[maybe_unused]] const auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; }; elem.filter = {filter_or_placeholder(view.template storage())..., filter_or_placeholder(other.template storage())...}; elem.refresh(); return elem; } template class view_iterator final { template friend struct extended_view_iterator; using iterator_type = Type::const_iterator; using iterator_traits = stl::iterator_traits; [[nodiscard]] bool valid(const iterator_traits::value_type entt) const noexcept { return (!Checked || (entt != tombstone)) && ((Get == 1u) || (internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt))) && ((Exclude == 0u) || internal::none_of(filter.begin(), filter.end(), entt)); } void seek_next() { for(constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {} } public: using value_type = iterator_traits::value_type; using pointer = iterator_traits::pointer; using reference = iterator_traits::reference; using difference_type = iterator_traits::difference_type; using iterator_category = stl::forward_iterator_tag; constexpr view_iterator() noexcept : it{}, pools{}, filter{}, index{} {} view_iterator(iterator_type first, stl::array value, stl::array excl, const stl::size_t idx) noexcept : it{first}, pools{value}, filter{excl}, index{static_cast(idx)} { ENTT_ASSERT((Get != 1u) || (Exclude != 0u) || pools[0u]->policy() == deletion_policy::in_place, "Non in-place storage view iterator"); seek_next(); } view_iterator &operator++() noexcept { ++it; seek_next(); return *this; } view_iterator operator++(int) noexcept { const view_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] pointer operator->() const noexcept { return &*it; } [[nodiscard]] reference operator*() const noexcept { return *operator->(); } template [[nodiscard]] constexpr bool operator==(const view_iterator &other) const noexcept { return it == other.it; } private: iterator_type it; stl::array pools; stl::array filter; difference_type index; }; template struct extended_view_iterator final { using iterator_type = It; using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::declval().get_as_tuple({})...)); using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr extended_view_iterator() : it{} {} extended_view_iterator(iterator_type from) : it{from} {} extended_view_iterator &operator++() noexcept { return ++it, *this; } extended_view_iterator operator++(int) noexcept { const extended_view_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] reference operator*() const noexcept { return [this](stl::index_sequence) { return stl::tuple_cat(stl::make_tuple(*it), static_cast(const_cast *>(stl::get(it.pools)))->get_as_tuple(*it)...); }(stl::index_sequence_for{}); } [[nodiscard]] pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr iterator_type base() const noexcept { return it; } template [[nodiscard]] constexpr bool operator==(const extended_view_iterator &other) const noexcept { return it == other.it; } private: It it; }; } // namespace internal /*! @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. * * @b Important * * View iterators aren't invalidated if: * * * New elements are added to the storage iterated by the view. * * The entity currently returned is modified (for example, elements are added * or removed from it). * * The entity currently returned is destroyed. * * In all other cases, modifying the storage iterated by a view in any way can * invalidate all iterators. */ template class basic_view; /** * @brief Basic storage view implementation. * @warning For internal use only, backward compatibility not guaranteed. * @tparam Type Common type among all storage types. * @tparam Checked True to enable the tombstone check, false otherwise. * @tparam Get Number of storage iterated by the view. * @tparam Exclude Number of storage used to filter the view. */ template class basic_common_view { template friend Return internal::view_pack(const View &, const Other &, stl::index_sequence, stl::index_sequence, stl::index_sequence, stl::index_sequence); [[nodiscard]] auto offset() const noexcept { ENTT_ASSERT(index != Get, "Invalid view"); return (pools[index]->policy() == deletion_policy::swap_only) ? pools[index]->free_list() : pools[index]->size(); } void unchecked_refresh() noexcept { index = 0u; if constexpr(Get > 1u) { for(size_type pos{1u}; pos < Get; ++pos) { if(pools[pos]->size() < pools[index]->size()) { index = pos; } } } } protected: /*! @cond ENTT_INTERNAL */ basic_common_view() noexcept { for(size_type pos{}, last = filter.size(); pos < last; ++pos) { filter[pos] = placeholder; } } basic_common_view(stl::array value, stl::array excl) noexcept : pools{value}, filter{excl}, index{Get} { unchecked_refresh(); } [[nodiscard]] const Type *pool_at(const stl::size_t pos) const noexcept { return pools[pos]; } void pool_at(const stl::size_t pos, const Type *elem) noexcept { ENTT_ASSERT(elem != nullptr, "Unexpected element"); pools[pos] = elem; refresh(); } [[nodiscard]] const Type *filter_at(const stl::size_t pos) const noexcept { return (filter[pos] == placeholder) ? nullptr : filter[pos]; } void filter_at(const stl::size_t pos, const Type *elem) noexcept { ENTT_ASSERT(elem != nullptr, "Unexpected element"); filter[pos] = elem; } [[nodiscard]] bool none_of(const Type::entity_type entt) const noexcept { return internal::none_of(filter.begin(), filter.end(), entt); } void use(const stl::size_t pos) noexcept { index = (index != Get) ? pos : Get; } /*! @endcond */ public: /*! @brief Common type among all storage types. */ using common_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = Type::entity_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Forward iterator type. */ using iterator = internal::view_iterator; /*! @brief Updates the internal leading view if required. */ void refresh() noexcept { size_type pos = static_cast(index != Get) * Get; for(; pos < Get && pools[pos] != nullptr; ++pos) {} if(pos == Get) { unchecked_refresh(); } } /** * @brief Returns the leading storage of a view, if any. * @return The leading storage of the view. */ [[nodiscard]] const common_type *handle() const noexcept { return (index != Get) ? pools[index] : nullptr; } /** * @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 noexcept { return (index != Get) ? offset() : size_type{}; } /** * @brief Returns an iterator 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 noexcept { return (index != Get) ? iterator{pools[index]->end() - static_cast(offset()), pools, filter, index} : iterator{}; } /** * @brief Returns an iterator that is past the last entity of the view. * @return An iterator to the entity following the last entity of the view. */ [[nodiscard]] iterator end() const noexcept { return (index != Get) ? iterator{pools[index]->end(), pools, filter, index} : iterator{}; } /** * @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 noexcept { 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 noexcept { if(index != Get) { auto it = pools[index]->rbegin(); const auto last = it + static_cast(offset()); for(const auto idx = static_cast(index); it != last && !(internal::all_of(pools.begin(), pools.begin() + idx, *it) && internal::all_of(pools.begin() + idx + 1, pools.end(), *it) && internal::none_of(filter.begin(), filter.end(), *it)); ++it) {} return it == last ? null : *it; } return null; } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { return contains(entt) ? iterator{pools[index]->find(entt), pools, filter, index} : end(); } /** * @brief Checks if a view is fully initialized. * @return True if the view is fully initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (index != Get) && internal::fully_initialized(filter.begin(), filter.end(), placeholder); } /** * @brief Checks if a view contains an entity. * @param entt A valid identifier. * @return True if the view contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { return (index != Get) && internal::all_of(pools.begin(), pools.end(), entt) && internal::none_of(filter.begin(), filter.end(), entt) && pools[index]->index(entt) < offset(); } private: stl::array pools{}; stl::array filter{}; const common_type *placeholder{internal::view_placeholder()}; size_type index{Get}; }; /** * @brief General purpose view. * * This view visits all entities that are at least in the given storage. During * initialization, it also looks at the number of elements available for each * storage and uses the smallest set in order to get a performance boost. * * @sa basic_view * * @tparam Get Types of storage iterated by the view. * @tparam Exclude Types of storage used to filter the view. */ template requires (sizeof...(Get) != 0u) class basic_view, exclude_t> : public basic_common_view, internal::tombstone_check_v, sizeof...(Get), sizeof...(Exclude)> { using base_type = basic_common_view, internal::tombstone_check_v, sizeof...(Get), sizeof...(Exclude)>; template using element_at = type_list_element_t>; template static constexpr stl::size_t index_of = type_list_index_v, type_list>; template [[nodiscard]] auto dispatch_get(const stl::tuple &curr) const { if constexpr(Curr == Other) { return stl::forward_as_tuple(stl::get(curr)...); } else { return storage()->get_as_tuple(stl::get<0>(curr)); } } template void each(Func func, stl::index_sequence) const { for(const auto curr: storage()->each()) { if(const auto entt = stl::get<0>(curr); (!internal::tombstone_check_v || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) { if constexpr(is_applicable_v{}, stl::declval().get({})))>) { stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), dispatch_get(curr)...)); } else { stl::apply(func, stl::tuple_cat(dispatch_get(curr)...)); } } } } template void storage_if(Type *elem) noexcept { if(elem != nullptr) { storage>(*elem); } } public: /*! @brief Common type among all storage types. */ using common_type = base_type::common_type; /*! @brief Underlying entity identifier. */ using entity_type = base_type::entity_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Forward iterator type. */ using iterator = base_type::iterator; /*! @brief Iterable view type. */ using iterable = iterable_adaptor>; /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() noexcept : base_type{} {} /** * @brief Constructs a view from a set of storage classes. * @param value The storage for the types to iterate. * @param excl The storage for the types used to filter the view. */ basic_view(Get &...value, Exclude &...excl) noexcept : base_type{{&value...}, {&excl...}} { } /** * @brief Constructs a view from a set of storage classes. * @param value The storage for the types to iterate. * @param excl The storage for the types used to filter the view. */ basic_view(stl::tuple value, stl::tuple excl = {}) noexcept : basic_view{stl::make_from_tuple(stl::tuple_cat(value, excl))} {} /** * @brief Constructs a view from a convertible counterpart. * @tparam Args Storage types managed by the other view. * @param other A view to convert from. */ template requires (!stl::same_as>) basic_view(const basic_view &other) noexcept : basic_view{} { (storage_if(other.template storage()), ...); (storage_if(other.template storage()), ...); } /** * @brief Forces a view to use a given element to drive iterations * @tparam Type Type of element to use to drive iterations. */ template void use() noexcept { use>(); } /** * @brief Forces a view to use a given element to drive iterations * @tparam Index Index of the element to use to drive iterations. */ template void use() noexcept { base_type::use(Index); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { return storage>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { if constexpr(Index < sizeof...(Get)) { return static_cast *>(const_cast> *>(base_type::pool_at(Index))); } else { return static_cast *>(const_cast> *>(base_type::filter_at(Index - sizeof...(Get)))); } } /** * @brief Assigns a storage to a view. * @tparam Type Type of storage to assign to the view. * @param elem A storage to assign to the view. */ template void storage(Type &elem) noexcept { storage>(elem); } /** * @brief Assigns a storage to a view. * @tparam Index Index of the storage to assign to the view. * @tparam Type Type of storage to assign to the view. * @param elem A storage to assign to the view. */ template void storage(Type &elem) noexcept { static_assert(stl::is_convertible_v &>, "Unexpected type"); if constexpr(Index < sizeof...(Get)) { base_type::pool_at(Index, &elem); } else { base_type::filter_at(Index - sizeof...(Get), &elem); } } /** * @brief Returns the elements assigned to the given entity. * @param entt A valid identifier. * @return The elements assigned to the given entity. */ [[nodiscard]] decltype(auto) operator[](const entity_type entt) const { return get(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Type Type of the element to get. * @tparam Other Other types of elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { return get, index_of...>(entt); } /** * @brief Returns the elements assigned to the given entity. * @tparam Index Indexes of the elements to get. * @param entt A valid identifier. * @return The elements assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { if constexpr(sizeof...(Index) == 0) { return [this, entt](stl::index_sequence) { return stl::tuple_cat(this->storage()->get_as_tuple(entt)...); }(stl::index_sequence_for{}); } else if constexpr(sizeof...(Index) == 1) { return (storage()->get(entt), ...); } else { return stl::tuple_cat(storage()->get_as_tuple(entt)...); } } /** * @brief Iterates entities and elements and applies the given function * object to them. * * The signature of the function must be equivalent to one of the following * (non-empty types only, constness as requested): * * @code{.cpp} * void(const entity_type, Type &...); * void(Type &...); * @endcode * * @tparam Func Type of the function object to invoke. * @param func A valid function object. */ template void each(Func func) const { [this, &func](stl::index_sequence seq) { if(const auto *view = base_type::handle(); view != nullptr) { ((view == base_type::pool_at(Index) ? each(stl::move(func), seq) : void()), ...); } }(stl::index_sequence_for{}); } /** * @brief Returns an iterable object to use to _visit_ a view. * * The iterable object returns a tuple that contains the current entity and * a set of references to its non-empty elements. The _constness_ of the * elements is as requested. * * @return An iterable object to use to _visit_ the view. */ [[nodiscard]] iterable each() const noexcept { return iterable{base_type::begin(), base_type::end()}; } /** * @brief Combines a view and a storage in _more specific_ view. * @tparam OGet Type of storage to combine the view with. * @param other The storage for the type to combine the view with. * @return A more specific view. */ template OGet> [[nodiscard]] basic_view, exclude_t> operator|(OGet &other) const noexcept { return *this | basic_view, exclude_t<>>{other}; } /** * @brief Combines two views in a _more specific_ one. * @tparam OGet Element list of the view to combine with. * @tparam OExclude Filter list of the view to combine with. * @param other The view to combine with. * @return A more specific view. */ template... OGet, stl::derived_from... OExclude> [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { return internal::view_pack, exclude_t>>( *this, other, stl::index_sequence_for{}, stl::index_sequence_for{}, stl::index_sequence_for{}, stl::index_sequence_for{}); } }; /** * @brief Basic storage view implementation. * @warning For internal use only, backward compatibility not guaranteed. * @tparam Type Common type among all storage types. * @tparam Policy Storage policy. */ template class basic_storage_view { protected: /*! @cond ENTT_INTERNAL */ basic_storage_view() noexcept = default; basic_storage_view(const Type *value) noexcept : leading{value} { ENTT_ASSERT(leading->policy() == Policy, "Unexpected storage policy"); } /*! @endcond */ public: /*! @brief Common type among all storage types. */ using common_type = Type; /*! @brief Underlying entity identifier. */ using entity_type = common_type::entity_type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Random access iterator type. */ using iterator = stl::conditional_t, typename common_type::iterator>; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::conditional_t; /** * @brief Returns the leading storage of a view, if any. * @return The leading storage of the view. */ [[nodiscard]] const common_type *handle() const noexcept { return leading; } /** * @brief Returns the number of entities that have the given element. * @return Number of entities that have the given element. */ [[nodiscard]] size_type size() const noexcept requires (Policy != deletion_policy::in_place) { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->size() : size_type{}; } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return leading ? leading->free_list() : size_type{}; } } /** * @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 noexcept requires (Policy == deletion_policy::in_place) { return leading ? leading->size() : size_type{}; } /** * @brief Checks whether a view is empty. * @return True if the view is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept requires (Policy != deletion_policy::in_place) { if constexpr(Policy == deletion_policy::swap_and_pop) { return !leading || leading->empty(); } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return !leading || (leading->free_list() == 0u); } } /** * @brief Returns an iterator 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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->begin() : iterator{}; } else if constexpr(Policy == deletion_policy::swap_only) { return leading ? (leading->end() - static_cast(leading->free_list())) : iterator{}; } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); return leading ? iterator{leading->begin(), {leading}, {}, 0u} : iterator{}; } } /** * @brief Returns an iterator that is past the last entity of the view. * @return An iterator to the entity following the last entity of the view. */ [[nodiscard]] iterator end() const noexcept { if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) { return leading ? leading->end() : iterator{}; } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); return leading ? iterator{leading->end(), {leading}, {}, 0u} : iterator{}; } } /** * @brief Returns an iterator 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 noexcept requires (Policy != deletion_policy::in_place) { return leading ? leading->rbegin() : reverse_iterator{}; } /** * @brief Returns an iterator that is past the last entity of the reversed * view. * @return An iterator to the entity following the last entity of the * reversed view. */ [[nodiscard]] reverse_iterator rend() const noexcept requires (Policy != deletion_policy::in_place) { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->rend() : reverse_iterator{}; } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return leading ? (leading->rbegin() + static_cast(leading->free_list())) : reverse_iterator{}; } } /** * @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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop) { return empty() ? null : *leading->begin(); } else if constexpr(Policy == deletion_policy::swap_only) { return empty() ? null : *(leading->end() - static_cast(leading->free_list())); } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); const auto it = begin(); return (it == end()) ? null : *it; } } /** * @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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) { return empty() ? null : *leading->rbegin(); } else { static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); if(leading) { auto it = leading->rbegin(); const auto last = leading->rend(); for(; (it != last) && (*it == tombstone); ++it) {} return it == last ? null : *it; } return null; } } /** * @brief Finds an entity. * @param entt A valid 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 noexcept { if constexpr(Policy == deletion_policy::swap_and_pop) { return leading ? leading->find(entt) : iterator{}; } else if constexpr(Policy == deletion_policy::swap_only) { const auto it = leading ? leading->find(entt) : iterator{}; return leading && (static_cast(it.index()) < leading->free_list()) ? it : iterator{}; } else { return leading ? iterator{leading->find(entt), {leading}, {}, 0u} : iterator{}; } } /** * @brief Checks if a view is fully initialized. * @return True if the view is fully initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (leading != nullptr); } /** * @brief Checks if a view contains an entity. * @param entt A valid identifier. * @return True if the view contains the given entity, false otherwise. */ [[nodiscard]] bool contains(const entity_type entt) const noexcept { if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::in_place) { return leading && leading->contains(entt); } else { static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); return leading && leading->contains(entt) && (leading->index(entt) < leading->free_list()); } } private: const common_type *leading{}; }; /** * @brief Storage view specialization. * * This specialization offers a boost in terms of performance. It can access the * underlying data structure directly and avoid superfluous checks. * * @sa basic_view * * @tparam Get Type of storage iterated by the view. */ template class basic_view, exclude_t<>> : public basic_storage_view { using base_type = basic_storage_view; void storage_if(Get *value) noexcept { if(value != nullptr) { storage(*value); } } public: /*! @brief Common type among all storage types. */ using common_type = base_type::common_type; /*! @brief Underlying entity identifier. */ using entity_type = base_type::entity_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Random access iterator type. */ using iterator = base_type::iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = base_type::reverse_iterator; /*! @brief Iterable view type. */ using iterable = stl::conditional_t>, decltype(stl::declval().each())>; /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() noexcept : base_type{} {} /** * @brief Constructs a view from a storage class. * @param value The storage for the type to iterate. */ basic_view(Get &value) noexcept : base_type{&value} { } /** * @brief Constructs a view from a storage class. * @param value The storage for the type to iterate. */ basic_view(stl::tuple value, stl::tuple<> = {}) noexcept : basic_view{stl::get<0>(value)} {} /** * @brief Constructs a view from a convertible counterpart. * @tparam Args Storage types managed by the other view. * @param other A view to convert from. */ template requires (!stl::same_as>) basic_view(const basic_view &other) noexcept : base_type{} { storage_if(other.template storage()); } /** * @brief Returns the storage for a given element type, if any. * @tparam Type Type of element of which to return the storage. * @return The storage for the given element type. */ template [[nodiscard]] auto *storage() const noexcept { static_assert(stl::is_same_v, typename Get::element_type>, "Invalid element type"); return storage<0>(); } /** * @brief Returns the storage for a given index, if any. * @tparam Index Index of the storage to return. * @return The storage for the given index. */ template [[nodiscard]] auto *storage() const noexcept { static_assert(Index == 0u, "Index out of bounds"); return static_cast(const_cast *>(base_type::handle())); } /** * @brief Assigns a storage to a view. * @param elem A storage to assign to the view. */ void storage(Get &elem) noexcept { storage<0>(elem); } /** * @brief Assigns a storage to a view. * @tparam Index Index of the storage to assign to the view. * @param elem A storage to assign to the view. */ template void storage(Get &elem) noexcept { static_assert(Index == 0u, "Index out of bounds"); *this = basic_view{elem}; } /** * @brief Returns a pointer to the underlying storage. * @return A pointer to the underlying storage. */ [[nodiscard]] Get *operator->() const noexcept { return storage(); } /** * @brief Returns the element assigned to the given entity. * @param entt A valid identifier. * @return The element assigned to the given entity. */ [[nodiscard]] decltype(auto) operator[](const entity_type entt) const { return storage()->get(entt); } /** * @brief Returns the element assigned to the given entity. * @tparam Elem Type of the element to get. * @param entt A valid identifier. * @return The element assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { static_assert(stl::is_same_v, typename Get::element_type>, "Invalid element type"); return get<0>(entt); } /** * @brief Returns the element assigned to the given entity. * @tparam Index Index of the element to get. * @param entt A valid identifier. * @return The element assigned to the entity. */ template [[nodiscard]] decltype(auto) get(const entity_type entt) const { if constexpr(sizeof...(Index) == 0) { return storage()->get_as_tuple(entt); } else { return storage()->get(entt); } } /** * @brief Iterates entities and elements and applies the given function * object to them. * * The signature of the function must be equivalent to one of the following * (non-empty types only, constness as requested): * * @code{.cpp} * void(const entity_type, Type &); * void(Type &); * @endcode * * @tparam Func Type of the function object to invoke. * @param func A valid function object. */ template void each(Func func) const { if constexpr(is_applicable_v{}, stl::declval().get({})))>) { for(const auto pack: each()) { stl::apply(func, pack); } } else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) { if constexpr(stl::is_void_v) { for(size_type pos = base_type::size(); pos; --pos) { func(); } } else { if(const auto len = static_cast(base_type::size()); len != 0) { for(auto last = storage()->end(), first = last - len; first != last; ++first) { func(*first); } } } } else { static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy"); for(const auto pack: each()) { stl::apply([&func](const auto, auto &&...elem) { func(stl::forward(elem)...); }, pack); } } } /** * @brief Returns an iterable object to use to _visit_ a view. * * The iterable object returns a tuple that contains the current entity and * a reference to its element if it's a non-empty one. The _constness_ of * the element is as requested. * * @return An iterable object to use to _visit_ the view. */ [[nodiscard]] iterable each() const noexcept { if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) { return base_type::handle() ? storage()->each() : iterable{}; } else { static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy"); return iterable{base_type::begin(), base_type::end()}; } } /** * @brief Combines a view and a storage in _more specific_ view. * @tparam OGet Type of storage to combine the view with. * @param other The storage for the type to combine the view with. * @return A more specific view. */ template OGet> [[nodiscard]] basic_view, exclude_t<>> operator|(OGet &other) const noexcept { return *this | basic_view, exclude_t<>>{other}; } /** * @brief Combines two views in a _more specific_ one. * @tparam OGet Element list of the view to combine with. * @tparam OExclude Filter list of the view to combine with. * @param other The view to combine with. * @return A more specific view. */ template... OGet, stl::derived_from... OExclude> [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { return internal::view_pack, exclude_t>>( *this, other, stl::index_sequence_for{}, stl::index_sequence_for<>{}, stl::index_sequence_for{}, stl::index_sequence_for{}); } }; /** * @brief Deduction guide. * @tparam Type Type of storage classes used to create the view. * @param storage The storage for the types to iterate. */ template basic_view(Type &...storage) -> basic_view, exclude_t<>>; /** * @brief Deduction guide. * @tparam Get Types of elements iterated by the view. * @tparam Exclude Types of elements used to filter the view. */ template basic_view(stl::tuple, stl::tuple = {}) -> basic_view, exclude_t>; } // namespace entt #endif // #include "graph/adjacency_matrix.hpp" #ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP #define ENTT_GRAPH_ADJACENCY_MATRIX_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_GRAPH_FWD_HPP #define ENTT_GRAPH_FWD_HPP // #include "../core/fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" namespace entt { /*! @brief Undirected graph category tag. */ struct directed_tag {}; /*! @brief Directed graph category tag. */ struct undirected_tag: directed_tag {}; template, typename = stl::allocator> class adjacency_matrix; template> class basic_flow; /*! @brief Alias declaration for the most common use case. */ using flow = basic_flow<>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class edge_iterator { using size_type = stl::size_t; void find_next() noexcept { for(; pos != last && !it[static_cast(pos)]; pos += offset) {} } public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr edge_iterator() noexcept = default; // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept : it{stl::move(base)}, vert{vertices}, pos{from}, last{to}, offset{step} { find_next(); } constexpr edge_iterator &operator++() noexcept { pos += offset; find_next(); return *this; } constexpr edge_iterator operator++(int) noexcept { const edge_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr reference operator*() const noexcept { return *operator->(); } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::make_pair(pos / vert, pos % vert); } [[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept { return pos == other.pos; } private: It it{}; size_type vert{}; size_type pos{}; size_type last{}; size_type offset{}; }; } // namespace internal /*! @endcond */ /** * @brief Basic implementation of a directed adjacency matrix. * @tparam Category Either a directed or undirected category tag. * @tparam Allocator Type of allocator used to manage memory and elements. */ template Category, typename Allocator> class adjacency_matrix { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_type = stl::vector>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Vertex type. */ using vertex_type = size_type; /*! @brief Edge type. */ using edge_type = stl::pair; /*! @brief Vertex iterator type. */ using vertex_iterator = iota_iterator; /*! @brief Edge iterator type. */ using edge_iterator = internal::edge_iterator; /*! @brief Out-edge iterator type. */ using out_edge_iterator = edge_iterator; /*! @brief In-edge iterator type. */ using in_edge_iterator = edge_iterator; /*! @brief Graph category tag. */ using graph_category = Category; /*! @brief Default constructor. */ adjacency_matrix() noexcept(noexcept(allocator_type{})) : adjacency_matrix{0u} { } /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit adjacency_matrix(const allocator_type &allocator) noexcept : adjacency_matrix{0u, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied number of vertices. * @param vertices Number of vertices. * @param allocator The allocator to use. */ adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{}) : matrix{vertices * vertices, allocator}, vert{vertices} {} /*! @brief Default copy constructor. */ adjacency_matrix(const adjacency_matrix &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator) : matrix{other.matrix, allocator}, vert{other.vert} {} /*! @brief Default move constructor. */ adjacency_matrix(adjacency_matrix &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator) : matrix{stl::move(other.matrix), allocator}, vert{other.vert} {} /*! @brief Default destructor. */ ~adjacency_matrix() = default; /** * @brief Default copy assignment operator. * @return This container. */ adjacency_matrix &operator=(const adjacency_matrix &) = default; /** * @brief Default move assignment operator. * @return This container. */ adjacency_matrix &operator=(adjacency_matrix &&) noexcept = default; /** * @brief Exchanges the contents with those of a given adjacency matrix. * @param other Adjacency matrix to exchange the content with. */ void swap(adjacency_matrix &other) noexcept { using stl::swap; swap(matrix, other.matrix); swap(vert, other.vert); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return matrix.get_allocator(); } /*! @brief Clears the adjacency matrix. */ void clear() noexcept { matrix.clear(); vert = {}; } /** * @brief Returns true if an adjacency matrix is empty, false otherwise. * * @warning * Potentially expensive, try to avoid it on hot paths. * * @return True if the adjacency matrix is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { const auto iterable = edges(); return (iterable.begin() == iterable.end()); } /** * @brief Returns the number of vertices. * @return The number of vertices. */ [[nodiscard]] size_type size() const noexcept { return vert; } /** * @brief Returns an iterable object to visit all vertices of a matrix. * @return An iterable object to visit all vertices of a matrix. */ [[nodiscard]] iterable_adaptor vertices() const noexcept { return {0u, vert}; } /** * @brief Returns an iterable object to visit all edges of a matrix. * @return An iterable object to visit all edges of a matrix. */ [[nodiscard]] iterable_adaptor edges() const noexcept { const auto it = matrix.cbegin(); const auto sz = matrix.size(); return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}}; } /** * @brief Returns an iterable object to visit all out-edges of a vertex. * @param vertex The vertex of which to return all out-edges. * @return An iterable object to visit all out-edges of a vertex. */ [[nodiscard]] iterable_adaptor out_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex * vert; const auto to = from + vert; return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}}; } /** * @brief Returns an iterable object to visit all in-edges of a vertex. * @param vertex The vertex of which to return all in-edges. * @return An iterable object to visit all in-edges of a vertex. */ [[nodiscard]] iterable_adaptor in_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex; const auto to = vert * vert + from; return {{it, vert, from, to, vert}, {it, vert, to, to, vert}}; } /** * @brief Resizes an adjacency matrix. * @param vertices The new number of vertices. */ void resize(const size_type vertices) { adjacency_matrix other{vertices, get_allocator()}; for(auto [lhs, rhs]: edges()) { other.insert(lhs, rhs); } other.swap(*this); } /** * @brief Inserts an edge into the adjacency matrix, if it does not exist. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 1u; } const auto inserted = !stl::exchange(matrix[pos], 1u); return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted}; } /** * @brief Removes the edge associated with a pair of given vertices. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return Number of elements removed (either 0 or 1). */ size_type erase(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 0u; } return stl::exchange(matrix[pos], 0u); } /** * @brief Checks if an adjacency matrix contains a given edge. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return True if there is such an edge, false otherwise. */ [[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const { const auto pos = lhs * vert + rhs; return pos < matrix.size() && matrix[pos]; } private: container_type matrix; size_type vert; }; } // namespace entt #endif // #include "graph/dot.hpp" #ifndef ENTT_GRAPH_DOT_HPP #define ENTT_GRAPH_DOT_HPP // #include "../stl/concepts.hpp" // #include "../stl/ostream.hpp" #ifndef ENTT_STL_OSTREAM_HPP #define ENTT_STL_OSTREAM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ostream; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" namespace entt { /** * @brief Outputs a graph in dot format. * @tparam Graph Graph type, valid as long as it exposes edges and vertices. * @param out A standard output stream. * @param graph The graph to output. * @param writer Vertex decorator object. */ template requires stl::derived_from void dot(stl::ostream &out, const Graph &graph, stl::invocable auto writer) { if constexpr(stl::same_as) { out << "graph{"; } else { out << "digraph{"; } for(auto &&vertex: graph.vertices()) { out << vertex << "["; writer(out, vertex); out << "];"; } for(auto [lhs, rhs]: graph.edges()) { if constexpr(stl::same_as) { out << lhs << "--" << rhs << ";"; } else { out << lhs << "->" << rhs << ";"; } } out << "}"; } /** * @brief Outputs a graph in dot format. * @tparam Graph Graph type, valid as long as it exposes edges and vertices. * @param out A standard output stream. * @param graph The graph to output. */ template void dot(stl::ostream &out, const Graph &graph) { return dot(out, graph, [](auto &&...) {}); } } // namespace entt #endif // #include "graph/flow.hpp" #ifndef ENTT_GRAPH_FLOW_HPP #define ENTT_GRAPH_FLOW_HPP // #include "../config/config.h" // #include "../container/dense_map.hpp" #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" namespace entt { template< typename Key, typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator>> class dense_map; template< typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator> class dense_set; template class basic_table; /** * @brief Alias declaration for the most common use case. * @tparam Type Element types. */ template using table = basic_table...>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { using value_type = stl::pair; template dense_map_node(const stl::size_t pos, Args &&...args) : next{pos}, element{stl::forward(args)...} {} template dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) : next{pos}, element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, other.element)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} stl::size_t next; value_type element; }; template class dense_map_iterator final { template friend class dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr dense_map_iterator() noexcept : it{} {} constexpr dense_map_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_iterator(const dense_map_iterator &other) noexcept : it{other.it} {} constexpr dense_map_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_map_iterator operator++(int) noexcept { const dense_map_iterator orig = *this; return ++(*this), orig; } constexpr dense_map_iterator &operator--() noexcept { return --it, *this; } constexpr dense_map_iterator operator--(int) noexcept { const dense_map_iterator orig = *this; return operator--(), orig; } constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_map_iterator operator+(const difference_type value) const noexcept { dense_map_iterator copy = *this; return (copy += value); } constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_map_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].element.first, it[value].element.second}; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_map_local_iterator final { template friend class dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr dense_map_local_iterator() noexcept = default; constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_map_local_iterator &operator++() noexcept { return (offset = it[static_cast(offset)].next), *this; } constexpr dense_map_local_iterator operator++(int) noexcept { const dense_map_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { const auto idx = static_cast(offset); return {it[idx].element.first, it[idx].element.second}; } template [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_map_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for key-value pairs with unique keys. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on the hash of its key. Keys with the same hash * code appear in the same bucket. * * @tparam Key Key type of the associative container. * @tparam Type Mapped type of the associative container. * @tparam Hash Type of function to use to hash the keys. * @tparam KeyEqual Type of function to use to compare the keys for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_map { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; using node_type = internal::dense_map_node; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v>, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) return fast_mod(static_cast(sparse.second()(key)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } template [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { it->second = stl::forward(value); return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].next) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Key; /*! @brief Mapped type of the container. */ using mapped_type = Type; /*! @brief Key-value type of the container. */ using value_type = stl::pair; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the keys. */ using hasher = Hash; /*! @brief Type of function to use to compare the keys for equality. */ using key_equal = KeyEqual; /*! @brief Input iterator type. */ using iterator = internal::dense_map_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::dense_map_iterator; /*! @brief Input iterator type. */ using local_iterator = internal::dense_map_local_iterator; /*! @brief Constant input iterator type. */ using const_local_iterator = internal::dense_map_local_iterator; /*! @brief Default constructor. */ dense_map() : dense_map{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_map(const allocator_type &allocator) : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const allocator_type &allocator) : dense_map{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_map{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_map(const dense_map &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_map(const dense_map &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_map(dense_map &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_map(dense_map &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_map() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_map &operator=(const dense_map &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_map &operator=(dense_map &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_map &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if the key does not exist. * @param value A key-value pair eventually convertible to the value type. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value.first, value.second); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); } /** * @copydoc insert * @tparam Arg Type of the key-value pair to insert into the container. */ template requires stl::constructible_from stl::pair insert(Arg &&value) { return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); } /** * @brief Inserts elements into the container, if their keys do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Inserts an element into the container or assigns to the current * element if the key already exists. * @tparam Arg Type of the value to insert or assign. * @param key A key used both to look up and to insert if not found. * @param value A value to insert or assign. * @return A pair consisting of an iterator to the element and a bool * denoting whether the insertion took place. */ template stl::pair insert_or_assign(const key_type &key, Arg &&value) { return insert_or_overwrite(key, stl::forward(value)); } /*! @copydoc insert_or_assign */ template stl::pair insert_or_assign(key_type &&key, Arg &&value) { return insert_or_overwrite(stl::move(key), stl::forward(value)); } /** * @brief Constructs an element in-place, if the key does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace([[maybe_unused]] Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return insert_or_do_nothing(key_type{}); } else if constexpr(sizeof...(Args) == 1u) { return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); } else if constexpr(sizeof...(Args) == 2u) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); const auto index = key_to_bucket(node.element.first); if(auto it = constrained_find(node.element.first, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.next, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Inserts in-place if the key does not exist, does nothing if the * key exists. * @tparam Args Types of arguments to forward to the constructor of the * element. * @param key A key used both to look up and to insert if not found. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair try_emplace(const key_type &key, Args &&...args) { return insert_or_do_nothing(key, stl::forward(args)...); } /*! @copydoc try_emplace */ template stl::pair try_emplace(key_type &&key, Args &&...args) { return insert_or_do_nothing(stl::move(key), stl::forward(args)...); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(pos->first); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].element.first); } return (begin() + dist); } /** * @brief Removes the element associated with a given key. * @param key A key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const key_type &key) { for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { if(packed.second()(packed.first()[*curr].element.first, key)) { const auto index = *curr; *curr = packed.first()[*curr].next; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &at(const key_type &key) { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] const mapped_type &at(const key_type &key) const { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type const &at(const auto &key) const requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] mapped_type &at(const auto &key) requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](const key_type &key) { return insert_or_do_nothing(key).first->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](key_type &&key) { return insert_or_do_nothing(stl::move(key)).first->second; } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const key_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const key_type &key) { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const key_type &key) const { return constrained_find(key, key_to_bucket(key)); } /** * @brief Finds an element with a key that compares _equivalent_ to a given * key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &key) requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &key) const requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /** * @brief Returns a range containing all elements with a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const key_type &key) { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const key_type &key) const { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &key) requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &key) const requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given key. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const key_type &key) const { return (find(key) != cend()); } /** * @brief Checks if the container contains an element with a key that * compares _equivalent_ to a given value. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &key) const requires is_transparent_v && is_transparent_v { return (find(key) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given key. * @param key The value of the key to examine. * @return The bucket for the given key. */ [[nodiscard]] size_type bucket(const key_type &key) const { return key_to_bucket(key); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = key_to_bucket(packed.first()[pos].element.first); packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the keys. * @return The function used to hash the keys. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare keys for equality. * @return The function used to compare keys for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::true_type {}; } // namespace std /*! @endcond */ #endif // #include "../container/dense_set.hpp" #ifndef ENTT_CONTAINER_DENSE_SET_HPP #define ENTT_CONTAINER_DENSE_SET_HPP #include // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../core/compressed_pair.hpp" // #include "../core/type_traits.hpp" // #include "../stl/bit.hpp" // #include "../stl/cmath.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" // #include "../stl/iterator.hpp" // #include "../stl/limits.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits::max)(); template class dense_set_iterator final { template friend class dense_set_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); public: using value_type = stl::remove_const_t>::second_type; using pointer = const value_type *; using reference = const value_type &; using difference_type = stl::ptrdiff_t; using iterator_category = stl::random_access_iterator_tag; constexpr dense_set_iterator() noexcept : it{} {} constexpr dense_set_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_set_iterator(const dense_set_iterator &other) noexcept : it{other.it} {} constexpr dense_set_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_set_iterator operator++(int) noexcept { const dense_set_iterator orig = *this; return ++(*this), orig; } constexpr dense_set_iterator &operator--() noexcept { return --it, *this; } constexpr dense_set_iterator operator--(int) noexcept { const dense_set_iterator orig = *this; return operator--(), orig; } constexpr dense_set_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_set_iterator operator+(const difference_type value) const noexcept { dense_set_iterator copy = *this; return (copy += value); } constexpr dense_set_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_set_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return it[value].second; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(operator[](0)); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_set_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_set_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_set_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_set_local_iterator final { template friend class dense_set_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); public: using value_type = stl::remove_const_t>::second_type; using pointer = const value_type *; using reference = const value_type &; using difference_type = stl::ptrdiff_t; using iterator_category = stl::forward_iterator_tag; constexpr dense_set_local_iterator() noexcept = default; constexpr dense_set_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_set_local_iterator(const dense_set_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_set_local_iterator &operator++() noexcept { return offset = it[static_cast(offset)].first, *this; } constexpr dense_set_local_iterator operator++(int) noexcept { const dense_set_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::addressof(it[static_cast(offset)].second); } [[nodiscard]] constexpr reference operator*() const noexcept { return *operator->(); } template [[nodiscard]] constexpr bool operator==(const dense_set_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_set_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for unique objects of a given type. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on its hash. Elements with the same hash code * appear in the same bucket. * * @tparam Type Value type of the associative container. * @tparam Hash Type of function to use to hash the values. * @tparam KeyEqual Type of function to use to compare the values for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_set { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_set_placeholder_position; using node_type = stl::pair; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t value_to_bucket(const auto &value) const noexcept { return fast_mod(static_cast(sparse.second()(value)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { if(packed.second()(packed.first()[offset].second, value)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { if(packed.second()(packed.first()[offset].second, value)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&value) { const auto index = value_to_bucket(value); if(auto it = constrained_find(value, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[value_to_bucket(packed.first().back().second)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].first) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Type; /*! @brief Value type of the container. */ using value_type = Type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the elements. */ using hasher = Hash; /*! @brief Type of function to use to compare the elements for equality. */ using key_equal = KeyEqual; /*! @brief Random access iterator type. */ using iterator = internal::dense_set_iterator; /*! @brief Constant random access iterator type. */ using const_iterator = internal::dense_set_iterator; /*! @brief Reverse iterator type. */ using reverse_iterator = stl::reverse_iterator; /*! @brief Constant reverse iterator type. */ using const_reverse_iterator = stl::reverse_iterator; /*! @brief Forward iterator type. */ using local_iterator = internal::dense_set_local_iterator; /*! @brief Constant forward iterator type. */ using const_local_iterator = internal::dense_set_local_iterator; /*! @brief Default constructor. */ dense_set() : dense_set{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_set(const allocator_type &allocator) : dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_set(const size_type cnt, const allocator_type &allocator) : dense_set{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_set{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_set(const dense_set &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_set(const dense_set &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_set(dense_set &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_set(dense_set &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_set() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_set &operator=(const dense_set &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_set &operator=(dense_set &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_set &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Returns a reverse iterator to the beginning. * * If the array 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 noexcept { return stl::make_reverse_iterator(cend()); } /*! @copydoc crbegin */ [[nodiscard]] const_reverse_iterator rbegin() const noexcept { return crbegin(); } /*! @copydoc rbegin */ [[nodiscard]] reverse_iterator rbegin() noexcept { return stl::make_reverse_iterator(end()); } /** * @brief Returns a reverse iterator to the end. * @return An iterator to the element following the last instance of the * reversed internal array. */ [[nodiscard]] const_reverse_iterator crend() const noexcept { return stl::make_reverse_iterator(cbegin()); } /*! @copydoc crend */ [[nodiscard]] const_reverse_iterator rend() const noexcept { return crend(); } /*! @copydoc rend */ [[nodiscard]] reverse_iterator rend() noexcept { return stl::make_reverse_iterator(begin()); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if it does not exist. * @param value An element to insert into the container. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value)); } /** * @brief Inserts elements into the container, if they do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Constructs an element in-place, if it does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace(Args &&...args) { if constexpr(((sizeof...(Args) == 1u) && ... && stl::is_same_v, value_type>)) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(stl::piecewise_construct, stl::make_tuple(packed.first().size()), stl::forward_as_tuple(stl::forward(args)...)); const auto index = value_to_bucket(node.second); if(auto it = constrained_find(node.second, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.first, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(*pos); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].second); } return (begin() + dist); } /** * @brief Removes the element associated with a given value. * @param value Value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const value_type &value) { for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != placeholder_position; curr = &packed.first()[*curr].first) { if(packed.second()(packed.first()[*curr].second, value)) { const auto index = *curr; *curr = packed.first()[*curr].first; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Returns the number of elements matching a value (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const value_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given value. * @param value Value of an element to search for. * @return An iterator to an element with the given value. If no such * element is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const value_type &value) { return constrained_find(value, value_to_bucket(value)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const value_type &value) const { return constrained_find(value, value_to_bucket(value)); } /** * @brief Finds an element that compares _equivalent_ to a given value. * @param value Value of an element to search for. * @return An iterator to an element with the given value. If no such * element is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &value) requires is_transparent_v && is_transparent_v { return constrained_find(value, value_to_bucket(value)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &value) const requires is_transparent_v && is_transparent_v { return constrained_find(value, value_to_bucket(value)); } /** * @brief Returns a range containing all elements with a given value. * @param value Value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const value_type &value) { const auto it = find(value); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const value_type &value) const { const auto it = find(value); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given value. * @param value Value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &value) requires is_transparent_v && is_transparent_v { const auto it = find(value); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &value) const requires is_transparent_v && is_transparent_v { const auto it = find(value); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given value. * @param value Value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const value_type &value) const { return (find(value) != cend()); } /** * @brief Checks if the container contains an element that compares * _equivalent_ to a given value. * @param value Value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &value) const requires is_transparent_v && is_transparent_v { return (find(value) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given element. * @param value The value of the element to examine. * @return The bucket for the given element. */ [[nodiscard]] size_type bucket(const value_type &value) const { return value_to_bucket(value); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = value_to_bucket(packed.first()[pos].second); packed.first()[pos].first = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the elements. * @return The function used to hash the elements. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare elements for equality. * @return The function used to compare elements for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" // #include "../stl/algorithm.hpp" #ifndef ENTT_STL_ALGORITHM_HPP #define ENTT_STL_ALGORITHM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::all_of; using std::any_of; using std::find_if; using std::none_of; using std::sort; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "adjacency_matrix.hpp" #ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP #define ENTT_GRAPH_ADJACENCY_MATRIX_HPP // #include "../config/config.h" // #include "../core/iterator.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class edge_iterator { using size_type = stl::size_t; void find_next() noexcept { for(; pos != last && !it[static_cast(pos)]; pos += offset) {} } public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr edge_iterator() noexcept = default; // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept : it{stl::move(base)}, vert{vertices}, pos{from}, last{to}, offset{step} { find_next(); } constexpr edge_iterator &operator++() noexcept { pos += offset; find_next(); return *this; } constexpr edge_iterator operator++(int) noexcept { const edge_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr reference operator*() const noexcept { return *operator->(); } [[nodiscard]] constexpr pointer operator->() const noexcept { return stl::make_pair(pos / vert, pos % vert); } [[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept { return pos == other.pos; } private: It it{}; size_type vert{}; size_type pos{}; size_type last{}; size_type offset{}; }; } // namespace internal /*! @endcond */ /** * @brief Basic implementation of a directed adjacency matrix. * @tparam Category Either a directed or undirected category tag. * @tparam Allocator Type of allocator used to manage memory and elements. */ template Category, typename Allocator> class adjacency_matrix { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_type = stl::vector>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Vertex type. */ using vertex_type = size_type; /*! @brief Edge type. */ using edge_type = stl::pair; /*! @brief Vertex iterator type. */ using vertex_iterator = iota_iterator; /*! @brief Edge iterator type. */ using edge_iterator = internal::edge_iterator; /*! @brief Out-edge iterator type. */ using out_edge_iterator = edge_iterator; /*! @brief In-edge iterator type. */ using in_edge_iterator = edge_iterator; /*! @brief Graph category tag. */ using graph_category = Category; /*! @brief Default constructor. */ adjacency_matrix() noexcept(noexcept(allocator_type{})) : adjacency_matrix{0u} { } /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit adjacency_matrix(const allocator_type &allocator) noexcept : adjacency_matrix{0u, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied number of vertices. * @param vertices Number of vertices. * @param allocator The allocator to use. */ adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{}) : matrix{vertices * vertices, allocator}, vert{vertices} {} /*! @brief Default copy constructor. */ adjacency_matrix(const adjacency_matrix &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator) : matrix{other.matrix, allocator}, vert{other.vert} {} /*! @brief Default move constructor. */ adjacency_matrix(adjacency_matrix &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator) : matrix{stl::move(other.matrix), allocator}, vert{other.vert} {} /*! @brief Default destructor. */ ~adjacency_matrix() = default; /** * @brief Default copy assignment operator. * @return This container. */ adjacency_matrix &operator=(const adjacency_matrix &) = default; /** * @brief Default move assignment operator. * @return This container. */ adjacency_matrix &operator=(adjacency_matrix &&) noexcept = default; /** * @brief Exchanges the contents with those of a given adjacency matrix. * @param other Adjacency matrix to exchange the content with. */ void swap(adjacency_matrix &other) noexcept { using stl::swap; swap(matrix, other.matrix); swap(vert, other.vert); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return matrix.get_allocator(); } /*! @brief Clears the adjacency matrix. */ void clear() noexcept { matrix.clear(); vert = {}; } /** * @brief Returns true if an adjacency matrix is empty, false otherwise. * * @warning * Potentially expensive, try to avoid it on hot paths. * * @return True if the adjacency matrix is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { const auto iterable = edges(); return (iterable.begin() == iterable.end()); } /** * @brief Returns the number of vertices. * @return The number of vertices. */ [[nodiscard]] size_type size() const noexcept { return vert; } /** * @brief Returns an iterable object to visit all vertices of a matrix. * @return An iterable object to visit all vertices of a matrix. */ [[nodiscard]] iterable_adaptor vertices() const noexcept { return {0u, vert}; } /** * @brief Returns an iterable object to visit all edges of a matrix. * @return An iterable object to visit all edges of a matrix. */ [[nodiscard]] iterable_adaptor edges() const noexcept { const auto it = matrix.cbegin(); const auto sz = matrix.size(); return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}}; } /** * @brief Returns an iterable object to visit all out-edges of a vertex. * @param vertex The vertex of which to return all out-edges. * @return An iterable object to visit all out-edges of a vertex. */ [[nodiscard]] iterable_adaptor out_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex * vert; const auto to = from + vert; return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}}; } /** * @brief Returns an iterable object to visit all in-edges of a vertex. * @param vertex The vertex of which to return all in-edges. * @return An iterable object to visit all in-edges of a vertex. */ [[nodiscard]] iterable_adaptor in_edges(const vertex_type vertex) const noexcept { const auto it = matrix.cbegin(); const auto from = vertex; const auto to = vert * vert + from; return {{it, vert, from, to, vert}, {it, vert, to, to, vert}}; } /** * @brief Resizes an adjacency matrix. * @param vertices The new number of vertices. */ void resize(const size_type vertices) { adjacency_matrix other{vertices, get_allocator()}; for(auto [lhs, rhs]: edges()) { other.insert(lhs, rhs); } other.swap(*this); } /** * @brief Inserts an edge into the adjacency matrix, if it does not exist. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 1u; } const auto inserted = !stl::exchange(matrix[pos], 1u); return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted}; } /** * @brief Removes the edge associated with a pair of given vertices. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return Number of elements removed (either 0 or 1). */ size_type erase(const vertex_type lhs, const vertex_type rhs) { const auto pos = lhs * vert + rhs; if constexpr(stl::is_same_v) { const auto rev = rhs * vert + lhs; ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); matrix[rev] = 0u; } return stl::exchange(matrix[pos], 0u); } /** * @brief Checks if an adjacency matrix contains a given edge. * @param lhs The left hand vertex of the edge. * @param rhs The right hand vertex of the edge. * @return True if there is such an edge, false otherwise. */ [[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const { const auto pos = lhs * vert + rhs; return pos < matrix.size() && matrix[pos]; } private: container_type matrix; size_type vert; }; } // namespace entt #endif // #include "fwd.hpp" namespace entt { /** * @brief Utility class for creating task graphs. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_flow { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using task_container_type = dense_set, typename alloc_traits::template rebind_alloc>; using ro_rw_container_type = stl::vector, typename alloc_traits::template rebind_alloc>>; using deps_container_type = dense_map, typename alloc_traits::template rebind_alloc>>; using adjacency_matrix_type = adjacency_matrix>; void emplace(const id_type res, const bool is_rw) { ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); if(!deps.contains(res) && sync_on != vertices.size()) { deps[res].emplace_back(sync_on, true); } deps[res].emplace_back(index.first(), is_rw); } void setup_graph(adjacency_matrix_type &matrix) const { for(const auto &elem: deps) { const auto last = elem.second.cend(); auto it = elem.second.cbegin(); while(it != last) { if(it->second) { // rw item if(auto curr = it++; it != last) { if(it->second) { matrix.insert(curr->first, it->first); } else if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { for(; it != next; ++it) { matrix.insert(curr->first, it->first); matrix.insert(it->first, next->first); } } else { for(; it != next; ++it) { matrix.insert(curr->first, it->first); } } } } else { // ro item (first iteration only) if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { for(; it != next; ++it) { matrix.insert(it->first, next->first); } } else { it = last; } } } } } void transitive_closure(adjacency_matrix_type &matrix) const { const auto length = matrix.size(); for(stl::size_t vk{}; vk < length; ++vk) { for(stl::size_t vi{}; vi < length; ++vi) { for(stl::size_t vj{}; vj < length; ++vj) { if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) { matrix.insert(vi, vj); } } } } } void transitive_reduction(adjacency_matrix_type &matrix) const { const auto length = matrix.size(); for(stl::size_t vert{}; vert < length; ++vert) { matrix.erase(vert, vert); } for(stl::size_t vj{}; vj < length; ++vj) { for(stl::size_t vi{}; vi < length; ++vi) { if(matrix.contains(vi, vj)) { for(stl::size_t vk{}; vk < length; ++vk) { if(matrix.contains(vj, vk)) { matrix.erase(vi, vk); } } } } } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Iterable task list. */ using iterable = iterable_adaptor; /*! @brief Adjacency matrix type. */ using graph_type = adjacency_matrix_type; /*! @brief Default constructor. */ basic_flow() : basic_flow{allocator_type{}} {} /** * @brief Constructs a flow builder with a given allocator. * @param allocator The allocator to use. */ explicit basic_flow(const allocator_type &allocator) : index{0u, allocator}, vertices{allocator}, deps{allocator} {} /*! @brief Default copy constructor. */ basic_flow(const basic_flow &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ basic_flow(const basic_flow &other, const allocator_type &allocator) : index{other.index.first(), allocator}, vertices{other.vertices, allocator}, deps{other.deps, allocator}, sync_on{other.sync_on} {} /*! @brief Default move constructor. */ basic_flow(basic_flow &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_flow(basic_flow &&other, const allocator_type &allocator) : index{other.index.first(), allocator}, vertices{stl::move(other.vertices), allocator}, deps{stl::move(other.deps), allocator}, sync_on{other.sync_on} {} /*! @brief Default destructor. */ ~basic_flow() = default; /** * @brief Default copy assignment operator. * @return This flow builder. */ basic_flow &operator=(const basic_flow &) = default; /** * @brief Default move assignment operator. * @return This flow builder. */ basic_flow &operator=(basic_flow &&) noexcept = default; /** * @brief Exchanges the contents with those of a given flow builder. * @param other Flow builder to exchange the content with. */ void swap(basic_flow &other) noexcept { using stl::swap; swap(index, other.index); swap(vertices, other.vertices); swap(deps, other.deps); swap(sync_on, other.sync_on); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return allocator_type{index.second()}; } /** * @brief Returns the identifier at specified location. * @param pos Position of the identifier to return. * @return The requested identifier. */ [[nodiscard]] id_type operator[](const size_type pos) const { return vertices.cbegin()[static_cast(pos)]; } /*! @brief Clears the flow builder. */ void clear() noexcept { index.first() = {}; vertices.clear(); deps.clear(); sync_on = {}; } /** * @brief Returns true if a flow builder contains no tasks, false otherwise. * @return True if the flow builder contains no tasks, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return vertices.empty(); } /** * @brief Returns the number of tasks. * @return The number of tasks. */ [[nodiscard]] size_type size() const noexcept { return vertices.size(); } /** * @brief Binds a task to a flow builder. * @param value Task identifier. * @return This flow builder. */ basic_flow &bind(const id_type value) { sync_on += (sync_on == vertices.size()); const auto it = vertices.emplace(value).first; index.first() = size_type(it - vertices.begin()); return *this; } /** * @brief Turns the current task into a sync point. * @return This flow builder. */ basic_flow &sync() { ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); sync_on = index.first(); for(const auto &elem: deps) { elem.second.emplace_back(sync_on, true); } return *this; } /** * @brief Assigns a resource to the current task with a given access mode. * @param res Resource identifier. * @param is_rw Access mode. * @return This flow builder. */ basic_flow &set(const id_type res, bool is_rw = false) { emplace(res, is_rw); return *this; } /** * @brief Assigns a read-only resource to the current task. * @param res Resource identifier. * @return This flow builder. */ basic_flow &ro(const id_type res) { emplace(res, false); return *this; } /** * @brief Assigns a range of read-only resources to the current task. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return This flow builder. */ basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { emplace(*first, false); } return *this; } /** * @brief Assigns a writable resource to the current task. * @param res Resource identifier. * @return This flow builder. */ basic_flow &rw(const id_type res) { emplace(res, true); return *this; } /** * @brief Assigns a range of writable resources to the current task. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return This flow builder. */ basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { emplace(*first, true); } return *this; } /** * @brief Generates a task graph for the current content. * @return The adjacency matrix of the task graph. */ [[nodiscard]] graph_type graph() const { graph_type matrix{vertices.size(), get_allocator()}; setup_graph(matrix); transitive_closure(matrix); transitive_reduction(matrix); return matrix; } private: compressed_pair index; task_container_type vertices; deps_container_type deps; size_type sync_on{}; }; } // namespace entt #endif // #include "locator/locator.hpp" #ifndef ENTT_LOCATOR_LOCATOR_HPP #define ENTT_LOCATOR_LOCATOR_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Service locator, nothing more. * * A service locator is used to do what it promises: locate services.
* Usually service locators are tightly bound to the services they expose and * thus it's hard to define a general purpose class to do that. This tiny class * tries to fill the gap and to get rid of the burden of defining a different * specific locator for each application. * * @note * Users shouldn't retain references to a service. The recommended way is to * retrieve the service implementation currently set each and every time the * need for it arises. The risk is to incur in unexpected behaviors otherwise. * * @tparam Service Service type. */ template class locator final { class service_handle { friend class locator; stl::shared_ptr value{}; }; public: /*! @brief Service type. */ using type = Service; /*! @brief Service node type. */ using node_type = service_handle; /*! @brief Default constructor, deleted on purpose. */ locator() = delete; /*! @brief Default copy constructor, deleted on purpose. */ locator(const locator &) = delete; /*! @brief Default destructor, deleted on purpose. */ ~locator() = delete; /** * @brief Default copy assignment operator, deleted on purpose. * @return This locator. */ locator &operator=(const locator &) = delete; /** * @brief Checks whether a service locator contains a value. * @return True if the service locator contains a value, false otherwise. */ [[nodiscard]] static bool has_value() noexcept { return (service != nullptr); } /** * @brief Returns a reference to a valid service, if any. * * @warning * Invoking this function can result in undefined behavior if the service * hasn't been set yet. * * @return A reference to the service currently set, if any. */ [[nodiscard]] static Service &value() noexcept { ENTT_ASSERT(has_value(), "Service not available"); return *service; } /** * @brief Returns a service if available or sets it from a fallback type. * * Arguments are used only if a service doesn't already exist. In all other * cases, they are discarded. * * @tparam Args Types of arguments to use to construct the fallback service. * @tparam Type Fallback service type. * @param args Parameters to use to construct the fallback service. * @return A reference to a valid service. */ template Type = Service, typename... Args> requires stl::constructible_from [[nodiscard]] static Service &value_or(Args &&...args) { return service ? *service : emplace(stl::forward(args)...); } /** * @brief Sets or replaces a service. * @tparam Type Service type. * @tparam Args Types of arguments to use to construct the service. * @param args Parameters to use to construct the service. * @return A reference to a valid service. */ template Type = Service, typename... Args> requires stl::constructible_from static Service &emplace(Args &&...args) { service = stl::make_shared(stl::forward(args)...); return *service; } /** * @brief Sets or replaces a service using a given allocator. * @tparam Type Service type. * @tparam Args Types of arguments to use to construct the service. * @param alloc The allocator to use. * @param args Parameters to use to construct the service. * @return A reference to a valid service. */ template Type = Service, typename... Args> requires stl::constructible_from static Service &emplace(stl::allocator_arg_t, auto alloc, Args &&...args) { service = stl::allocate_shared(alloc, stl::forward(args)...); return *service; } /** * @brief Returns a handle to the underlying service. * @return A handle to the underlying service. */ static node_type handle() noexcept { node_type node{}; node.value = service; return node; } /** * @brief Resets or replaces a service. * @param other Optional handle with which to replace the service. */ static void reset(const node_type &other = {}) noexcept { service = other.value; } /** * @brief Resets or replaces a service. * @tparam Type Service type. * @tparam Deleter Deleter type. * @param elem A pointer to a service to manage. * @param deleter A deleter to use to destroy the service. */ template Type, typename Deleter = stl::default_delete> static void reset(Type *elem, Deleter deleter = {}) { service = stl::shared_ptr{elem, stl::move(deleter)}; } private: // stl::shared_ptr because of its type erased allocator which is useful here // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) inline static stl::shared_ptr service{}; }; } // 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); } }; } // namespace entt #endif // #include "meta/container.hpp" // IWYU pragma: always_keep #ifndef ENTT_META_CONTAINER_HPP #define ENTT_META_CONTAINER_HPP // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "context.hpp" #ifndef ENTT_META_CTX_HPP #define ENTT_META_CTX_HPP // #include "../container/dense_map.hpp" #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" namespace entt { template< typename Key, typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator>> class dense_map; template< typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator> class dense_set; template class basic_table; /** * @brief Alias declaration for the most common use case. * @tparam Type Element types. */ template using table = basic_table...>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { using value_type = stl::pair; template dense_map_node(const stl::size_t pos, Args &&...args) : next{pos}, element{stl::forward(args)...} {} template dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) : next{pos}, element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, other.element)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} stl::size_t next; value_type element; }; template class dense_map_iterator final { template friend class dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr dense_map_iterator() noexcept : it{} {} constexpr dense_map_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_iterator(const dense_map_iterator &other) noexcept : it{other.it} {} constexpr dense_map_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_map_iterator operator++(int) noexcept { const dense_map_iterator orig = *this; return ++(*this), orig; } constexpr dense_map_iterator &operator--() noexcept { return --it, *this; } constexpr dense_map_iterator operator--(int) noexcept { const dense_map_iterator orig = *this; return operator--(), orig; } constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_map_iterator operator+(const difference_type value) const noexcept { dense_map_iterator copy = *this; return (copy += value); } constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_map_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].element.first, it[value].element.second}; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_map_local_iterator final { template friend class dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr dense_map_local_iterator() noexcept = default; constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_map_local_iterator &operator++() noexcept { return (offset = it[static_cast(offset)].next), *this; } constexpr dense_map_local_iterator operator++(int) noexcept { const dense_map_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { const auto idx = static_cast(offset); return {it[idx].element.first, it[idx].element.second}; } template [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_map_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for key-value pairs with unique keys. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on the hash of its key. Keys with the same hash * code appear in the same bucket. * * @tparam Key Key type of the associative container. * @tparam Type Mapped type of the associative container. * @tparam Hash Type of function to use to hash the keys. * @tparam KeyEqual Type of function to use to compare the keys for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_map { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; using node_type = internal::dense_map_node; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v>, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) return fast_mod(static_cast(sparse.second()(key)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } template [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { it->second = stl::forward(value); return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].next) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Key; /*! @brief Mapped type of the container. */ using mapped_type = Type; /*! @brief Key-value type of the container. */ using value_type = stl::pair; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the keys. */ using hasher = Hash; /*! @brief Type of function to use to compare the keys for equality. */ using key_equal = KeyEqual; /*! @brief Input iterator type. */ using iterator = internal::dense_map_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::dense_map_iterator; /*! @brief Input iterator type. */ using local_iterator = internal::dense_map_local_iterator; /*! @brief Constant input iterator type. */ using const_local_iterator = internal::dense_map_local_iterator; /*! @brief Default constructor. */ dense_map() : dense_map{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_map(const allocator_type &allocator) : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const allocator_type &allocator) : dense_map{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_map{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_map(const dense_map &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_map(const dense_map &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_map(dense_map &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_map(dense_map &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_map() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_map &operator=(const dense_map &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_map &operator=(dense_map &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_map &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if the key does not exist. * @param value A key-value pair eventually convertible to the value type. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value.first, value.second); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); } /** * @copydoc insert * @tparam Arg Type of the key-value pair to insert into the container. */ template requires stl::constructible_from stl::pair insert(Arg &&value) { return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); } /** * @brief Inserts elements into the container, if their keys do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Inserts an element into the container or assigns to the current * element if the key already exists. * @tparam Arg Type of the value to insert or assign. * @param key A key used both to look up and to insert if not found. * @param value A value to insert or assign. * @return A pair consisting of an iterator to the element and a bool * denoting whether the insertion took place. */ template stl::pair insert_or_assign(const key_type &key, Arg &&value) { return insert_or_overwrite(key, stl::forward(value)); } /*! @copydoc insert_or_assign */ template stl::pair insert_or_assign(key_type &&key, Arg &&value) { return insert_or_overwrite(stl::move(key), stl::forward(value)); } /** * @brief Constructs an element in-place, if the key does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace([[maybe_unused]] Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return insert_or_do_nothing(key_type{}); } else if constexpr(sizeof...(Args) == 1u) { return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); } else if constexpr(sizeof...(Args) == 2u) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); const auto index = key_to_bucket(node.element.first); if(auto it = constrained_find(node.element.first, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.next, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Inserts in-place if the key does not exist, does nothing if the * key exists. * @tparam Args Types of arguments to forward to the constructor of the * element. * @param key A key used both to look up and to insert if not found. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair try_emplace(const key_type &key, Args &&...args) { return insert_or_do_nothing(key, stl::forward(args)...); } /*! @copydoc try_emplace */ template stl::pair try_emplace(key_type &&key, Args &&...args) { return insert_or_do_nothing(stl::move(key), stl::forward(args)...); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(pos->first); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].element.first); } return (begin() + dist); } /** * @brief Removes the element associated with a given key. * @param key A key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const key_type &key) { for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { if(packed.second()(packed.first()[*curr].element.first, key)) { const auto index = *curr; *curr = packed.first()[*curr].next; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &at(const key_type &key) { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] const mapped_type &at(const key_type &key) const { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type const &at(const auto &key) const requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] mapped_type &at(const auto &key) requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](const key_type &key) { return insert_or_do_nothing(key).first->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](key_type &&key) { return insert_or_do_nothing(stl::move(key)).first->second; } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const key_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const key_type &key) { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const key_type &key) const { return constrained_find(key, key_to_bucket(key)); } /** * @brief Finds an element with a key that compares _equivalent_ to a given * key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &key) requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &key) const requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /** * @brief Returns a range containing all elements with a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const key_type &key) { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const key_type &key) const { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &key) requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &key) const requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given key. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const key_type &key) const { return (find(key) != cend()); } /** * @brief Checks if the container contains an element with a key that * compares _equivalent_ to a given value. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &key) const requires is_transparent_v && is_transparent_v { return (find(key) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given key. * @param key The value of the key to examine. * @return The bucket for the given key. */ [[nodiscard]] size_type bucket(const key_type &key) const { return key_to_bucket(key); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = key_to_bucket(packed.first()[pos].element.first); packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the keys. * @return The function used to hash the keys. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare keys for equality. * @return The function used to compare keys for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::true_type {}; } // namespace std /*! @endcond */ #endif // #include "../core/fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "fwd.hpp" #ifndef ENTT_META_FWD_HPP #define ENTT_META_FWD_HPP // #include "../stl/cstddef.hpp" // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { struct meta_ctx; class meta_sequence_container; class meta_associative_container; class meta_any; class meta_handle; struct meta_custom; struct meta_data; struct meta_func; struct meta_base; class meta_type; template class meta_factory; /*! @brief Used to identicate that a sequence container has not a fixed size. */ inline constexpr stl::size_t meta_dynamic_extent = (stl::numeric_limits::max)(); /*! @brief Disambiguation tag for constructors and the like. */ struct meta_ctx_arg_t final {}; /*! @brief Constant of type meta_context_arg_t used to disambiguate calls. */ inline constexpr meta_ctx_arg_t meta_ctx_arg{}; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct meta_type_node; struct meta_context { using bucket_type = dense_map, stl::identity>; bucket_type bucket; [[nodiscard]] inline static meta_context &from(meta_ctx &); [[nodiscard]] inline static const meta_context &from(const meta_ctx &); }; } // namespace internal /*! @endcond */ /*! @brief Opaque meta context type. */ struct meta_ctx: private internal::meta_context { // attorney idiom like model to access the base class friend struct internal::meta_context; }; /*! @cond ENTT_INTERNAL */ [[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) { return ctx; } [[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) { return ctx; } /*! @endcond */ } // namespace entt #endif // #include "fwd.hpp" // #include "meta.hpp" #ifndef ENTT_META_META_HPP #define ENTT_META_META_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/any.hpp" #ifndef ENTT_CORE_ANY_HPP #define ENTT_CORE_ANY_HPP // #include "../config/config.h" // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" #ifndef ENTT_STL_STRING_VIEW_HPP #define ENTT_STL_STRING_VIEW_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string_view; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct fnv_1a_params; template<> struct fnv_1a_params { static constexpr auto offset = 2166136261; static constexpr auto prime = 16777619; }; template<> struct fnv_1a_params { static constexpr auto offset = 14695981039346656037ull; static constexpr auto prime = 1099511628211ull; }; template struct basic_hashed_string { using value_type = Char; using size_type = stl::size_t; using hash_type = id_type; const value_type *repr{}; hash_type hash{fnv_1a_params<>::offset}; size_type length{}; }; } // namespace internal /*! @endcond */ /** * @brief Zero overhead unique identifier. * * A hashed string is a compile-time tool that allows users to use * human-readable identifiers 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. * * @warning * This class doesn't take ownership of user-supplied strings nor does it make a * copy of them. * * @tparam Char Character type. */ template class basic_hashed_string: internal::basic_hashed_string { using base_type = internal::basic_hashed_string; using params = internal::fnv_1a_params<>; struct const_wrapper { // non-explicit constructor on purpose constexpr const_wrapper(const base_type::value_type *str) noexcept : repr{str} {} const base_type::value_type *repr; }; public: /*! @brief Character type. */ using value_type = base_type::value_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Unsigned integer type. */ using hash_type = base_type::hash_type; /** * @brief Returns directly the numeric representation of a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. * @return The numeric representation of the string. */ [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { return basic_hashed_string{str, len}; } /** * @brief Returns directly the numeric representation of a string. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. * @return The numeric representation of the string. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { return basic_hashed_string{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 constexpr hash_type value(const_wrapper wrapper) noexcept { return basic_hashed_string{wrapper}; } /*! @brief Constructs an empty hashed string. */ constexpr basic_hashed_string() noexcept : basic_hashed_string{nullptr, 0u} {} /** * @brief Constructs a hashed string from a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. */ constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; base_type::length < len; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Constructs a hashed string from an array of const characters. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { for(; str[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } } /** * @brief Explicit constructor on purpose to avoid constructing a hashed * string directly from a `const value_type *`. * * @warning * The lifetime of the string is not extended nor is it copied. * * @param wrapper Helps achieving the purpose by relying on overloading. */ explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept : base_type{wrapper.repr} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; wrapper.repr[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Returns the size of a hashed string. * @return The size of the hashed string. */ [[nodiscard]] constexpr size_type size() const noexcept { return base_type::length; } /** * @brief Returns the human-readable representation of a hashed string. * @return The string used to initialize the hashed string. */ [[nodiscard]] constexpr const value_type *data() const noexcept { return base_type::repr; } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr hash_type value() const noexcept { return base_type::hash; } /*! @copydoc data */ [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { return data(); } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr operator hash_type() const noexcept { return value(); } /** * @brief Compares two hashed strings. * @param other A valid hashed string. * @return True if the two hashed strings are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { return value() == other.value(); } /** * @brief Lexicographically compares two hashed strings. * @param other A valid hashed string. * @return The relative order between the two hashed strings. */ [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { return value() <=> other.value(); } }; /** * @brief Deduction guide. * @tparam Char Character type. * @param str Human-readable identifier. * @param len Length of the string to hash. */ template basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; /** * @brief Deduction guide. * @tparam Char Character type. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) basic_hashed_string(const Char (&str)[N]) -> 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]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { return hashed_string{str}; } /** * @brief User defined literal for hashed wstrings. * @param str The literal without its suffix. * @return A properly initialized hashed wstring. */ [[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { return hashed_wstring{str}; } } // namespace literals } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @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) 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) 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. */ constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) : func{stl::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 constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } private: Func func; }; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { enum class any_request : stl::uint8_t { info, transfer, assign, compare, copy, move }; template struct basic_any_storage { static constexpr bool has_buffer = true; union { const void *instance{}; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) alignas(Align) stl::byte buffer[Len]; }; }; template struct basic_any_storage<0u, Align> { static constexpr bool has_buffer = false; const void *instance{}; }; template // NOLINTNEXTLINE(bugprone-sizeof-expression) struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v> {}; template struct in_situ: stl::false_type {}; } // namespace internal /*! @endcond */ /** * @brief A SBO friendly, type-safe container for single values of any type. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Optional alignment requirement. */ template class basic_any: private internal::basic_any_storage { using request = internal::any_request; using base_type = internal::basic_any_storage; using vtable_type = const void *(const request, const basic_any &, const void *); using deleter_type = void(const basic_any &); template static constexpr bool in_situ_v = internal::in_situ::value; template static const void *basic_vtable(const request req, const basic_any &value, const void *other) { switch(const auto *elem = static_cast(value.data()); req) { using enum internal::any_request; case info: return &type_id(); case transfer: if constexpr(stl::is_move_assignable_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) *const_cast(elem) = stl::move(*static_cast(const_cast(other))); return other; } [[fallthrough]]; case assign: if constexpr(stl::is_copy_assignable_v) { *const_cast(elem) = *static_cast(other); return other; } break; case compare: if constexpr(!stl::is_function_v && !stl::is_array_v && is_equality_comparable_v) { return (*elem == *static_cast(other)) ? other : nullptr; } else { return (elem == other) ? other : nullptr; } case copy: if constexpr(stl::is_copy_constructible_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) static_cast(const_cast(other))->initialize(*elem); } break; case move: ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy"); if constexpr(in_situ_v) { // NOLINTNEXTLINE(bugprone-casting-through-void, bugprone-multi-level-implicit-pointer-conversion) return ::new(&static_cast(const_cast(other))->buffer) Type{stl::move(*const_cast(elem))}; } } return nullptr; } template static void basic_deleter(const basic_any &value) { ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::is_trivially_destructible_v), "Unexpected policy"); const auto *elem = static_cast(value.data()); if constexpr(in_situ_v) { (value.mode == any_policy::embedded) ? elem->~Type() : (delete elem); } else if constexpr(stl::is_array_v) { delete[] elem; } else { delete elem; } } template void initialize([[maybe_unused]] Args &&...args) { using plain_type = stl::remove_cvref_t; vtable = basic_vtable; underlying_type = type_hash::value(); if constexpr(stl::is_void_v) { deleter = nullptr; mode = any_policy::empty; this->instance = nullptr; } else if constexpr(stl::is_lvalue_reference_v) { deleter = nullptr; mode = stl::is_const_v> ? any_policy::cref : any_policy::ref; static_assert((stl::is_lvalue_reference_v && ...) && (sizeof...(Args) == 1u), "Invalid arguments"); // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) this->instance = (stl::addressof(args), ...); } else if constexpr(in_situ_v) { if constexpr(stl::is_trivially_destructible_v) { deleter = nullptr; } else { deleter = &basic_deleter; } mode = any_policy::embedded; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { ::new(&this->buffer) plain_type{stl::forward(args)...}; } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) ::new(&this->buffer) plain_type(stl::forward(args)...); } } else { deleter = &basic_deleter; mode = any_policy::dynamic; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { this->instance = new plain_type{stl::forward(args)...}; } else if constexpr(stl::is_array_v) { static_assert(sizeof...(Args) == 0u, "Invalid arguments"); this->instance = new plain_type[stl::extent_v](); } else { this->instance = new plain_type(stl::forward(args)...); } } } void invoke_deleter_if_exists() { if(deleter != nullptr) { deleter(*this); } } public: /*! @brief Size of the internal buffer. */ static constexpr auto length = Len; /*! @brief Alignment requirement. */ static constexpr auto alignment = Align; /*! @brief Default constructor. */ constexpr basic_any() noexcept : basic_any{stl::in_place_type} {} /** * @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(stl::in_place_type_t, Args &&...args) : base_type{} { initialize(stl::forward(args)...); } /** * @brief Constructs a wrapper taking ownership of the passed object. * @tparam Type Type of object to use to initialize the wrapper. * @param value A pointer to an object to take ownership of. */ template requires (!stl::is_const_v && !stl::is_void_v) explicit basic_any(stl::in_place_t, Type *value) : base_type{} { if(value == nullptr) { initialize(); } else { initialize(*value); deleter = &basic_deleter; mode = any_policy::dynamic; } } /** * @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 requires (!stl::same_as, basic_any>) basic_any(Type &&value) : basic_any{stl::in_place_type>, stl::forward(value)} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ basic_any(const basic_any &other) : basic_any{} { other.vtable(request::copy, other, this); } /** * @brief Move constructor. * @param other The instance to move from. */ basic_any(basic_any &&other) noexcept : base_type{}, vtable{other.vtable}, deleter{other.deleter}, underlying_type{other.underlying_type}, mode{other.mode} { if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } } /*! @brief Frees the internal buffer, whatever it means. */ ~basic_any() { invoke_deleter_if_exists(); } /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This any object. */ basic_any &operator=(const basic_any &other) { if(this != &other) { invoke_deleter_if_exists(); if(other) { other.vtable(request::copy, other, this); } else { initialize(); } } return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This any object. */ basic_any &operator=(basic_any &&other) noexcept { if(this != &other) { invoke_deleter_if_exists(); if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } vtable = other.vtable; deleter = other.deleter; underlying_type = other.underlying_type; 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 requires (!stl::same_as, basic_any>) basic_any &operator=(Type &&value) { emplace>(stl::forward(value)); return *this; } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] bool has_value() const noexcept { return (mode != any_policy::empty); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @param req Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ [[nodiscard]] bool has_value(const type_info &req) const noexcept { return (underlying_type == req.hash()); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @tparam Type Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ template [[nodiscard]] bool has_value() const noexcept { return (underlying_type == type_hash::value()); } /** * @brief Returns the object type info if any, `type_id()` otherwise. * @return The object type info if any, `type_id()` otherwise. */ [[nodiscard]] const type_info &info() const noexcept { return *static_cast(vtable(request::info, *this, nullptr)); } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data() const noexcept { if constexpr(base_type::has_buffer) { return (mode == any_policy::embedded) ? &this->buffer : this->instance; } else { return this->instance; } } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data(const type_info &req) const noexcept { return has_value(req) ? data() : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] const Type *data() const noexcept { return has_value>() ? static_cast(data()) : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data() noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data()); } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data(const type_info &req) noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data(req)); } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] Type *data() noexcept { if constexpr(stl::is_const_v) { return stl::as_const(*this).template data>(); } else { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).template data>()); } } /** * @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) { invoke_deleter_if_exists(); initialize(stl::forward(args)...); } /** * @brief Assigns a value to the contained object without replacing it. * @param other The value to assign to the contained object. * @return True in case of success, false otherwise. */ bool assign(const basic_any &other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (vtable(request::assign, *this, other.data()) != nullptr); } return false; } /*! @copydoc assign */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) bool assign(basic_any &&other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (other.mode == any_policy::cref) ? (vtable(request::assign, *this, stl::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr); } return false; } /*! @brief Destroys contained object */ void reset() { invoke_deleter_if_exists(); initialize(); } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return has_value(); } /** * @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 basic_any &other) const noexcept { if(other && (underlying_type == other.underlying_type)) { return (vtable(request::compare, *this, other.data()) != nullptr); } return (!*this && !other); } /** * @brief Aliasing constructor. * @return A wrapper that shares a reference to an unmanaged object. */ [[nodiscard]] basic_any as_ref() noexcept { basic_any other = stl::as_const(*this).as_ref(); switch(mode) { using enum any_policy; case cref: case empty: other.mode = mode; break; default: other.mode = any_policy::ref; break; } return other; } /*! @copydoc as_ref */ [[nodiscard]] basic_any as_ref() const noexcept { basic_any other{}; other.instance = data(); other.vtable = vtable; other.underlying_type = underlying_type; other.mode = any_policy::cref; return other; } /** * @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 noexcept { return (mode == any_policy::dynamic || mode == any_policy::embedded); } /** * @brief Returns the current mode of an any object. * @return The current mode of the any object. */ [[nodiscard]] any_policy policy() const noexcept { return mode; } private: vtable_type *vtable{}; deleter_type *deleter{}; id_type underlying_type{}; any_policy mode{}; }; /** * @brief Performs type-safe access to the contained object. * @tparam Type Type to which conversion is required. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Alignment requirement. * @param data Target any object. * @return The element converted to the requested type. */ template [[nodiscard]] stl::remove_const_t any_cast(const basic_any &data) noexcept { const auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(*instance); } /*! @copydoc any_cast */ template [[nodiscard]] stl::remove_const_t any_cast(basic_any &data) 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 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) [[nodiscard]] stl::remove_const_t any_cast(basic_any &&data) noexcept { if constexpr(stl::is_copy_constructible_v>) { if(auto *const instance = any_cast>(&data); instance) { return static_cast(stl::move(*instance)); } return any_cast(data); } else { auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(stl::move(*instance)); } } /*! @copydoc any_cast */ template [[nodiscard]] const Type *any_cast(const basic_any *data) noexcept { return data->template data>(); } /*! @copydoc any_cast */ template [[nodiscard]] Type *any_cast(basic_any *data) noexcept { if constexpr(stl::is_const_v) { // last attempt to make wrappers for const references return their values return any_cast(&stl::as_const(*data)); } else { return data->template data(); } } /** * @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 buffer 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, stl::size_t Align = basic_any::alignment, typename... Args> [[nodiscard]] basic_any make_any(Args &&...args) { return basic_any{stl::in_place_type, stl::forward(args)...}; } /** * @brief Forwards its argument and avoids copies for lvalue references. * @tparam Len Size of the buffer 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, stl::size_t Align = basic_any::alignment, typename Type> [[nodiscard]] basic_any forward_as_any(Type &&value) { return basic_any{stl::in_place_type, stl::forward(value)}; } } // namespace entt #endif // #include "../core/concepts.hpp" // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "../core/type_traits.hpp" // #include "../core/utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @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) 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) 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. */ constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) : func{stl::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 constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } private: Func func; }; } // namespace entt #endif // #include "../locator/locator.hpp" #ifndef ENTT_LOCATOR_LOCATOR_HPP #define ENTT_LOCATOR_LOCATOR_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Service locator, nothing more. * * A service locator is used to do what it promises: locate services.
* Usually service locators are tightly bound to the services they expose and * thus it's hard to define a general purpose class to do that. This tiny class * tries to fill the gap and to get rid of the burden of defining a different * specific locator for each application. * * @note * Users shouldn't retain references to a service. The recommended way is to * retrieve the service implementation currently set each and every time the * need for it arises. The risk is to incur in unexpected behaviors otherwise. * * @tparam Service Service type. */ template class locator final { class service_handle { friend class locator; stl::shared_ptr value{}; }; public: /*! @brief Service type. */ using type = Service; /*! @brief Service node type. */ using node_type = service_handle; /*! @brief Default constructor, deleted on purpose. */ locator() = delete; /*! @brief Default copy constructor, deleted on purpose. */ locator(const locator &) = delete; /*! @brief Default destructor, deleted on purpose. */ ~locator() = delete; /** * @brief Default copy assignment operator, deleted on purpose. * @return This locator. */ locator &operator=(const locator &) = delete; /** * @brief Checks whether a service locator contains a value. * @return True if the service locator contains a value, false otherwise. */ [[nodiscard]] static bool has_value() noexcept { return (service != nullptr); } /** * @brief Returns a reference to a valid service, if any. * * @warning * Invoking this function can result in undefined behavior if the service * hasn't been set yet. * * @return A reference to the service currently set, if any. */ [[nodiscard]] static Service &value() noexcept { ENTT_ASSERT(has_value(), "Service not available"); return *service; } /** * @brief Returns a service if available or sets it from a fallback type. * * Arguments are used only if a service doesn't already exist. In all other * cases, they are discarded. * * @tparam Args Types of arguments to use to construct the fallback service. * @tparam Type Fallback service type. * @param args Parameters to use to construct the fallback service. * @return A reference to a valid service. */ template Type = Service, typename... Args> requires stl::constructible_from [[nodiscard]] static Service &value_or(Args &&...args) { return service ? *service : emplace(stl::forward(args)...); } /** * @brief Sets or replaces a service. * @tparam Type Service type. * @tparam Args Types of arguments to use to construct the service. * @param args Parameters to use to construct the service. * @return A reference to a valid service. */ template Type = Service, typename... Args> requires stl::constructible_from static Service &emplace(Args &&...args) { service = stl::make_shared(stl::forward(args)...); return *service; } /** * @brief Sets or replaces a service using a given allocator. * @tparam Type Service type. * @tparam Args Types of arguments to use to construct the service. * @param alloc The allocator to use. * @param args Parameters to use to construct the service. * @return A reference to a valid service. */ template Type = Service, typename... Args> requires stl::constructible_from static Service &emplace(stl::allocator_arg_t, auto alloc, Args &&...args) { service = stl::allocate_shared(alloc, stl::forward(args)...); return *service; } /** * @brief Returns a handle to the underlying service. * @return A handle to the underlying service. */ static node_type handle() noexcept { node_type node{}; node.value = service; return node; } /** * @brief Resets or replaces a service. * @param other Optional handle with which to replace the service. */ static void reset(const node_type &other = {}) noexcept { service = other.value; } /** * @brief Resets or replaces a service. * @tparam Type Service type. * @tparam Deleter Deleter type. * @param elem A pointer to a service to manage. * @param deleter A deleter to use to destroy the service. */ template Type, typename Deleter = stl::default_delete> static void reset(Type *elem, Deleter deleter = {}) { service = stl::shared_ptr{elem, stl::move(deleter)}; } private: // stl::shared_ptr because of its type erased allocator which is useful here // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) inline static stl::shared_ptr service{}; }; } // namespace entt #endif // #include "../stl/array.hpp" #ifndef ENTT_STL_ARRAY_HPP #define ENTT_STL_ARRAY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::array; using std::get; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/string_view.hpp" #ifndef ENTT_STL_STRING_VIEW_HPP #define ENTT_STL_STRING_VIEW_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string_view; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.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); } }; } // namespace entt #endif // #include "context.hpp" // #include "fwd.hpp" // #include "node.hpp" #ifndef ENTT_META_NODE_HPP #define ENTT_META_NODE_HPP // #include "../config/config.h" // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/concepts.hpp" // #include "../core/enum.hpp" #ifndef ENTT_CORE_ENUM_HPP #define ENTT_CORE_ENUM_HPP // #include "../stl/concepts.hpp" // #include "../stl/type_traits.hpp" namespace entt { /** * @brief Enable bitmask support for enum classes. * @tparam Type The enum type for which to enable bitmask support. */ template struct enum_as_bitmask: stl::false_type {}; /*! @copydoc enum_as_bitmask */ template requires requires { requires stl::is_enum_v; { Type::_entt_enum_as_bitmask } -> stl::same_as; } struct enum_as_bitmask: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The enum class type for which to enable bitmask support. */ template inline constexpr bool enum_as_bitmask_v = enum_as_bitmask::value; /** * @brief Specifies that an enum class supports bitmask operations. * @tparam Type Enum class type. */ template // check again that it is an enum to deal with incorrect specializations concept enum_bitmask = stl::is_enum_v && enum_as_bitmask_v; } // namespace entt /** * @brief Operator available for enums for which bitmask support is enabled. * @tparam Type Enum class type. * @param lhs The first value to use. * @param rhs The second value to use. * @return The result of invoking the operator on the underlying types of the * two values provided. */ template [[nodiscard]] constexpr Type operator|(const Type lhs, const Type rhs) noexcept { return static_cast(static_cast>(lhs) | static_cast>(rhs)); } /*! @copydoc operator| */ template [[nodiscard]] constexpr Type operator&(const Type lhs, const Type rhs) noexcept { return static_cast(static_cast>(lhs) & static_cast>(rhs)); } /*! @copydoc operator| */ template [[nodiscard]] constexpr Type operator^(const Type lhs, const Type rhs) noexcept { return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); } /** * @brief Operator available for enums for which bitmask support is enabled. * @tparam Type Enum class type. * @param value The value to use. * @return The result of invoking the operator on the underlying types of the * value provided. */ template [[nodiscard]] constexpr Type operator~(const Type value) noexcept { return static_cast(~static_cast>(value)); } /*! @copydoc operator~ */ template [[nodiscard]] constexpr bool operator!(const Type value) noexcept { return !static_cast>(value); } /*! @copydoc operator| */ template constexpr Type &operator|=(Type &lhs, const Type rhs) noexcept { return (lhs = (lhs | rhs)); } /*! @copydoc operator| */ template constexpr Type &operator&=(Type &lhs, const Type rhs) noexcept { return (lhs = (lhs & rhs)); } /*! @copydoc operator| */ template constexpr Type &operator^=(Type &lhs, const Type rhs) noexcept { return (lhs = (lhs ^ rhs)); } #endif // #include "../core/fwd.hpp" // #include "../core/type_info.hpp" // #include "../core/type_traits.hpp" // #include "../core/utility.hpp" // #include "../stl/array.hpp" // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "context.hpp" // #include "fwd.hpp" // #include "type_traits.hpp" #ifndef ENTT_META_TYPE_TRAITS_HPP #define ENTT_META_TYPE_TRAITS_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" 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` equal to true if a given type is * a pointer-like type, false otherwise. */ template struct is_meta_pointer_like: stl::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; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { enum class meta_traits : stl::uint32_t { is_none = 0x0000, is_const = 0x0001, is_static = 0x0002, is_arithmetic = 0x0004, is_integral = 0x0008, is_signed = 0x0010, is_array = 0x0020, is_enum = 0x0040, is_class = 0x0080, is_pointer = 0x0100, is_pointer_like = 0x0200, is_sequence_container = 0x0400, is_associative_container = 0x0800, _user_defined_traits = 0xFFFF, _entt_enum_as_bitmask = 0xFFFF }; template requires stl::is_enum_v [[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept { constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); return Type{static_cast>(static_cast>(traits) >> shift)}; } template requires stl::is_enum_v [[nodiscard]] auto user_to_meta_traits(const Type value) noexcept { constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); const auto traits = static_cast>(static_cast>(value)); ENTT_ASSERT(traits < ((~static_cast>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits"); return meta_traits{traits << shift}; } struct meta_type_node; struct meta_custom_node { id_type id{}; stl::shared_ptr value{}; }; struct meta_base_node { id_type id{}; const meta_type_node &(*type)(const meta_context &) noexcept {}; const void *(*cast)(const void *) noexcept {}; }; struct meta_conv_node { id_type id{}; meta_any (*conv)(const meta_ctx &, const void *){}; }; struct meta_ctor_node { using size_type = stl::size_t; id_type id{}; size_type arity{0u}; meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; meta_any (*invoke)(const meta_ctx &, meta_any *const){}; }; struct meta_data_node { using size_type = stl::size_t; id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type set_arity{0u}; size_type get_arity{0u}; meta_type (*set_arg)(const meta_ctx &, const size_type) noexcept {}; meta_type (*get_arg)(const meta_ctx &, const size_type) noexcept {}; const meta_type_node &(*type)(const meta_context &) noexcept {}; bool (*set)(meta_handle, meta_any *const){}; meta_any (*get)(meta_handle, meta_any *const){}; meta_custom_node custom{}; }; struct meta_func_node { using size_type = stl::size_t; id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type arity{0u}; const meta_type_node &(*ret)(const meta_context &) noexcept {}; meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; meta_any (*invoke)(meta_handle, meta_any *const){}; stl::unique_ptr next; meta_custom_node custom{}; }; struct meta_template_node { using size_type = stl::size_t; size_type arity{0u}; const meta_type_node &(*resolve)(const meta_context &) noexcept {}; const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {}; }; struct meta_type_descriptor { stl::vector ctor{}; stl::vector base{}; stl::vector conv{}; stl::vector data{}; stl::vector func{}; }; struct meta_type_node { using size_type = stl::size_t; const type_info *info{}; id_type alias{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type size_of{0u}; const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {}; meta_any (*default_constructor)(const meta_ctx &){}; double (*conversion_helper)(void *, const void *){}; meta_any (*from_void)(const meta_ctx &, void *, const void *){}; meta_template_node templ{}; meta_custom_node custom{}; stl::unique_ptr details{}; }; template [[nodiscard]] auto *find_member(Type &from, const Value value) { for(auto &&elem: from) { if(elem.id == value) { return &elem; } } return static_cast(nullptr); } [[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t *const ref) { while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); } return curr; } template [[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) { using value_type = stl::remove_reference_t*Member))>::value_type; if(node.details) { if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) { return member; } if(recursive) { for(auto &&curr: node.details->base) { if(auto *elem = look_for(context, curr.type(context), id, recursive); elem) { return elem; } } } } return static_cast(nullptr); } template const meta_type_node &resolve(const meta_context &) noexcept; template [[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list, const stl::size_t index) noexcept { using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept; constexpr stl::array list{&resolve>...}; ENTT_ASSERT(index < sizeof...(Args), "Out of bounds"); return list[index](context); } [[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept { if(from.details) { for(auto &&curr: from.details->base) { if(const void *other = curr.cast(instance); curr.id == to) { return other; } else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) { return elem; } } } return nullptr; } template auto setup_node_for() noexcept { meta_type_node node{ &type_id(), type_id().hash(), nullptr, (stl::is_arithmetic_v ? meta_traits::is_arithmetic : meta_traits::is_none) | (stl::is_integral_v ? meta_traits::is_integral : meta_traits::is_none) | (stl::is_signed_v ? meta_traits::is_signed : meta_traits::is_none) | (stl::is_array_v ? meta_traits::is_array : meta_traits::is_none) | (stl::is_enum_v ? meta_traits::is_enum : meta_traits::is_none) | (stl::is_class_v ? meta_traits::is_class : meta_traits::is_none) | (stl::is_pointer_v ? meta_traits::is_pointer : meta_traits::is_none) | (is_meta_pointer_like_v ? meta_traits::is_pointer_like : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_sequence_container : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_associative_container : meta_traits::is_none), size_of_v, &resolve>>}; if constexpr(stl::is_default_constructible_v) { node.default_constructor = +[](const meta_ctx &ctx) { return meta_any{ctx, stl::in_place_type}; }; } if constexpr(stl::is_arithmetic_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { return lhs ? static_cast(*static_cast(lhs) = static_cast(*static_cast(rhs))) : static_cast(*static_cast(rhs)); }; } else if constexpr(stl::is_enum_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { return lhs ? static_cast(*static_cast(lhs) = static_cast(static_cast>(*static_cast(rhs)))) : static_cast(*static_cast(rhs)); }; } if constexpr(!stl::is_void_v && !stl::is_function_v) { node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) { if(elem && celem) { // ownership construction request return meta_any{ctx, stl::in_place, static_cast *>(elem)}; } if(elem) { // non-const reference construction request return meta_any{ctx, stl::in_place_type &>, *static_cast *>(elem)}; } // const reference construction request return meta_any{ctx, stl::in_place_type &>, *static_cast *>(celem)}; }; } if constexpr(is_complete_v>) { node.templ = meta_template_node{ meta_template_traits::args_type::size, &resolve::class_type>, +[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits::args_type{}, index); }}; } return node; } template [[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept { static const meta_type_node node = setup_node_for(); const auto it = context.bucket.find(node.info->hash()); return (it == context.bucket.cend()) ? node : *it->second; } } // namespace internal /*! @endcond */ } // namespace entt #endif // #include "range.hpp" #ifndef ENTT_META_RANGE_HPP #define ENTT_META_RANGE_HPP #include // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/utility.hpp" // #include "context.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct meta_base_node; template struct meta_range_iterator final { using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr meta_range_iterator() noexcept : it{}, ctx{} {} constexpr meta_range_iterator(const meta_ctx &area, const It iter) noexcept : it{iter}, ctx{&area} {} constexpr meta_range_iterator &operator++() noexcept { return ++it, *this; } constexpr meta_range_iterator operator++(int) noexcept { const meta_range_iterator orig = *this; return ++(*this), orig; } constexpr meta_range_iterator &operator--() noexcept { return --it, *this; } constexpr meta_range_iterator operator--(int) noexcept { const meta_range_iterator orig = *this; return operator--(), orig; } constexpr meta_range_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr meta_range_iterator operator+(const difference_type value) const noexcept { meta_range_iterator copy = *this; return (copy += value); } constexpr meta_range_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr meta_range_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { if constexpr(stl::is_same_v) { return {it[value].first, Type{*ctx, *it[value].second}}; } else { return {it[value].id, Type{*ctx, it[value]}}; } } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } [[nodiscard]] constexpr stl::ptrdiff_t operator-(const meta_range_iterator &other) const noexcept { return it - other.it; } [[nodiscard]] constexpr bool operator==(const meta_range_iterator &other) const noexcept { return it == other.it; } [[nodiscard]] constexpr auto operator<=>(const meta_range_iterator &other) const noexcept { return it <=> other.it; } private: It it; const meta_ctx *ctx; }; } // namespace internal /*! @endcond */ /** * @brief Iterable range to use to iterate all types of meta objects. * @tparam Type Type of meta objects returned. * @tparam It Type of forward iterator. */ template using meta_range = iterable_adaptor>; } // namespace entt #endif // #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct basic_meta_object { [[nodiscard]] auto &node_or_assert() const noexcept { ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); return *node; } const Type *node{}; const meta_ctx *ctx{&locator::value_or()}; }; } // namespace internal /*! @endcond */ /*! @brief Proxy object for sequence containers. */ class meta_sequence_container { class meta_iterator; public: /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Meta iterator type. */ using iterator = meta_iterator; /*! @brief Default constructor. */ meta_sequence_container() = default; /** * @brief Context aware constructor. * @tparam Type Type of container to wrap. * @param area The context from which to search for meta types. * @param instance The container to wrap. */ template meta_sequence_container(const meta_ctx &area, Type &instance) noexcept : ctx{&area}, data{&instance}, value_type_node{&internal::resolve}, const_reference_node{&internal::resolve>}, size_fn{meta_sequence_container_traits>::size}, clear_fn{meta_sequence_container_traits>::clear}, reserve_fn{meta_sequence_container_traits>::reserve}, resize_fn{meta_sequence_container_traits>::resize}, begin_end_fn{meta_sequence_container_traits>::iter}, insert_fn{meta_sequence_container_traits>::insert}, erase_fn{meta_sequence_container_traits>::erase}, const_only{stl::is_const_v} {} [[nodiscard]] inline meta_type value_type() const noexcept; [[nodiscard]] inline size_type size() const noexcept; inline bool resize(size_type); inline bool clear(); inline bool reserve(size_type); [[nodiscard]] inline iterator begin(); [[nodiscard]] inline iterator end(); inline iterator insert(const iterator &, meta_any); inline iterator erase(const iterator &); [[nodiscard]] inline meta_any operator[](size_type); [[nodiscard]] inline explicit operator bool() const noexcept; private: const meta_ctx *ctx{}; const void *data{}; const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; const internal::meta_type_node &(*const_reference_node)(const internal::meta_context &){}; size_type (*size_fn)(const void *){}; bool (*clear_fn)(void *){}; bool (*reserve_fn)(void *, const size_type){}; bool (*resize_fn)(void *, const size_type){}; iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){}; iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){}; bool const_only{}; }; /*! @brief Proxy object for associative containers. */ class meta_associative_container { class meta_iterator; public: /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Meta iterator type. */ using iterator = meta_iterator; /*! @brief Default constructor. */ meta_associative_container() = default; /** * @brief Context aware constructor. * @tparam Type Type of container to wrap. * @param area The context from which to search for meta types. * @param instance The container to wrap. */ template meta_associative_container(const meta_ctx &area, Type &instance) noexcept : ctx{&area}, data{&instance}, key_type_node{&internal::resolve}, value_type_node{&internal::resolve}, size_fn{&meta_associative_container_traits>::size}, clear_fn{&meta_associative_container_traits>::clear}, reserve_fn{&meta_associative_container_traits>::reserve}, begin_end_fn{&meta_associative_container_traits>::iter}, insert_fn{&meta_associative_container_traits>::insert}, erase_fn{&meta_associative_container_traits>::erase}, find_fn{&meta_associative_container_traits>::find}, const_only{stl::is_const_v} { if constexpr(!meta_associative_container_traits>::key_only) { mapped_type_node = &internal::resolve; } } [[nodiscard]] inline meta_type key_type() const noexcept; [[nodiscard]] inline meta_type mapped_type() const noexcept; [[nodiscard]] inline meta_type value_type() const noexcept; [[nodiscard]] inline size_type size() const noexcept; inline bool clear(); inline bool reserve(size_type); [[nodiscard]] inline iterator begin(); [[nodiscard]] inline iterator end(); inline bool insert(meta_any, meta_any); inline size_type erase(meta_any); [[nodiscard]] inline iterator find(meta_any); [[nodiscard]] inline explicit operator bool() const noexcept; private: const meta_ctx *ctx{}; const void *data{}; const internal::meta_type_node &(*key_type_node)(const internal::meta_context &){}; const internal::meta_type_node &(*mapped_type_node)(const internal::meta_context &){}; const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; size_type (*size_fn)(const void *){}; bool (*clear_fn)(void *){}; bool (*reserve_fn)(void *, const size_type){}; iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; bool (*insert_fn)(void *, const void *, const void *){}; size_type (*erase_fn)(void *, const void *){}; iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){}; bool const_only{}; }; /*! @brief Opaque wrapper for values of any type. */ class meta_any { using vtable_type = void(const internal::meta_traits, const meta_any &, void *); template static void basic_vtable(const internal::meta_traits req, const meta_any &value, [[maybe_unused]] void *other) { if(req == internal::meta_traits::is_none) { value.node = &internal::resolve(internal::meta_context::from(*value.ctx)); } if constexpr(is_meta_pointer_like_v) { if(req == internal::meta_traits::is_pointer) { if constexpr(!stl::is_void_v::element_type>>) { if constexpr(stl::is_constructible_v) { if(const auto &pointer_like = any_cast(value.storage); pointer_like) { static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(pointer_like)); } } else { static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(any_cast(value.storage))); } } } } else if constexpr(requires(Type elem) { *elem; }) { if(req == internal::meta_traits::is_pointer) { if constexpr(stl::is_class_v) { if(const auto &elem = any_cast(value.storage); elem) { return (value.storage.policy() == any_policy::cref) ? static_cast(other)->emplace(*elem) : static_cast(other)->emplace(elem))>(*const_cast(elem)); } } else if constexpr(!stl::is_array_v && !stl::is_void_v>>) { if(auto *pointer = any_cast(value.storage); pointer) { static_cast(other)->emplace>>, Type, stl::remove_pointer_t &>>(*pointer); } } } } else if constexpr(is_complete_v> || is_complete_v>) { if(constexpr auto flag = (is_complete_v> ? internal::meta_traits::is_sequence_container : internal::meta_traits::is_associative_container); req == flag) { using container_type = stl::conditional_t>, meta_sequence_container, meta_associative_container>; *static_cast(other) = (value.storage.policy() == any_policy::cref) ? container_type{*value.ctx, any_cast(value.storage)} : container_type{*value.ctx, any_cast(const_cast(value).storage)}; } } } [[nodiscard]] const auto &fetch_node() const { if(node == nullptr) { ENTT_ASSERT(*this, "Invalid vtable function"); vtable(internal::meta_traits::is_none, *this, nullptr); } ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); return *node; } meta_any(const meta_any &other, any elem) : storage{stl::move(elem)}, ctx{other.ctx}, node{other.node}, vtable{other.vtable} {} public: /*! Default constructor. */ meta_any() = default; /** * @brief Context aware constructor. * @param area The context from which to search for meta types. */ meta_any(meta_ctx_arg_t, const meta_ctx &area) : ctx{&area} {} /** * @brief Constructs a wrapper by directly initializing the new object. * @tparam Type Type of object to use to initialize the wrapper. * @param args Parameters to use to construct the instance. */ template explicit meta_any(stl::in_place_type_t, auto &&...args) : meta_any{locator::value_or(), stl::in_place_type, stl::forward(args)...} {} /** * @brief Constructs a wrapper by directly initializing the new object. * @tparam Type Type of object to use to initialize the wrapper. * @param area The context from which to search for meta types. * @param args Parameters to use to construct the instance. */ template explicit meta_any(const meta_ctx &area, stl::in_place_type_t, auto &&...args) : storage{stl::in_place_type, stl::forward(args)...}, ctx{&area}, vtable{&basic_vtable>} {} /** * @brief Constructs a wrapper taking ownership of the passed object. * @param value A pointer to an object to take ownership of. */ explicit meta_any(stl::in_place_t, auto *value) : meta_any{locator::value_or(), stl::in_place, value} {} /** * @brief Constructs a wrapper taking ownership of the passed object. * @param area The context from which to search for meta types. * @param value A pointer to an object to take ownership of. */ explicit meta_any(const meta_ctx &area, stl::in_place_t, auto *value) : storage{stl::in_place, value}, ctx{&area}, vtable{storage ? &basic_vtable>> : nullptr} { } /** * @brief Constructs a wrapper from a given value. * @param value An instance of an object to use to initialize the wrapper. */ meta_any(auto &&value) requires (!stl::same_as, meta_any>) : meta_any{locator::value_or(), stl::forward(value)} {} /** * @brief Constructs a wrapper from a given value. * @param area The context from which to search for meta types. * @param value An instance of an object to use to initialize the wrapper. */ meta_any(const meta_ctx &area, auto &&value) requires (!stl::same_as, meta_any>) : meta_any{area, stl::in_place_type>, stl::forward(value)} {} /** * @brief Context aware copy constructor. * @param area The context from which to search for meta types. * @param other The instance to copy from. */ meta_any(const meta_ctx &area, const meta_any &other) : storage{other.storage}, ctx{&area}, node{(ctx == other.ctx) ? other.node : nullptr}, vtable{other.vtable} {} /** * @brief Context aware move constructor. * @param area The context from which to search for meta types. * @param other The instance to move from. */ meta_any(const meta_ctx &area, meta_any &&other) : storage{stl::move(other.storage)}, ctx{&area}, node{(ctx == other.ctx) ? stl::exchange(other.node, nullptr) : nullptr}, vtable{stl::exchange(other.vtable, nullptr)} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ meta_any(const meta_any &other) : storage{other.storage}, ctx{other.ctx}, node{(other.storage && !storage) ? nullptr : other.node}, vtable{(other.storage && !storage) ? nullptr : other.vtable} { } /** * @brief Move constructor. * @param other The instance to move from. */ meta_any(meta_any &&other) noexcept : storage{stl::move(other.storage)}, ctx{other.ctx}, node{stl::exchange(other.node, nullptr)}, vtable{stl::exchange(other.vtable, nullptr)} {} /*! @brief Default destructor. */ ~meta_any() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This meta any object. */ meta_any &operator=(const meta_any &other) { if(this != &other) { ctx = other.ctx; storage = other.storage; node = (other.storage && !storage) ? nullptr : other.node; vtable = (other.storage && !storage) ? nullptr : other.vtable; } return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This meta any object. */ meta_any &operator=(meta_any &&other) noexcept { storage = stl::move(other.storage); ctx = other.ctx; node = stl::exchange(other.node, nullptr); vtable = stl::exchange(other.vtable, nullptr); return *this; } /** * @brief Value assignment operator. * @param value An instance of an object to use to initialize the wrapper. * @return This meta any object. */ meta_any &operator=(auto &&value) requires (!stl::same_as, meta_any>) { emplace>(stl::forward(value)); return *this; } /** * @brief Returns the meta type associated with the contained instance. * @return The meta type associated with the contained instance. */ [[nodiscard]] inline meta_type type() const noexcept; /** * @brief Sets a meta type for the contained instance. * @param alias The meta to use with the contained instance. */ inline void type(const meta_type &alias) noexcept; /** * @brief Invokes the underlying function, if possible. * @param id Unique identifier. * @param args Parameters to use to invoke the function. * @return A wrapper containing the returned value, if any. */ meta_any invoke(id_type id, auto &&...args) const; /*! @copydoc invoke */ meta_any invoke(id_type id, auto &&...args); /** * @brief Sets the value of a given variable. * @param id Unique identifier. * @param args Parameters to use to set the underlying variable. * @return True in case of success, false otherwise. */ bool set(id_type id, auto &&...args); /** * @brief Gets the value of a given variable. * @param id Unique identifier. * @param args Parameters to use to set the underlying variable, if any. * @return A wrapper containing the value of the underlying variable. */ [[nodiscard]] meta_any get(id_type id, auto &&...args) const; /*! @copydoc get */ [[nodiscard]] meta_any get(id_type id, auto &&...args); /** * @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 { const auto *elem = any_cast(&storage); return ((elem != nullptr) || !*this) ? elem : static_cast(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), type_hash>::value(), storage.data())); } /*! @copydoc try_cast */ template [[nodiscard]] Type *try_cast() { return ((storage.policy() == any_policy::cref) && !stl::is_const_v) ? nullptr : const_cast(stl::as_const(*this).try_cast>()); } /** * @brief Tries to cast an instance to a given type. * @tparam Type Type to which to cast the instance. * @return A reference to the contained instance. */ template [[nodiscard]] stl::remove_const_t cast() const { auto *const instance = try_cast>(); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(*instance); } /*! @copydoc cast */ template [[nodiscard]] stl::remove_const_t 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. * @param type Meta type to which the cast is requested. * @return A valid meta object if convertible, an invalid one otherwise. */ [[nodiscard]] meta_any allow_cast(const meta_type &type) const; /** * @brief Converts an object in such a way that a given cast becomes viable. * @param type Meta type to which the cast is requested. * @return True if convertible, false otherwise. */ [[nodiscard]] bool allow_cast(const meta_type &type); /** * @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 object if convertible, an invalid one otherwise. */ template [[nodiscard]] meta_any allow_cast() const { if constexpr(!stl::is_reference_v || stl::is_const_v>) { if(storage.has_value>()) { return as_ref(); } else if(*this) { if constexpr(stl::is_arithmetic_v> || stl::is_enum_v>) { if(const auto &from = fetch_node(); from.conversion_helper) { return meta_any{*ctx, static_cast(from.conversion_helper(nullptr, storage.data()))}; } } if(const auto &from = fetch_node(); from.details != nullptr) { if(const auto *elem = internal::find_member(from.details->conv, entt::type_hash>::value()); elem != nullptr) { return elem->conv(*ctx, storage.data()); } for(auto &&curr: from.details->base) { if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == entt::type_hash>::value()) { return other; } else if(auto from_base = stl::as_const(other).template allow_cast(); from_base) { return from_base; } } } } } return meta_any{meta_ctx_arg, *ctx}; } /** * @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 convertible, false otherwise. */ template [[nodiscard]] bool allow_cast() { if constexpr(stl::is_reference_v && !stl::is_const_v>) { return allow_cast &>() && (storage.policy() != any_policy::cref); } else { if(storage.has_value>()) { return true; } else if(auto other = stl::as_const(*this).allow_cast>(); other) { if(other.storage.owner()) { stl::swap(*this, other); } return true; } return false; } } /*! @copydoc any::emplace */ template void emplace(auto &&...args) { storage.emplace(stl::forward(args)...); auto *prev = stl::exchange(vtable, &basic_vtable>); node = (prev == vtable) ? node : nullptr; } /*! @copydoc any::assign */ bool assign(const meta_any &other); /*! @copydoc any::assign */ bool assign(meta_any &&other); /*! @copydoc any::reset */ void reset() { storage.reset(); node = nullptr; vtable = nullptr; } /** * @brief Returns a sequence container proxy. * @return A sequence container proxy for the underlying object. */ [[nodiscard]] meta_sequence_container as_sequence_container() noexcept { meta_sequence_container proxy{}; if(*this) { vtable(internal::meta_traits::is_sequence_container, *this, &proxy); } return proxy; } /*! @copydoc as_sequence_container */ [[nodiscard]] meta_sequence_container as_sequence_container() const noexcept { meta_sequence_container proxy{}; if(*this) { vtable(internal::meta_traits::is_sequence_container, 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() noexcept { meta_associative_container proxy{}; if(*this) { vtable(internal::meta_traits::is_associative_container, *this, &proxy); } return proxy; } /*! @copydoc as_associative_container */ [[nodiscard]] meta_associative_container as_associative_container() const noexcept { meta_associative_container proxy{}; if(*this) { vtable(internal::meta_traits::is_associative_container, 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*() noexcept { meta_any ret{meta_ctx_arg, *ctx}; if(*this) { vtable(internal::meta_traits::is_pointer, *this, &ret); } return ret; } /*! @copydoc operator* */ [[nodiscard]] meta_any operator*() const noexcept { meta_any ret{meta_ctx_arg, *ctx}; if(*this) { vtable(internal::meta_traits::is_pointer, as_ref(), &ret); } return ret; } /*! @copydoc any::operator bool */ [[nodiscard]] explicit operator bool() const noexcept { return !(vtable == nullptr); } /*! @copydoc any::operator== */ [[nodiscard]] bool operator==(const meta_any &other) const noexcept { return (ctx == other.ctx) && (!*this == !other) && (storage == other.storage); } /*! @copydoc any::as_ref */ [[nodiscard]] meta_any as_ref() noexcept { return meta_any{*this, storage.as_ref()}; } /*! @copydoc any::as_ref */ [[nodiscard]] meta_any as_ref() const noexcept { return meta_any{*this, storage.as_ref()}; } /** * @brief Returns the underlying storage. * @return The underlyig storage. */ [[nodiscard]] const any &base() const noexcept { return storage; } /** * @brief Returns the underlying meta context. * @return The underlying meta context. */ [[nodiscard]] const meta_ctx &context() const noexcept { return *ctx; } private: any storage{}; const meta_ctx *ctx{&locator::value_or()}; mutable const internal::meta_type_node *node{}; vtable_type *vtable{}; }; /** * @brief Forwards its argument and avoids copies for lvalue references. * @param value Parameter to use to construct the instance. * @param ctx The context from which to search for meta types. * @return A properly initialized and not necessarily owning wrapper. */ [[nodiscard]] meta_any forward_as_meta(const meta_ctx &ctx, auto &&value) { return meta_any{ctx, stl::in_place_type, stl::forward(value)}; } /** * @brief Forwards its argument and avoids copies for lvalue references. * @param value Parameter to use to construct the instance. * @return A properly initialized and not necessarily owning wrapper. */ [[nodiscard]] meta_any forward_as_meta(auto &&value) { return forward_as_meta(locator::value_or(), stl::forward(value)); } /*! @brief Opaque pointers to instances of any type. */ class meta_handle { meta_handle(int, auto &value, auto &&...args) requires stl::same_as, meta_any> : any{stl::forward(args)..., value.as_ref()} {} meta_handle(char, auto &value, auto &&...args) : any{stl::forward(args)..., stl::in_place_type, value} {} public: /*! Default constructor. */ meta_handle() = default; /** * @brief Creates a handle that points to an unmanaged object. * @param ctx The context from which to search for meta types. * @param value An instance of an object to use to initialize the handle. */ meta_handle(const meta_ctx &ctx, auto &value) requires (!stl::same_as, meta_handle>) : meta_handle{0, value, ctx} {} /** * @brief Creates a handle that points to an unmanaged object. * @param value An instance of an object to use to initialize the handle. */ meta_handle(auto &value) requires (!stl::same_as, meta_handle>) : meta_handle{0, value} {} /** * @brief Context aware move constructor. * @param area The context from which to search for meta types. * @param other The instance to move from. */ meta_handle(const meta_ctx &area, meta_handle &&other) : any{area, stl::move(other.any)} {} /*! @brief Default copy constructor, deleted on purpose. */ meta_handle(const meta_handle &) = delete; /*! @brief Default move constructor. */ meta_handle(meta_handle &&) = default; /*! @brief Default destructor. */ ~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 Returns false if a handle is invalid, true otherwise. * @return False if the handle is invalid, true otherwise. */ [[nodiscard]] explicit operator bool() const 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; } private: meta_any any{}; }; /*! @brief Opaque wrapper for user defined data of any type. */ struct meta_custom { /*! @brief Default constructor. */ meta_custom() noexcept = default; /** * @brief Basic constructor for meta objects. * @param curr The underlying node with which to construct the instance. */ meta_custom(const internal::meta_custom_node &curr) noexcept : node{&curr} {} /** * @brief Generic conversion operator. * @tparam Type Type to which conversion is requested. */ template [[nodiscard]] operator Type *() const noexcept { return ((node != nullptr) && (type_hash>::value() == node->id)) ? static_cast(node->value.get()) : nullptr; } /** * @brief Generic conversion operator. * @tparam Type Type to which conversion is requested. */ template [[nodiscard]] operator Type &() const noexcept { ENTT_ASSERT(static_cast(*this) != nullptr, "Invalid type"); return *static_cast(node->value.get()); } private: const internal::meta_custom_node *node{}; }; /** * @brief Common opaque wrapper for meta objects. * @tparam Type Underlying meta node type. */ template struct meta_object: protected internal::basic_meta_object { /*! @brief Underlying meta node type. */ using node_type = Type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Default constructor. */ meta_object() noexcept = default; /** * @brief Context aware constructor for meta objects. * @param area The context from which to search for meta types. * @param curr The underlying node with which to construct the instance. */ meta_object(const meta_ctx &area, const node_type &curr) noexcept : internal::basic_meta_object{&curr, &area} { } /** * @brief Returns true if an object is valid, false otherwise. * @return True if the object is valid, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (this->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_object &other) const noexcept { return (this->ctx == other.ctx) && (this->node == other.node); } }; /*! @brief Opaque wrapper for data members. */ struct meta_data: meta_object { using meta_object::meta_object; /** * @brief Returns the name assigned to a data member, if any. * @return The name assigned to the data member, if any. */ [[nodiscard]] stl::string_view name() const noexcept { return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; } /** * @brief Returns the number of arguments of a data member's setter. * @return The number of arguments accepted by the data member's setter. */ [[nodiscard]] size_type set_arity() const noexcept { return node_or_assert().set_arity; } /** * @brief Returns the number of arguments of a data member's getter. * @return The number of arguments accepted by the data member's getter. */ [[nodiscard]] size_type get_arity() const noexcept { return node_or_assert().get_arity; } /** * @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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::is_static); } /*! @copydoc meta_any::type */ [[nodiscard]] inline meta_type type() const noexcept; /** * @brief Sets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to set the underlying variable. * @return True in case of success, false otherwise. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) bool set(Instance &&instance, auto &&...args) const { return (sizeof...(args) >= set_arity()) && node_or_assert().set(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); } /** * @brief Gets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to get the underlying variable, if any. * @return A wrapper containing the value of the underlying variable. */ template [[nodiscard]] meta_any get(Instance &&instance, auto &&...args) const { return (sizeof...(args) >= get_arity()) ? node_or_assert().get(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; } /** * @brief Returns the type of the i-th argument of a data member's setter. * @param index Index of the argument of which to return the type. * @return The type of the i-th argument of a data member's setter. */ [[nodiscard]] inline meta_type set_arg(size_type index) const noexcept; /** * @brief Returns the type of the i-th argument of a data member's getter. * @param index Index of the argument of which to return the type. * @return The type of the i-th argument of a data member's getter. */ [[nodiscard]] inline meta_type get_arg(size_type index) const noexcept; /** * @brief Returns all meta traits for a given meta object. * @tparam Type The type to convert the meta traits to. * @return The registered meta traits, if any. */ template [[nodiscard]] Type traits() const noexcept { return internal::meta_to_user_traits(node_or_assert().traits); } /** * @brief Returns user defined data for a given meta object. * @return User defined arbitrary data. */ [[nodiscard]] meta_custom custom() const noexcept { return {node_or_assert().custom}; } }; /*! @brief Opaque wrapper for member functions. */ struct meta_func: meta_object { using meta_object::meta_object; /** * @brief Returns the name assigned to a member function, if any. * @return The name assigned to the member function, if any. */ [[nodiscard]] stl::string_view name() const noexcept { return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; } /** * @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 noexcept { return node_or_assert().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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::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 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 noexcept; /** * @brief Invokes the underlying function, if possible. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to invoke the function. * @return A wrapper containing the returned value, if any. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) meta_any invoke(Instance &&instance, auto &&...args) const { return (sizeof...(args) == arity()) ? node_or_assert().invoke(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; } /*! @copydoc meta_data::traits */ template [[nodiscard]] Type traits() const noexcept { return internal::meta_to_user_traits(node_or_assert().traits); } /*! @copydoc meta_data::custom */ [[nodiscard]] meta_custom custom() const noexcept { return {node_or_assert().custom}; } /** * @brief Returns the next overload of a given function, if any. * @return The next overload of the given function, if any. */ [[nodiscard]] meta_func next() const { return (node_or_assert().next != nullptr) ? meta_func{*ctx, *node_or_assert().next} : meta_func{}; } }; /*! @brief Opaque wrapper for base types. */ struct meta_base: meta_object { using meta_object::meta_object; /*! @copydoc meta_any::type */ [[nodiscard]] inline meta_type type() const noexcept; }; /*! @brief Opaque wrapper for types. */ class meta_type { friend class meta_any; [[nodiscard]] const auto &fetch_node() const { return (node == nullptr) ? internal::resolve(internal::meta_context::from(*ctx)) : *node; } [[nodiscard]] auto lookup(meta_handle *const args, const auto sz, [[maybe_unused]] bool constness, auto next) const { decltype(next()) candidate = nullptr; size_type same{}; bool ambiguous{}; for(auto curr = next(); curr; curr = next()) { if constexpr(stl::is_same_v, internal::meta_func_node>) { if(constness && !(curr->traits & internal::meta_traits::is_const)) { continue; } } if(curr->arity == sz) { size_type match{}; size_type pos{}; // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) for(; pos < sz; ++pos) { const auto other = curr->arg(*ctx, pos); const auto type = args[pos]->type(); if(const auto &info = other.info(); info == type.info()) { ++match; } else if(!(type.fetch_node().conversion_helper && other.fetch_node().conversion_helper) && !(type.fetch_node().details && (internal::find_member(type.fetch_node().details->base, info.hash()) || internal::find_member(type.fetch_node().details->conv, info.hash())))) { break; } } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) if(pos == sz) { if(!candidate || match > same) { candidate = curr; same = match; ambiguous = false; } else if(match == same) { if constexpr(stl::is_same_v, internal::meta_func_node>) { if(!!(curr->traits & internal::meta_traits::is_const) != !!(candidate->traits & internal::meta_traits::is_const)) { candidate = !!(candidate->traits & internal::meta_traits::is_const) ? curr : candidate; ambiguous = false; continue; } } ambiguous = true; } } } } return ambiguous ? nullptr : candidate; } public: /*! @brief Unsigned integer type. */ using size_type = internal::meta_type_node::size_type; /*! @brief Default constructor. */ meta_type() noexcept = default; /** * @brief Context aware constructor for meta objects. * @param area The context from which to search for meta types. * @param curr The underlying node with which to construct the instance. */ meta_type(const meta_ctx &area, const internal::meta_type_node &curr) noexcept : node{&curr}, ctx{&area} {} /** * @brief Returns the type info object of the underlying type. * @return The type info object of the underlying type. */ [[nodiscard]] const type_info &info() const noexcept { return *fetch_node().info; } /** * @brief Returns the alias assigned to a type. * @return The alias assigned to the type. */ [[nodiscard]] id_type alias() const noexcept { return fetch_node().alias; } /** * @brief Returns the name assigned to a type, if any. * @return The name assigned to the type, if any. */ [[nodiscard]] stl::string_view name() const noexcept { return (fetch_node().name == nullptr) ? stl::string_view{} : stl::string_view{fetch_node().name}; } /** * @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 noexcept { return fetch_node().size_of; } /** * @brief Checks whether a type refers to an arithmetic type or not. * @return True if the underlying type is an arithmetic type, false * otherwise. */ [[nodiscard]] bool is_arithmetic() const noexcept { return !!(fetch_node().traits & internal::meta_traits::is_arithmetic); } /** * @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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_integral); } /** * @brief Checks whether a type refers to a signed type or not. * @return True if the underlying type is a signed type, false otherwise. */ [[nodiscard]] bool is_signed() const noexcept { return !!(fetch_node().traits & internal::meta_traits::is_signed); } /** * @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 noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_enum); } /** * @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 noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_pointer); } /** * @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 noexcept { return meta_type{*ctx, fetch_node().remove_pointer(internal::meta_context::from(*ctx))}; } /** * @brief Checks whether a type is a pointer-like type or not. * @return True if the underlying type is pointer-like, false otherwise. */ [[nodiscard]] bool is_pointer_like() const noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_associative_container); } /** * @brief Checks whether a type refers to a template specialization or not. * @return True if the type is a template specialization, false otherwise. */ [[nodiscard]] bool is_template_specialization() const noexcept { return (fetch_node().templ.arity != 0u); } /** * @brief Returns the number of template arguments. * @return The number of template arguments. */ [[nodiscard]] size_type template_arity() const noexcept { return fetch_node().templ.arity; } /** * @brief Returns a tag for the class template of the underlying type. * @return The tag for the class template of the underlying type. */ [[nodiscard]] meta_type template_type() const noexcept { return (fetch_node().templ.resolve != nullptr) ? meta_type{*ctx, fetch_node().templ.resolve(internal::meta_context::from(*ctx))} : 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]] meta_type template_arg(const size_type index) const noexcept { return index < template_arity() ? meta_type{*ctx, fetch_node().templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{}; } /** * @brief Checks if a type supports direct casting to another type. * @param other The meta type to test for. * @return True if direct casting is allowed, false otherwise. */ [[nodiscard]] bool can_cast(const meta_type &other) const noexcept { // casting this is UB in all cases but we aren't going to use the resulting pointer, so... return other && ((*this == other) || (internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), other.fetch_node().info->hash(), this) != nullptr)); } /** * @brief Checks whether a type supports conversion to another type. * @param other The meta type to test for. * @return True if the conversion is allowed, false otherwise. */ [[nodiscard]] bool can_convert(const meta_type &other) const noexcept { if(const auto &to = other.info().hash(); (info().hash() == to) || ((fetch_node().conversion_helper != nullptr) && (other.is_arithmetic() || other.is_enum()))) { return true; } else if(const auto &from = fetch_node(); from.details) { if(const auto *elem = internal::find_member(from.details->conv, to); elem != nullptr) { return true; } for(auto &&curr: from.details->base) { if(curr.id == to || meta_type{*ctx, curr.type(internal::meta_context::from(*ctx))}.can_convert(other)) { return true; } } } return false; } /** * @brief Returns a range to visit registered top-level base meta types. * @return An iterable range to visit registered top-level base meta types. */ [[nodiscard]] meta_range base() const noexcept { using range_type = meta_range; return fetch_node().details ? range_type{{*ctx, fetch_node().details->base.cbegin()}, {*ctx, fetch_node().details->base.cend()}} : range_type{}; } /** * @brief Returns a range to visit registered top-level meta data. * @return An iterable range to visit registered top-level meta data. */ [[nodiscard]] meta_range data() const noexcept { using range_type = meta_range; return fetch_node().details ? range_type{{*ctx, fetch_node().details->data.cbegin()}, {*ctx, fetch_node().details->data.cend()}} : range_type{}; } /** * @brief Lookup utility for meta data (bases are also visited). * @param id Unique identifier. * @param recursive True for a search in the base classes, false otherwise. * @return The registered meta data for the given identifier, if any. */ [[nodiscard]] meta_data data(const id_type id, const bool recursive = true) const { const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); return (elem != nullptr) ? meta_data{*ctx, *elem} : meta_data{}; } /** * @brief Returns a range to visit registered top-level functions. * @return An iterable range to visit registered top-level functions. */ [[nodiscard]] meta_range func() const noexcept { using return_type = meta_range; return fetch_node().details ? return_type{{*ctx, fetch_node().details->func.cbegin()}, {*ctx, fetch_node().details->func.cend()}} : return_type{}; } /** * @brief Lookup utility for meta functions (bases are also visited). * @param id Unique identifier. * @param recursive True for a search in the base classes, false otherwise. * @return The registered meta function for the given identifier, if any. */ [[nodiscard]] meta_func func(const id_type id, const bool recursive = true) const { const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); return (elem != nullptr) ? meta_func{*ctx, *elem} : meta_func{}; } /** * @copybrief construct * @param args Parameters to use to construct the instance. * @return A wrapper containing the new instance, if any. */ [[nodiscard]] meta_any construct(auto &&...args) const { if(const auto &ref = fetch_node(); ref.details) { if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), false, [first = ref.details->ctor.cbegin(), last = ref.details->ctor.cend()]() mutable { return first == last ? nullptr : &*(first++); }); candidate) { return candidate->invoke(*ctx, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); } } if(const auto &ref = fetch_node(); (sizeof...(args) == 0u) && (ref.default_constructor != nullptr)) { return ref.default_constructor(*ctx); } return meta_any{meta_ctx_arg, *ctx}; } /** * @brief Wraps an opaque element of the underlying type. * @param elem A valid pointer to an element of the underlying type. * @param transfer_ownership True to transfer ownership, false otherwise. * @return A wrapper that references the given instance. */ [[nodiscard]] meta_any from_void(void *elem, bool transfer_ownership = false) const { return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{meta_ctx_arg, *ctx}; } /** * @brief Wraps an opaque element of the underlying type. * @param elem A valid pointer to an element of the underlying type. * @return A wrapper that references the given instance. */ [[nodiscard]] meta_any from_void(const void *elem) const { return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, nullptr, elem) : meta_any{meta_ctx_arg, *ctx}; } /** * @copybrief invoke * @param id Unique identifier. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to invoke the function. * @return A wrapper containing the returned value, if any. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) meta_any invoke(const id_type id, Instance &&instance, auto &&...args) const { meta_handle wrapped{*ctx, stl::forward(instance)}; if(const auto &ref = fetch_node(); ref.details) { if(auto *elem = internal::find_member(ref.details->func, id); elem != nullptr) { if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), (wrapped->base().policy() == any_policy::cref), [curr = elem]() mutable { return (curr != nullptr) ? stl::exchange(curr, curr->next.get()) : nullptr; }); candidate) { return candidate->invoke(stl::move(wrapped), stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); } } } for(auto &&curr: base()) { if(auto elem = curr.second.type().invoke(id, *wrapped.operator->(), stl::forward(args)...); elem) { return elem; } } return meta_any{meta_ctx_arg, *ctx}; } /** * @brief Sets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param id Unique identifier. * @param instance An instance that fits the underlying type. * @param args Parameters to use to set the underlying variable. * @return True in case of success, false otherwise. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) bool set(const id_type id, Instance &&instance, auto &&...args) const { const auto candidate = data(id); return candidate && candidate.set(stl::forward(instance), stl::forward(args)...); } /** * @brief Gets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param id Unique identifier. * @param instance An instance that fits the underlying type. * @param args Parameters to use to set the underlying variable, if any. * @return A wrapper containing the value of the underlying variable. */ template [[nodiscard]] meta_any get(const id_type id, Instance &&instance, auto &&...args) const { const auto candidate = data(id); return candidate ? candidate.get(stl::forward(instance), stl::forward(args)...) : meta_any{meta_ctx_arg, *ctx}; } /*! @copydoc meta_data::traits */ template [[nodiscard]] Type traits() const noexcept { return internal::meta_to_user_traits(fetch_node().traits); } /*! @copydoc meta_data::custom */ [[nodiscard]] meta_custom custom() const noexcept { return fetch_node().custom; } /*! @copydoc meta_data::operator bool */ [[nodiscard]] explicit operator bool() const noexcept { return (node != nullptr); } /*! @copydoc meta_data::operator== */ [[nodiscard]] bool operator==(const meta_type &other) const noexcept { return (ctx == other.ctx) && (fetch_node().alias == other.fetch_node().alias); } private: mutable const internal::meta_type_node *node{}; const meta_ctx *ctx{&locator::value_or()}; }; [[nodiscard]] inline meta_type meta_any::type() const noexcept { return *this ? meta_type{*ctx, fetch_node()} : meta_type{}; } inline void meta_any::type(const meta_type &alias) noexcept { ENTT_ASSERT(storage.info() == alias.info(), "Unexpected type"); node = alias.node; ctx = alias.ctx; } // NOLINTNEXTLINE(modernize-use-nodiscard) meta_any meta_any::invoke(const id_type id, auto &&...args) const { return type().invoke(id, *this, stl::forward(args)...); } meta_any meta_any::invoke(const id_type id, auto &&...args) { return type().invoke(id, *this, stl::forward(args)...); } bool meta_any::set(const id_type id, auto &&...args) { return type().set(id, *this, stl::forward(args)...); } [[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) const { return type().get(id, *this, stl::forward(args)...); } [[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) { return type().get(id, *this, stl::forward(args)...); } [[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { if(storage.has_value(type.info())) { return as_ref(); } else if(*this) { if(const auto &from = fetch_node(); (from.conversion_helper != nullptr) && (type.is_arithmetic() || type.is_enum())) { auto other = type.construct(); const auto value = from.conversion_helper(nullptr, storage.data()); other.fetch_node().conversion_helper(other.storage.data(), &value); return other; } if(const auto &from = fetch_node(); from.details) { if(const auto *elem = internal::find_member(from.details->conv, type.info().hash()); elem != nullptr) { return elem->conv(*ctx, storage.data()); } for(auto &&curr: from.details->base) { if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == type.info().hash()) { return other; } else if(auto from_base = stl::as_const(other).allow_cast(type); from_base) { return from_base; } } } } return meta_any{meta_ctx_arg, *ctx}; } [[nodiscard]] inline bool meta_any::allow_cast(const meta_type &type) { if(storage.has_value(type.info())) { return true; } else if(auto other = stl::as_const(*this).allow_cast(type); other) { if(other.storage.owner()) { stl::swap(*this, other); } return true; } return false; } inline bool meta_any::assign(const meta_any &other) { if(!storage.assign(other.storage)) { auto value = other.allow_cast(type()); return storage.assign(value.storage); } return true; } inline bool meta_any::assign(meta_any &&other) { return storage.assign(stl::move(other.storage)) || storage.assign(stl::as_const(other).allow_cast(type()).storage); } [[nodiscard]] inline meta_type meta_data::type() const noexcept { return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; } [[nodiscard]] inline meta_type meta_data::set_arg(const size_type index) const noexcept { return index < set_arity() ? node_or_assert().set_arg(*ctx, index) : meta_type{}; } [[nodiscard]] inline meta_type meta_data::get_arg(const size_type index) const noexcept { return index < get_arity() ? node_or_assert().get_arg(*ctx, index) : meta_type{}; } [[nodiscard]] inline meta_type meta_func::ret() const noexcept { return meta_type{*ctx, node_or_assert().ret(internal::meta_context::from(*ctx))}; } [[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept { return index < arity() ? node_or_assert().arg(*ctx, index) : meta_type{}; } [[nodiscard]] inline meta_type meta_base::type() const noexcept { return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; } /*! @cond ENTT_INTERNAL */ class meta_sequence_container::meta_iterator final { using vtable_type = void(const void *, const stl::ptrdiff_t, meta_any *); template static void basic_vtable(const void *value, const stl::ptrdiff_t offset, meta_any *other) { const auto &it = *static_cast(value); other ? other->emplace(*it) : stl::advance(const_cast(it), offset); } public: using value_type = meta_any; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::bidirectional_iterator_tag; meta_iterator() = default; meta_iterator(const meta_ctx &area, stl::bidirectional_iterator auto iter) noexcept : ctx{&area}, vtable{&basic_vtable}, handle{iter} {} meta_iterator &operator++() noexcept { return vtable(handle.data(), 1, nullptr), *this; } meta_iterator operator++(int value) noexcept { meta_iterator orig = *this; vtable(handle.data(), ++value, nullptr); return orig; } meta_iterator &operator--() noexcept { return vtable(handle.data(), -1, nullptr), *this; } meta_iterator operator--(int value) noexcept { meta_iterator orig = *this; vtable(handle.data(), --value, nullptr); return orig; } [[nodiscard]] reference operator*() const { reference other{meta_ctx_arg, *ctx}; vtable(handle.data(), 0, &other); return other; } [[nodiscard]] pointer operator->() const { return operator*(); } [[nodiscard]] explicit operator bool() const noexcept { return (vtable != nullptr); } [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { return handle == other.handle; } [[nodiscard]] const any &base() const noexcept { return handle; } private: const meta_ctx *ctx{}; vtable_type *vtable{}; any handle{}; }; class meta_associative_container::meta_iterator final { using vtable_type = void(const void *, stl::pair *); template static void basic_vtable(const void *value, stl::pair *other) { if(const auto &it = *static_cast(value); other) { if constexpr(KeyOnly) { other->first.emplace(*it); } else { other->first.emplacefirst))>(it->first); other->second.emplacesecond))>(it->second); } } else { ++const_cast(it); } } public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; meta_iterator() = default; template meta_iterator(const meta_ctx &area, stl::bool_constant, stl::forward_iterator auto iter) noexcept : ctx{&area}, vtable{&basic_vtable}, handle{iter} {} meta_iterator &operator++() noexcept { return vtable(handle.data(), nullptr), *this; } meta_iterator operator++(int) noexcept { meta_iterator orig = *this; vtable(handle.data(), nullptr); return orig; } [[nodiscard]] reference operator*() const { reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}}; vtable(handle.data(), &other); return other; } [[nodiscard]] pointer operator->() const { return operator*(); } [[nodiscard]] explicit operator bool() const noexcept { return (vtable != nullptr); } [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { return handle == other.handle; } private: const meta_ctx *ctx{}; vtable_type *vtable{}; any handle{}; }; /*! @endcond */ /** * @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 noexcept { return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /** * @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 noexcept { return size_fn(data); } /** * @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(const size_type sz) { return !const_only && resize_fn(const_cast(data), sz); } /** * @brief Clears the content of a container. * @return True in case of success, false otherwise. */ inline bool meta_sequence_container::clear() { return !const_only && clear_fn(const_cast(data)); } /** * @brief Reserves storage for at least the given number of elements. * @param sz The new capacity of the container. * @return True in case of success, false otherwise. */ inline bool meta_sequence_container::reserve(const size_type sz) { return !const_only && reserve_fn(const_cast(data), sz); } /** * @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_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); } /** * @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 begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); } /** * @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 possibly invalid iterator to the inserted element. */ inline meta_sequence_container::iterator meta_sequence_container::insert(const iterator &it, meta_any value) { // this abomination is necessary because only on macos value_type and const_reference are different types for stl::vector if(const auto &vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) { const bool is_value_type = (value.type().info() == *vtype.info); return insert_fn(*ctx, const_cast(data), is_value_type ? value.base().data() : nullptr, is_value_type ? nullptr : value.base().data(), it); } return iterator{}; } /** * @brief Removes a given element from a container. * @param it Iterator to the element to remove. * @return A possibly invalid iterator following the last removed element. */ inline meta_sequence_container::iterator meta_sequence_container::erase(const iterator &it) { return const_only ? iterator{} : erase_fn(*ctx, const_cast(data), it); } /** * @brief Returns a reference to the element at a given location of a container. * @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[](const size_type pos) { auto it = begin(); it.operator++(static_cast(pos) - 1); return *it; } /** * @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 noexcept { return (data != nullptr); } /** * @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 noexcept { return (key_type_node != nullptr) ? meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /** * @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 noexcept { return (mapped_type_node != nullptr) ? meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /*! @copydoc meta_sequence_container::value_type */ [[nodiscard]] inline meta_type meta_associative_container::value_type() const noexcept { return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /*! @copydoc meta_sequence_container::size */ [[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept { return size_fn(data); } /*! @copydoc meta_sequence_container::clear */ inline bool meta_associative_container::clear() { return !const_only && clear_fn(const_cast(data)); } /*! @copydoc meta_sequence_container::reserve */ inline bool meta_associative_container::reserve(const size_type sz) { return !const_only && reserve_fn(const_cast(data), sz); } /*! @copydoc meta_sequence_container::begin */ [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() { return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); } /*! @copydoc meta_sequence_container::end */ [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() { return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); } /** * @brief Inserts a key-only or key/value element into a container. * @param key The key of the element to insert. * @param value The value of the element to insert, if needed. * @return A bool denoting whether the insertion took place. */ inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) && ((mapped_type_node == nullptr) || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))})) && insert_fn(const_cast(data), key.base().data(), value.base().data()); } /** * @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 meta_associative_container::size_type meta_associative_container::erase(meta_any key) { return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast(data), key.base().data()) : 0u; } /** * @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 key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast(data), data, key.base().data()) : iterator{}; } /** * @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 noexcept { return (data != nullptr); } } // namespace entt #endif // #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct sequence_container_extent: integral_constant {}; template requires is_complete_v> struct sequence_container_extent: integral_constant> {}; template inline constexpr stl::size_t sequence_container_extent_v = sequence_container_extent::value; template concept meta_sequence_container_like = requires(Type elem) { typename Type::value_type; typename Type::iterator; requires entt::stl::forward_iterator; { elem.begin() } -> stl::same_as; { elem.end() } -> stl::same_as; requires !requires { typename Type::key_type; }; requires !requires { elem.substr(); }; }; template concept meta_associative_container_like = requires(Type value) { typename Type::key_type; typename Type::value_type; typename Type::iterator; requires entt::stl::forward_iterator; { value.begin() } -> stl::same_as; { value.end() } -> stl::same_as; value.find(stl::declval()); }; } // namespace internal /*! @endcond */ /** * @brief General purpose implementation of meta sequence container traits. * @tparam Type Type of underlying sequence container. */ template struct basic_meta_sequence_container_traits { /*! @brief Unsigned integer type. */ using size_type = meta_sequence_container::size_type; /*! @brief Meta iterator type. */ using iterator = meta_sequence_container::iterator; /*! @brief Number of elements, or `meta_dynamic_extent` if dynamic. */ static constexpr stl::size_t extent = internal::sequence_container_extent_v; /** * @brief Returns the number of elements in a container. * @param container Opaque pointer to a container of the given type. * @return Number of elements. */ [[nodiscard]] static size_type size(const void *container) { return static_cast(container)->size(); } /** * @brief Clears a container. * @param container Opaque pointer to a container of the given type. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool clear([[maybe_unused]] void *container) { if constexpr(requires(Type elem) { elem.clear(); }) { static_cast(container)->clear(); return true; } else { return false; } } /** * @brief Increases the capacity of a container. * @param container Opaque pointer to a container of the given type. * @param sz Desired capacity. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { if constexpr(requires(Type elem) { elem.reserve(sz); }) { static_cast(container)->reserve(sz); return true; } else { return false; } } /** * @brief Resizes a container. * @param container Opaque pointer to a container of the given type. * @param sz The new number of elements. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { if constexpr(stl::is_default_constructible_v && requires(Type elem) { elem.resize(sz); }) { static_cast(container)->resize(sz); return true; } else { return false; } } /** * @brief Returns a possibly const iterator to the beginning or the end. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param as_const Const opaque pointer fallback. * @param end False to get a pointer that is past the last element. * @return An iterator to the first or past the last element of the * container. */ static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) { return (container == nullptr) ? iterator{area, end ? static_cast(as_const)->cend() : static_cast(as_const)->cbegin()} : iterator{area, end ? static_cast(container)->end() : static_cast(container)->begin()}; } /** * @brief Assigns one element to a container and constructs its object from * a given opaque instance. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param value Optional opaque instance of the object to construct (as * value type). * @param cref Optional opaque instance of the object to construct (as * decayed const reference type). * @param it Iterator before which the element will be inserted. * @return A possibly invalid iterator to the inserted element. */ [[nodiscard]] static iterator insert([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) { if constexpr(requires(Type elem, typename Type::const_iterator iter, Type::value_type instance) { elem.insert(iter, instance); }) { auto *const non_const = any_cast(&it.base()); return {area, static_cast(container)->insert( non_const ? *non_const : any_cast(it.base()), (value != nullptr) ? *static_cast(value) : *static_cast *>(cref))}; } else { return iterator{}; } } /** * @brief Erases an element from a container. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param it An opaque iterator to the element to erase. * @return A possibly invalid iterator following the last removed element. */ [[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) { if constexpr(requires(Type elem, typename Type::const_iterator iter) { elem.erase(iter); }) { auto *const non_const = any_cast(&it.base()); return {area, static_cast(container)->erase(non_const ? *non_const : any_cast(it.base()))}; } else { return iterator{}; } } }; /** * @brief General purpose implementation of meta associative container traits. * @tparam Type Type of underlying associative container. */ template struct basic_meta_associative_container_traits { /*! @brief Unsigned integer type. */ using size_type = meta_associative_container::size_type; /*! @brief Meta iterator type. */ using iterator = meta_associative_container::iterator; /*! @brief True in case of key-only containers, false otherwise. */ static constexpr bool key_only = !requires { typename Type::mapped_type; }; /** * @brief Returns the number of elements in a container. * @param container Opaque pointer to a container of the given type. * @return Number of elements. */ [[nodiscard]] static size_type size(const void *container) { return static_cast(container)->size(); } /** * @brief Clears a container. * @param container Opaque pointer to a container of the given type. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool clear(void *container) { static_cast(container)->clear(); return true; } /** * @brief Increases the capacity of a container. * @param container Opaque pointer to a container of the given type. * @param sz Desired capacity. * @return True in case of success, false otherwise. */ [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { if constexpr(requires(Type elem) { elem.reserve(sz); }) { static_cast(container)->reserve(sz); return true; } else { return false; } } /** * @brief Returns a possibly const iterator to the beginning or the end. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param as_const Const opaque pointer fallback. * @param end False to get a pointer that is past the last element. * @return An iterator to the first or past the last element of the * container. */ static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) { return (container == nullptr) ? iterator{area, stl::bool_constant{}, end ? static_cast(as_const)->cend() : static_cast(as_const)->cbegin()} : iterator{area, stl::bool_constant{}, end ? static_cast(container)->end() : static_cast(container)->begin()}; } /** * @brief Inserts an element into a container, if the key does not exist. * @param container Opaque pointer to a container of the given type. * @param key An opaque key value of an element to insert. * @param value Optional opaque value to insert (key-value containers). * @return True if the insertion took place, false otherwise. */ [[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) { if constexpr(key_only) { return static_cast(container)->insert(*static_cast(key)).second; } else { return static_cast(container)->emplace(*static_cast(key), *static_cast(value)).second; } } /** * @brief Removes an element from a container. * @param container Opaque pointer to a container of the given type. * @param key An opaque key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ [[nodiscard]] static size_type erase(void *container, const void *key) { return static_cast(container)->erase(*static_cast(key)); } /** * @brief Finds an element with a given key. * @param area The context to pass to the newly created iterator. * @param container Opaque pointer to a container of the given type. * @param as_const Const opaque pointer fallback. * @param key Opaque key value of an element to search for. * @return An iterator to the element with the given key, if any. */ static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) { return (container != nullptr) ? iterator{area, stl::bool_constant{}, static_cast(container)->find(*static_cast(key))} : iterator{area, stl::bool_constant{}, static_cast(as_const)->find(*static_cast(key))}; } }; /** * @brief Traits meta sequence container like types. * @tparam Type Container type to inspect. */ template struct meta_sequence_container_traits: basic_meta_sequence_container_traits {}; /** * @brief Traits for meta associative container like types. * @tparam Type Container type to inspect. */ template struct meta_associative_container_traits: basic_meta_associative_container_traits {}; } // namespace entt #endif // #include "meta/context.hpp" #ifndef ENTT_META_CTX_HPP #define ENTT_META_CTX_HPP // #include "../container/dense_map.hpp" // #include "../core/fwd.hpp" // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct meta_type_node; struct meta_context { using bucket_type = dense_map, stl::identity>; bucket_type bucket; [[nodiscard]] inline static meta_context &from(meta_ctx &); [[nodiscard]] inline static const meta_context &from(const meta_ctx &); }; } // namespace internal /*! @endcond */ /*! @brief Opaque meta context type. */ struct meta_ctx: private internal::meta_context { // attorney idiom like model to access the base class friend struct internal::meta_context; }; /*! @cond ENTT_INTERNAL */ [[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) { return ctx; } [[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) { return ctx; } /*! @endcond */ } // namespace entt #endif // #include "meta/factory.hpp" #ifndef ENTT_META_FACTORY_HPP #define ENTT_META_FACTORY_HPP // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../core/fwd.hpp" // #include "../core/hashed_string.hpp" #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct fnv_1a_params; template<> struct fnv_1a_params { static constexpr auto offset = 2166136261; static constexpr auto prime = 16777619; }; template<> struct fnv_1a_params { static constexpr auto offset = 14695981039346656037ull; static constexpr auto prime = 1099511628211ull; }; template struct basic_hashed_string { using value_type = Char; using size_type = stl::size_t; using hash_type = id_type; const value_type *repr{}; hash_type hash{fnv_1a_params<>::offset}; size_type length{}; }; } // namespace internal /*! @endcond */ /** * @brief Zero overhead unique identifier. * * A hashed string is a compile-time tool that allows users to use * human-readable identifiers 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. * * @warning * This class doesn't take ownership of user-supplied strings nor does it make a * copy of them. * * @tparam Char Character type. */ template class basic_hashed_string: internal::basic_hashed_string { using base_type = internal::basic_hashed_string; using params = internal::fnv_1a_params<>; struct const_wrapper { // non-explicit constructor on purpose constexpr const_wrapper(const base_type::value_type *str) noexcept : repr{str} {} const base_type::value_type *repr; }; public: /*! @brief Character type. */ using value_type = base_type::value_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Unsigned integer type. */ using hash_type = base_type::hash_type; /** * @brief Returns directly the numeric representation of a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. * @return The numeric representation of the string. */ [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { return basic_hashed_string{str, len}; } /** * @brief Returns directly the numeric representation of a string. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. * @return The numeric representation of the string. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { return basic_hashed_string{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 constexpr hash_type value(const_wrapper wrapper) noexcept { return basic_hashed_string{wrapper}; } /*! @brief Constructs an empty hashed string. */ constexpr basic_hashed_string() noexcept : basic_hashed_string{nullptr, 0u} {} /** * @brief Constructs a hashed string from a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. */ constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; base_type::length < len; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Constructs a hashed string from an array of const characters. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { for(; str[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } } /** * @brief Explicit constructor on purpose to avoid constructing a hashed * string directly from a `const value_type *`. * * @warning * The lifetime of the string is not extended nor is it copied. * * @param wrapper Helps achieving the purpose by relying on overloading. */ explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept : base_type{wrapper.repr} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; wrapper.repr[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Returns the size of a hashed string. * @return The size of the hashed string. */ [[nodiscard]] constexpr size_type size() const noexcept { return base_type::length; } /** * @brief Returns the human-readable representation of a hashed string. * @return The string used to initialize the hashed string. */ [[nodiscard]] constexpr const value_type *data() const noexcept { return base_type::repr; } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr hash_type value() const noexcept { return base_type::hash; } /*! @copydoc data */ [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { return data(); } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr operator hash_type() const noexcept { return value(); } /** * @brief Compares two hashed strings. * @param other A valid hashed string. * @return True if the two hashed strings are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { return value() == other.value(); } /** * @brief Lexicographically compares two hashed strings. * @param other A valid hashed string. * @return The relative order between the two hashed strings. */ [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { return value() <=> other.value(); } }; /** * @brief Deduction guide. * @tparam Char Character type. * @param str Human-readable identifier. * @param len Length of the string to hash. */ template basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; /** * @brief Deduction guide. * @tparam Char Character type. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) basic_hashed_string(const Char (&str)[N]) -> 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]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { return hashed_string{str}; } /** * @brief User defined literal for hashed wstrings. * @param str The literal without its suffix. * @return A properly initialized hashed wstring. */ [[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { return hashed_wstring{str}; } } // namespace literals } // namespace entt #endif // #include "../core/type_info.hpp" // #include "../core/type_traits.hpp" // #include "../locator/locator.hpp" // #include "../stl/algorithm.hpp" #ifndef ENTT_STL_ALGORITHM_HPP #define ENTT_STL_ALGORITHM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::all_of; using std::any_of; using std::find_if; using std::none_of; using std::sort; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "context.hpp" // #include "fwd.hpp" // #include "meta.hpp" // #include "node.hpp" // #include "policy.hpp" #ifndef ENTT_META_POLICY_HPP #define ENTT_META_POLICY_HPP // #include "../stl/type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct meta_policy {}; } // namespace internal /*! @endcond */ /*! @brief Empty class type used to request the _as-is_ policy. */ struct as_value_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = true; /*! @endcond */ }; /*! @brief Empty class type used to request the _as void_ policy. */ struct as_void_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = true; /*! @endcond */ }; /*! @brief Empty class type used to request the _as ref_ policy. */ struct as_ref_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = stl::is_reference_v && !stl::is_const_v>; /*! @endcond */ }; /*! @brief Empty class type used to request the _as cref_ policy. */ struct as_cref_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = stl::is_reference_v; /*! @endcond */ }; /*! @brief Empty class type used to request the _as auto_ policy. */ struct as_is_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = true; /*! @endcond */ }; /** * @brief Provides the member constant `value` equal to true if a type also is a * meta policy, false otherwise. * @tparam Type Type to check. */ template struct is_meta_policy : stl::bool_constant> {}; /** * @brief Helper variable template. * @tparam Type Type to check. */ template inline constexpr bool is_meta_policy_v = is_meta_policy::value; /** * @brief Specifies whether a type is a meta policy. * @tparam Type Type to check. */ template concept meta_policy = is_meta_policy_v; } // namespace entt #endif // #include "range.hpp" // #include "utility.hpp" #ifndef ENTT_META_UTILITY_HPP #define ENTT_META_UTILITY_HPP // #include "../core/type_traits.hpp" // #include "../locator/locator.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "meta.hpp" // #include "node.hpp" // #include "policy.hpp" namespace entt { /** * @brief Meta function descriptor traits. * @tparam Ret Function return type. * @tparam Args Function arguments. * @tparam Static Function staticness. * @tparam Const Function constness. */ template struct meta_function_descriptor_traits { /*! @brief Meta function return type. */ using return_type = Ret; /*! @brief Meta function arguments. */ using args_type = Args; /*! @brief True if the meta function is static, false otherwise. */ static constexpr bool is_static = Static; /*! @brief True if the meta function is const, false otherwise. */ static constexpr bool is_const = Const; }; /*! @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 : meta_function_descriptor_traits< Ret, stl::conditional_t, type_list, type_list>, !stl::is_base_of_v, true> {}; /** * @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 : meta_function_descriptor_traits< Ret, stl::conditional_t, type_list, type_list>, !stl::is_base_of_v, false> {}; /** * @brief Meta function descriptor. * @tparam Type Reflected type to which the meta data is associated. * @tparam Class Actual owner of the data member. * @tparam Ret Data member type. */ template struct meta_function_descriptor : meta_function_descriptor_traits< Ret &, stl::conditional_t, type_list<>, type_list>, !stl::is_base_of_v, false> {}; /** * @brief Meta function descriptor. * @tparam Type Reflected type to which the meta function is associated. * @tparam Ret Function return type. * @tparam MaybeType First function argument. * @tparam Args Other function arguments. */ template struct meta_function_descriptor : meta_function_descriptor_traits< Ret, stl::conditional_t< stl::is_same_v, Type> || stl::is_base_of_v, Type>, type_list, type_list>, !(stl::is_same_v, Type> || stl::is_base_of_v, Type>), stl::is_const_v> && (stl::is_same_v, Type> || stl::is_base_of_v, Type>)> {}; /** * @brief Meta function descriptor. * @tparam Type Reflected type to which the meta function is associated. * @tparam Ret Function return type. */ template struct meta_function_descriptor : meta_function_descriptor_traits< Ret, type_list<>, true, false> {}; /** * @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 meta_function_descriptor get_rid_of_noexcept(Ret (Class::*)(Args...) const); template static meta_function_descriptor get_rid_of_noexcept(Ret (Class::*)(Args...)); template requires stl::is_member_object_pointer_v static meta_function_descriptor get_rid_of_noexcept(Ret Class::*); template static meta_function_descriptor get_rid_of_noexcept(Ret (*)(Args...)); template static meta_function_descriptor get_rid_of_noexcept(Class); public: /*! @brief The meta function descriptor of the given function. */ using type = decltype(get_rid_of_noexcept(stl::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 = meta_function_helper::type; /** * @brief Wraps a value depending on the given policy. * * This function always returns a wrapped value in the requested context.
* Therefore, if the passed value is itself a wrapped object with a different * context, it undergoes a rebinding to the requested context. * * @tparam Policy Optional policy (no policy set by default). * @tparam Type Type of value to wrap. * @param ctx The context from which to search for meta types. * @param value Value to wrap. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) { if constexpr(stl::is_same_v) { static_assert(stl::is_lvalue_reference_v, "Invalid type"); return meta_any{ctx, stl::in_place_type &>, stl::as_const(value)}; } else if constexpr(stl::is_same_v || (stl::is_same_v && stl::is_lvalue_reference_v)) { return meta_any{ctx, stl::in_place_type, value}; } else if constexpr(stl::is_same_v) { return meta_any{ctx, stl::in_place_type}; } else { return meta_any{ctx, stl::forward(value)}; } } /** * @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, if any. */ template [[nodiscard]] meta_any meta_dispatch(Type &&value) { return meta_dispatch(locator::value_or(), stl::forward(value)); } /*! @cond ENTT_INTERNAL */ namespace internal { template [[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) { if constexpr(stl::is_void_v(candidate), args...))>) { stl::invoke(stl::forward(candidate), args...); return meta_any{ctx, stl::in_place_type}; } else { return meta_dispatch(ctx, stl::invoke(stl::forward(candidate), args...)); } } template [[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, stl::index_sequence) { using descriptor = meta_function_helper_t>; // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) if constexpr(stl::is_invocable_v, const Type &, type_list_element_t...>) { if(const auto *const clazz = instance.try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { return meta_invoke_with_args(instance.context(), stl::forward(candidate), *clazz, (args + Index)->cast>()...); } } else if constexpr(stl::is_invocable_v, Type &, type_list_element_t...>) { if(auto *const clazz = instance.try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { return meta_invoke_with_args(instance.context(), stl::forward(candidate), *clazz, (args + Index)->cast>()...); } } else { if(((args + Index)->allow_cast>() && ...)) { return meta_invoke_with_args(instance.context(), stl::forward(candidate), (args + Index)->cast>()...); } } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) return meta_any{meta_ctx_arg, instance.context()}; } template [[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, stl::index_sequence) { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) if(((args + Index)->allow_cast() && ...)) { return meta_any{ctx, stl::in_place_type, (args + Index)->cast()...}; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) return meta_any{meta_ctx_arg, ctx}; } } // namespace internal /*! @endcond */ /** * @brief Returns the meta type of the i-th element of a list of arguments. * @tparam Type Type list of the actual types of arguments. * @param ctx The context from which to search for meta types. * @param index The index of the element for which to return the meta type. * @return The meta type of the i-th element of the list of arguments. */ template [[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept { const auto &context = internal::meta_context::from(ctx); return {ctx, internal::meta_arg_node(context, Type{}, index)}; } /** * @brief Returns the meta type of the i-th element of a list of arguments. * @tparam Type Type list of the actual types of arguments. * @param index The index of the element for which to return the meta type. * @return The meta type of the i-th element of the list of arguments. */ template [[nodiscard]] meta_type meta_arg(const stl::size_t index) noexcept { return meta_arg(locator::value_or(), index); } /** * @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 args Parameters 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 *const args) { if constexpr(stl::is_member_function_pointer_v || stl::is_function_v>>) { return static_cast(internal::meta_invoke(*instance.operator->(), Data, args, stl::make_index_sequence::args_type::size>{})); } else if constexpr(stl::is_member_object_pointer_v) { using data_type = stl::remove_reference_t::return_type>; if constexpr(!stl::is_array_v && !stl::is_const_v) { if(auto *const clazz = instance->try_cast(); clazz && args->allow_cast()) { stl::invoke(Data, *clazz) = args->cast(); return true; } } return false; } else if constexpr(stl::is_pointer_v) { using data_type = stl::remove_reference_t; if constexpr(!stl::is_array_v && !stl::is_const_v) { if(args->allow_cast()) { *Data = args->cast(); return true; } } return false; } else { return false; } } /** * @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(meta_handle instance, meta_any value) { return meta_setter(*instance.operator->(), &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. * @param args Parameters to use to set the variable. * @return A meta any containing the value of the underlying variable. */ template [[nodiscard]] meta_any meta_getter(meta_handle instance, [[maybe_unused]] meta_any *const args) { if constexpr(stl::is_member_function_pointer_v || stl::is_function_v>>) { return internal::meta_invoke(*instance.operator->(), Data, args, stl::make_index_sequence::args_type::size>{}); } else if constexpr(stl::is_member_object_pointer_v) { if constexpr(!stl::is_array_v>>) { if(auto *clazz = instance->try_cast(); clazz) { return meta_dispatch(instance->context(), stl::invoke(Data, *clazz)); } else if(auto *fallback = instance->try_cast(); fallback) { return meta_dispatch(instance->context(), stl::invoke(Data, *fallback)); } } return meta_any{meta_ctx_arg, instance->context()}; } else if constexpr(stl::is_pointer_v) { if constexpr(stl::is_array_v>) { return meta_any{meta_ctx_arg, instance->context()}; } else { return meta_dispatch(instance->context(), *Data); } } else { return meta_dispatch(instance->context(), Data); } } /** * @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(meta_handle instance) { return meta_getter(*instance.operator->(), nullptr); } /** * @brief Tries to _invoke_ an object given a list of erased parameters. * @tparam Type Reflected type to which the object to _invoke_ is associated. * @tparam Policy Optional policy (no policy set by default). * @tparam Candidate The type of the actual object to _invoke_. * @param instance An opaque instance of the underlying type, if required. * @param candidate The actual object to _invoke_. * @param args Parameters to use to _invoke_ the object. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) { return internal::meta_invoke(*instance.operator->(), stl::forward(candidate), args, stl::make_index_sequence>::args_type::size>{}); } /** * @brief Tries to invoke a function given a list of erased parameters. * @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). * @param instance An opaque instance of the underlying type, if required. * @param args Parameters to use to invoke the function. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) { return internal::meta_invoke(*instance.operator->(), Candidate, args, stl::make_index_sequence>::args_type::size>{}); } /** * @brief Tries to construct an instance given a list of erased parameters. * * @warning * The context provided is used only for the return type.
* It's up to the caller to bind the arguments to the right context(s). * * @tparam Type Actual type of the instance to construct. * @tparam Args Types of arguments expected. * @param ctx The context from which to search for meta types. * @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(const meta_ctx &ctx, meta_any *const args) { return internal::meta_construct(ctx, args, stl::index_sequence_for{}); } /** * @brief Tries to construct an instance given a list of erased parameters. * @tparam Type Actual type of the instance to construct. * @tparam Args Types of arguments expected. * @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) { return meta_construct(locator::value_or(), args); } /** * @brief Tries to construct an instance given a list of erased parameters. * * @warning * The context provided is used only for the return type.
* It's up to the caller to bind the arguments to the right context(s). * * @tparam Type Reflected type to which the object to _invoke_ is associated. * @tparam Policy Optional policy (no policy set by default). * @tparam Candidate The type of the actual object to _invoke_. * @param ctx The context from which to search for meta types. * @param candidate The actual object to _invoke_. * @param args Parameters to use to _invoke_ the object. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) { if constexpr(meta_function_helper_t::is_static || stl::is_class_v>) { meta_any placeholder{meta_ctx_arg, ctx}; return internal::meta_invoke(placeholder, stl::forward(candidate), args, stl::make_index_sequence>::args_type::size>{}); } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) return internal::meta_invoke(*args, stl::forward(candidate), args + 1u, stl::make_index_sequence>::args_type::size>{}); } } /** * @brief Tries to construct an instance given a list of erased parameters. * @tparam Type Reflected type to which the object to _invoke_ is associated. * @tparam Policy Optional policy (no policy set by default). * @tparam Candidate The type of the actual object to _invoke_. * @param candidate The actual object to _invoke_. * @param args Parameters to use to _invoke_ the object. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) { return meta_construct(locator::value_or(), stl::forward(candidate), args); } /** * @brief Tries to construct an instance given a list of erased parameters. * * @warning * The context provided is used only for the return type.
* It's up to the caller to bind the arguments to the right context(s). * * @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). * @param ctx The context from which to search for meta types. * @param args Parameters to use to invoke the function. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) { return meta_construct(ctx, Candidate, args); } /** * @brief Tries to construct an instance given a list of erased parameters. * @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). * @param args Parameters to use to invoke the function. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(meta_any *const args) { return meta_construct(locator::value_or(), args); } } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { class basic_meta_factory { using invoke_type = stl::remove_pointer_t; enum class mode { type, data, func }; [[nodiscard]] auto *find_member_or_assert() { auto *member = find_member(parent->details->data, bucket); ENTT_ASSERT(member != nullptr, "Cannot find member"); return member; } [[nodiscard]] auto *find_overload_or_assert() { ENTT_ASSERT(invoke != nullptr, "Invoke function not available"); auto *overload = find_overload(find_member(parent->details->func, bucket), invoke); ENTT_ASSERT(overload != nullptr, "Cannot find overload"); return overload; } bool unique_alias(const id_type alias) const noexcept { return (ctx->bucket.find(alias) == ctx->bucket.cend()) && (stl::find_if(ctx->bucket.cbegin(), ctx->bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }) == ctx->bucket.cend()); } protected: void type(const id_type alias, const char *name) noexcept { state = mode::type; ENTT_ASSERT((parent->alias == alias) || unique_alias(alias), "Duplicate identifier"); parent->alias = alias; parent->name = name; } template void insert_or_assign(Type node) { state = mode::type; if constexpr(stl::is_same_v) { auto *member = find_member(parent->details->base, node.id); member ? (*member = node) : parent->details->base.emplace_back(node); } else if constexpr(stl::is_same_v) { auto *member = find_member(parent->details->conv, node.id); member ? (*member = node) : parent->details->conv.emplace_back(node); } else { static_assert(stl::is_same_v, "Unexpected type"); auto *member = find_member(parent->details->ctor, node.id); member ? (*member = node) : parent->details->ctor.emplace_back(node); } } void data(meta_data_node node) { state = mode::data; bucket = node.id; if(auto *member = find_member(parent->details->data, node.id); member == nullptr) { parent->details->data.emplace_back(stl::move(node)); } else if(member->set != node.set || member->get != node.get) { *member = stl::move(node); } } void func(meta_func_node node) { state = mode::func; bucket = node.id; invoke = node.invoke; if(auto *member = find_member(parent->details->func, node.id); member == nullptr) { parent->details->func.emplace_back(stl::move(node)); } else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) { while(member->next != nullptr) { member = member->next.get(); } member->next = stl::make_unique(stl::move(node)); } } void traits(const meta_traits value, const bool unset) { const auto set_or_unset_on = [=](auto &node) { node.traits = (unset ? (node.traits & ~value) : (node.traits | value)); }; switch(state) { case mode::type: set_or_unset_on(*parent); break; case mode::data: set_or_unset_on(*find_member_or_assert()); break; case mode::func: set_or_unset_on(*find_overload_or_assert()); break; } } void custom(meta_custom_node node) { switch(state) { case mode::type: parent->custom = stl::move(node); break; case mode::data: find_member_or_assert()->custom = stl::move(node); break; case mode::func: find_overload_or_assert()->custom = stl::move(node); break; } } public: basic_meta_factory(meta_ctx &area, meta_type_node node, const id_type id) : ctx{&meta_context::from(area)}, bucket{}, state{mode::type} { if(const auto it = ctx->bucket.find(id); it == ctx->bucket.cend()) { ENTT_ASSERT(unique_alias(id), "Duplicate identifier"); parent = ctx->bucket.emplace(id, stl::make_unique(stl::move(node))).first->second.get(); parent->details = stl::make_unique(); parent->alias = id; } else { parent = it->second.get(); } } private: meta_context *ctx{}; invoke_type *invoke{}; meta_type_node *parent{}; id_type bucket{}; mode state{}; }; } // namespace internal /*! @endcond */ /** * @brief Meta factory to be used for reflection purposes. * @tparam Type Type for which the factory was created. */ template class meta_factory: private internal::basic_meta_factory { using base_type = internal::basic_meta_factory; public: /*! @brief Type of object for which this factory builds a meta type. */ using element_type = Type; /*! @brief Default constructor. */ meta_factory() noexcept : meta_factory{locator::value_or()} {} /** * @brief Context aware constructor. * @param area The context into which to construct meta types. */ meta_factory(meta_ctx &area) noexcept : base_type{area, internal::setup_node_for(), type_hash::value()} {} /** * @brief Constructs an unconstrained type assigned to a given identifier. * @param id A custom unique identifier. */ meta_factory(const id_type id) noexcept : meta_factory{locator::value_or(), id} {} /** * @brief Context aware constructor. * @param id A custom unique identifier. * @param area The context into which to construct meta types. */ meta_factory(meta_ctx &area, const id_type id) noexcept : base_type{area, internal::setup_node_for(), id} {} /** * @brief Assigns a custom unique identifier to a meta type. * @param name A custom unique identifier as a **string literal**. * @return A meta factory for the given type. */ meta_factory type(const char *name) noexcept { return type(hashed_string::value(name), name); } /** * @brief Assigns a custom unique identifier to a meta type. * @param alias A custom unique identifier. * @param name An optional name for the type as a **string literal**. * @return A meta factory for the given type. */ meta_factory type(const id_type alias, const char *name = nullptr) noexcept { base_type::type(alias, name); return *this; } /** * @brief Assigns a meta base to a meta type. * * A reflected base class must be a real base class of the reflected type. * * @tparam Base Type of the base class to assign to the meta type. * @return A meta factory for the parent type. */ template requires stl::derived_from meta_factory base() noexcept { if constexpr(!stl::same_as) { auto *const op = +[](const void *instance) noexcept { return static_cast(static_cast(static_cast(instance))); }; base_type::insert_or_assign( internal::meta_base_node{ type_id().hash(), &internal::resolve, op}); } return *this; } /** * @brief Assigns a meta conversion function to a meta type. * * Conversion functions can be either free functions or member * functions.
* In case of free functions, they must accept a const reference to an * instance of the parent type as an argument. In case of member functions, * they should have no arguments at all. * * @tparam Candidate The actual function to use for the conversion. * @return A meta factory for the parent type. */ template auto conv() noexcept { using conv_type = stl::remove_cvref_t>; auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, stl::invoke(Candidate, *static_cast(instance))); }; base_type::insert_or_assign( internal::meta_conv_node{ type_id().hash(), op}); return *this; } /** * @brief Assigns a meta conversion function to a meta type. * * The given type must be such that an instance of the reflected type can be * converted to it. * * @tparam To Type of the conversion function to assign to the meta type. * @return A meta factory for the parent type. */ template meta_factory conv() noexcept { using conv_type = stl::remove_cvref_t; auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast(*static_cast(instance))); }; base_type::insert_or_assign( internal::meta_conv_node{ type_id().hash(), op}); return *this; } /** * @brief Assigns a meta constructor to a meta type. * * Both member functions and free function can be assigned to meta types in * the role of constructors. All that is required is that they return an * instance of the underlying type.
* From a client's point of view, nothing changes if a constructor of a meta * type is a built-in one or not. * * @tparam Candidate The actual function to use as a constructor. * @tparam Policy Optional policy (no policy set by default). * @return A meta factory for the parent type. */ template meta_factory ctor() noexcept { using descriptor = meta_function_helper_t; static_assert(Policy::template value, "Invalid return type for the given policy"); static_assert(stl::is_same_v, element_type>, "The function doesn't return an object of the required type"); base_type::insert_or_assign( internal::meta_ctor_node{ type_id().hash(), descriptor::args_type::size, &meta_arg, &meta_construct}); return *this; } /** * @brief Assigns a meta constructor to a meta type. * * A meta constructor is uniquely identified by the types of its arguments * and is such that there exists an actual constructor of the underlying * type that can be invoked with parameters whose types are those given. * * @tparam Args Types of arguments to use to construct an instance. * @return A meta factory for the parent type. */ template meta_factory ctor() noexcept { // default constructor is already implicitly generated, no need for redundancy if constexpr(sizeof...(Args) != 0u) { using descriptor = meta_function_helper_t; base_type::insert_or_assign( internal::meta_ctor_node{ type_id().hash(), descriptor::args_type::size, &meta_arg, &meta_construct}); } return *this; } /** * @brief Assigns a meta data to a meta type. * @tparam Data The actual variable to attach to the meta type. * @tparam Policy Optional policy (no policy set by default). * @param name A custom unique identifier as a **string literal**. * @return A meta factory for the given type. */ template meta_factory data(const char *name) noexcept { return data(hashed_string::value(name), name); } /** * @brief Assigns a meta data to a meta type. * * Both data members and static and global variables, as well as constants * of any kind, can be assigned to a meta type.
* From a client's point of view, all the variables associated with the * reflected object will appear as if they were part of the type itself. * * @tparam Data The actual variable to attach to the meta type. * @tparam Policy Optional policy (no policy set by default). * @param id Unique identifier. * @param name An optional name for the meta data as a **string literal**. * @return A meta factory for the parent type. */ template meta_factory data(const id_type id, const char *name = nullptr) noexcept { if constexpr(stl::is_member_object_pointer_v) { using data_type = stl::invoke_result_t; static_assert(Policy::template value, "Invalid return type for the given policy"); base_type::data( internal::meta_data_node{ id, name, /* this is never static */ stl::is_const_v> ? internal::meta_traits::is_const : internal::meta_traits::is_none, 1u, 0u, &meta_arg>>, &meta_arg>, &internal::resolve>, &meta_setter, &meta_getter}); } else { using data_type = stl::remove_pointer_t; if constexpr(stl::is_pointer_v) { static_assert(Policy::template value, "Invalid return type for the given policy"); } else { static_assert(Policy::template value, "Invalid return type for the given policy"); } base_type::data( internal::meta_data_node{ id, name, ((!stl::is_pointer_v || stl::is_const_v) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static, 1u, 0u, &meta_arg>>, &meta_arg>, &internal::resolve>, &meta_setter, &meta_getter}); } return *this; } /** * @brief Assigns a meta data to a meta type by means of its setter and * getter. * @tparam Setter The actual function to use as a setter. * @tparam Getter The actual function to use as a getter. * @tparam Policy Optional policy (no policy set by default). * @param name A custom unique identifier as a **string literal**. * @return A meta factory for the given type. */ template meta_factory data(const char *name) noexcept { return data(hashed_string::value(name), name); } /** * @brief Assigns a meta data to a meta type by means of its setter and * getter. * * Setters and getters can be either free functions, member functions or a * mix of them.
* In case of free functions, setters and getters must accept a reference to * an instance of the parent type as their first argument. A setter has then * an extra argument of a type convertible to that of the parameter to * set.
* In case of member functions, getters have no arguments at all, while * setters has an argument of a type convertible to that of the parameter to * set. * * @tparam Setter The actual function to use as a setter. * @tparam Getter The actual function to use as a getter. * @tparam Policy Optional policy (no policy set by default). * @param id Unique identifier. * @param name An optional name for the meta data as a **string literal**. * @return A meta factory for the parent type. */ template meta_factory data(const id_type id, const char *name = nullptr) noexcept { using getter = meta_function_helper_t; static_assert(Policy::template value, "Invalid return type for the given policy"); if constexpr(stl::is_same_v) { base_type::data( internal::meta_data_node{ id, name, /* this is never static */ internal::meta_traits::is_const, 0u, getter::args_type::size, &meta_arg>, &meta_arg, &internal::resolve>, &meta_setter, &meta_getter}); } else { using setter = meta_function_helper_t; base_type::data( internal::meta_data_node{ id, name, /* this is never static nor const */ internal::meta_traits::is_none, setter::args_type::size, getter::args_type::size, &meta_arg, &meta_arg, &internal::resolve>, &meta_setter, &meta_getter}); } return *this; } /** * @brief Assigns a meta function to a meta type. * @tparam Candidate The actual function to attach to the meta function. * @tparam Policy Optional policy (no policy set by default). * @param name A custom unique identifier as a **string literal**. * @return A meta factory for the given type. */ template meta_factory func(const char *name) noexcept { return func(hashed_string::value(name), name); } /** * @brief Assigns a meta function to a meta type. * * Both member functions and free functions can be assigned to a meta * type.
* From a client's point of view, all the functions associated with the * reflected object will appear as if they were part of the type itself. * * @tparam Candidate The actual function to attach to the meta type. * @tparam Policy Optional policy (no policy set by default). * @param id Unique identifier. * @param name An optional name for the function as a **string literal**. * @return A meta factory for the parent type. */ template meta_factory func(const id_type id, const char *name = nullptr) noexcept { using descriptor = meta_function_helper_t; static_assert(Policy::template value, "Invalid return type for the given policy"); base_type::func( internal::meta_func_node{ id, name, (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none), descriptor::args_type::size, &internal::resolve, void, stl::remove_cvref_t>>, &meta_arg, &meta_invoke}); return *this; } /** * @brief Sets traits on the last created meta object. * * The assigned value must be an enum and intended as a bitmask. * * @tparam Value Type of the traits value. * @param value Traits value. * @param unset True to unset the given traits, false otherwise. * @return A meta factory for the parent type. */ template meta_factory traits(const Value value, const bool unset = false) { static_assert(stl::is_enum_v, "Invalid enum type"); base_type::traits(internal::user_to_meta_traits(value), unset); return *this; } /** * @brief Sets user defined data that will never be used by the library. * @tparam Value Type of user defined data to store. * @tparam Args Types of arguments to use to construct the user data. * @param args Parameters to use to initialize the user data. * @return A meta factory for the parent type. */ template meta_factory custom(Args &&...args) { base_type::custom(internal::meta_custom_node{type_id().hash(), stl::make_shared(stl::forward(args)...)}); return *this; } }; /** * @brief Resets a type and all its parts. * * Resets a type and all its data members, member functions and properties, as * well as its constructors, destructors and conversion functions if any.
* Base classes aren't reset but the link between the two types is removed. * * The type is also removed from the set of searchable types. * * @param alias Unique identifier. * @param ctx The context from which to reset meta types. */ inline void meta_reset(meta_ctx &ctx, const id_type alias) noexcept { auto &bucket = internal::meta_context::from(ctx).bucket; // fast path for unsearchable and overloaded types if(bucket.erase(alias) == 0u) { if(const auto it = stl::find_if(bucket.cbegin(), bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }); it != bucket.cend()) { bucket.erase(it); } } } /** * @brief Resets a type and all its parts. * * Resets a type and all its data members, member functions and properties, as * well as its constructors, destructors and conversion functions if any.
* Base classes aren't reset but the link between the two types is removed. * * The type is also removed from the set of searchable types. * * @param alias Unique identifier. */ inline void meta_reset(const id_type alias) noexcept { meta_reset(locator::value_or(), alias); } /** * @brief Resets a type and all its parts. * * @sa meta_reset * * @tparam Type Type to reset. * @param ctx The context from which to reset meta types. */ template void meta_reset(meta_ctx &ctx) noexcept { internal::meta_context::from(ctx).bucket.erase(type_id().hash()); } /** * @brief Resets a type and all its parts. * * @sa meta_reset * * @tparam Type Type to reset. */ template void meta_reset() noexcept { meta_reset(locator::value_or()); } /** * @brief Resets all meta types. * * @sa meta_reset * * @param ctx The context from which to reset meta types. */ inline void meta_reset(meta_ctx &ctx) noexcept { internal::meta_context::from(ctx).bucket.clear(); } /** * @brief Resets all meta types. * * @sa meta_reset */ inline void meta_reset() noexcept { meta_reset(locator::value_or()); } } // namespace entt #endif // #include "meta/meta.hpp" #ifndef ENTT_META_META_HPP #define ENTT_META_META_HPP // #include "../config/config.h" // #include "../core/any.hpp" // #include "../core/concepts.hpp" // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" // #include "../core/type_info.hpp" // #include "../core/type_traits.hpp" // #include "../core/utility.hpp" // #include "../locator/locator.hpp" // #include "../stl/array.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" // #include "../stl/string_view.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "adl_pointer.hpp" // #include "context.hpp" // #include "fwd.hpp" // #include "node.hpp" // #include "range.hpp" // #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct basic_meta_object { [[nodiscard]] auto &node_or_assert() const noexcept { ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); return *node; } const Type *node{}; const meta_ctx *ctx{&locator::value_or()}; }; } // namespace internal /*! @endcond */ /*! @brief Proxy object for sequence containers. */ class meta_sequence_container { class meta_iterator; public: /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Meta iterator type. */ using iterator = meta_iterator; /*! @brief Default constructor. */ meta_sequence_container() = default; /** * @brief Context aware constructor. * @tparam Type Type of container to wrap. * @param area The context from which to search for meta types. * @param instance The container to wrap. */ template meta_sequence_container(const meta_ctx &area, Type &instance) noexcept : ctx{&area}, data{&instance}, value_type_node{&internal::resolve}, const_reference_node{&internal::resolve>}, size_fn{meta_sequence_container_traits>::size}, clear_fn{meta_sequence_container_traits>::clear}, reserve_fn{meta_sequence_container_traits>::reserve}, resize_fn{meta_sequence_container_traits>::resize}, begin_end_fn{meta_sequence_container_traits>::iter}, insert_fn{meta_sequence_container_traits>::insert}, erase_fn{meta_sequence_container_traits>::erase}, const_only{stl::is_const_v} {} [[nodiscard]] inline meta_type value_type() const noexcept; [[nodiscard]] inline size_type size() const noexcept; inline bool resize(size_type); inline bool clear(); inline bool reserve(size_type); [[nodiscard]] inline iterator begin(); [[nodiscard]] inline iterator end(); inline iterator insert(const iterator &, meta_any); inline iterator erase(const iterator &); [[nodiscard]] inline meta_any operator[](size_type); [[nodiscard]] inline explicit operator bool() const noexcept; private: const meta_ctx *ctx{}; const void *data{}; const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; const internal::meta_type_node &(*const_reference_node)(const internal::meta_context &){}; size_type (*size_fn)(const void *){}; bool (*clear_fn)(void *){}; bool (*reserve_fn)(void *, const size_type){}; bool (*resize_fn)(void *, const size_type){}; iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){}; iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){}; bool const_only{}; }; /*! @brief Proxy object for associative containers. */ class meta_associative_container { class meta_iterator; public: /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Meta iterator type. */ using iterator = meta_iterator; /*! @brief Default constructor. */ meta_associative_container() = default; /** * @brief Context aware constructor. * @tparam Type Type of container to wrap. * @param area The context from which to search for meta types. * @param instance The container to wrap. */ template meta_associative_container(const meta_ctx &area, Type &instance) noexcept : ctx{&area}, data{&instance}, key_type_node{&internal::resolve}, value_type_node{&internal::resolve}, size_fn{&meta_associative_container_traits>::size}, clear_fn{&meta_associative_container_traits>::clear}, reserve_fn{&meta_associative_container_traits>::reserve}, begin_end_fn{&meta_associative_container_traits>::iter}, insert_fn{&meta_associative_container_traits>::insert}, erase_fn{&meta_associative_container_traits>::erase}, find_fn{&meta_associative_container_traits>::find}, const_only{stl::is_const_v} { if constexpr(!meta_associative_container_traits>::key_only) { mapped_type_node = &internal::resolve; } } [[nodiscard]] inline meta_type key_type() const noexcept; [[nodiscard]] inline meta_type mapped_type() const noexcept; [[nodiscard]] inline meta_type value_type() const noexcept; [[nodiscard]] inline size_type size() const noexcept; inline bool clear(); inline bool reserve(size_type); [[nodiscard]] inline iterator begin(); [[nodiscard]] inline iterator end(); inline bool insert(meta_any, meta_any); inline size_type erase(meta_any); [[nodiscard]] inline iterator find(meta_any); [[nodiscard]] inline explicit operator bool() const noexcept; private: const meta_ctx *ctx{}; const void *data{}; const internal::meta_type_node &(*key_type_node)(const internal::meta_context &){}; const internal::meta_type_node &(*mapped_type_node)(const internal::meta_context &){}; const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; size_type (*size_fn)(const void *){}; bool (*clear_fn)(void *){}; bool (*reserve_fn)(void *, const size_type){}; iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; bool (*insert_fn)(void *, const void *, const void *){}; size_type (*erase_fn)(void *, const void *){}; iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){}; bool const_only{}; }; /*! @brief Opaque wrapper for values of any type. */ class meta_any { using vtable_type = void(const internal::meta_traits, const meta_any &, void *); template static void basic_vtable(const internal::meta_traits req, const meta_any &value, [[maybe_unused]] void *other) { if(req == internal::meta_traits::is_none) { value.node = &internal::resolve(internal::meta_context::from(*value.ctx)); } if constexpr(is_meta_pointer_like_v) { if(req == internal::meta_traits::is_pointer) { if constexpr(!stl::is_void_v::element_type>>) { if constexpr(stl::is_constructible_v) { if(const auto &pointer_like = any_cast(value.storage); pointer_like) { static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(pointer_like)); } } else { static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(any_cast(value.storage))); } } } } else if constexpr(requires(Type elem) { *elem; }) { if(req == internal::meta_traits::is_pointer) { if constexpr(stl::is_class_v) { if(const auto &elem = any_cast(value.storage); elem) { return (value.storage.policy() == any_policy::cref) ? static_cast(other)->emplace(*elem) : static_cast(other)->emplace(elem))>(*const_cast(elem)); } } else if constexpr(!stl::is_array_v && !stl::is_void_v>>) { if(auto *pointer = any_cast(value.storage); pointer) { static_cast(other)->emplace>>, Type, stl::remove_pointer_t &>>(*pointer); } } } } else if constexpr(is_complete_v> || is_complete_v>) { if(constexpr auto flag = (is_complete_v> ? internal::meta_traits::is_sequence_container : internal::meta_traits::is_associative_container); req == flag) { using container_type = stl::conditional_t>, meta_sequence_container, meta_associative_container>; *static_cast(other) = (value.storage.policy() == any_policy::cref) ? container_type{*value.ctx, any_cast(value.storage)} : container_type{*value.ctx, any_cast(const_cast(value).storage)}; } } } [[nodiscard]] const auto &fetch_node() const { if(node == nullptr) { ENTT_ASSERT(*this, "Invalid vtable function"); vtable(internal::meta_traits::is_none, *this, nullptr); } ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); return *node; } meta_any(const meta_any &other, any elem) : storage{stl::move(elem)}, ctx{other.ctx}, node{other.node}, vtable{other.vtable} {} public: /*! Default constructor. */ meta_any() = default; /** * @brief Context aware constructor. * @param area The context from which to search for meta types. */ meta_any(meta_ctx_arg_t, const meta_ctx &area) : ctx{&area} {} /** * @brief Constructs a wrapper by directly initializing the new object. * @tparam Type Type of object to use to initialize the wrapper. * @param args Parameters to use to construct the instance. */ template explicit meta_any(stl::in_place_type_t, auto &&...args) : meta_any{locator::value_or(), stl::in_place_type, stl::forward(args)...} {} /** * @brief Constructs a wrapper by directly initializing the new object. * @tparam Type Type of object to use to initialize the wrapper. * @param area The context from which to search for meta types. * @param args Parameters to use to construct the instance. */ template explicit meta_any(const meta_ctx &area, stl::in_place_type_t, auto &&...args) : storage{stl::in_place_type, stl::forward(args)...}, ctx{&area}, vtable{&basic_vtable>} {} /** * @brief Constructs a wrapper taking ownership of the passed object. * @param value A pointer to an object to take ownership of. */ explicit meta_any(stl::in_place_t, auto *value) : meta_any{locator::value_or(), stl::in_place, value} {} /** * @brief Constructs a wrapper taking ownership of the passed object. * @param area The context from which to search for meta types. * @param value A pointer to an object to take ownership of. */ explicit meta_any(const meta_ctx &area, stl::in_place_t, auto *value) : storage{stl::in_place, value}, ctx{&area}, vtable{storage ? &basic_vtable>> : nullptr} { } /** * @brief Constructs a wrapper from a given value. * @param value An instance of an object to use to initialize the wrapper. */ meta_any(auto &&value) requires (!stl::same_as, meta_any>) : meta_any{locator::value_or(), stl::forward(value)} {} /** * @brief Constructs a wrapper from a given value. * @param area The context from which to search for meta types. * @param value An instance of an object to use to initialize the wrapper. */ meta_any(const meta_ctx &area, auto &&value) requires (!stl::same_as, meta_any>) : meta_any{area, stl::in_place_type>, stl::forward(value)} {} /** * @brief Context aware copy constructor. * @param area The context from which to search for meta types. * @param other The instance to copy from. */ meta_any(const meta_ctx &area, const meta_any &other) : storage{other.storage}, ctx{&area}, node{(ctx == other.ctx) ? other.node : nullptr}, vtable{other.vtable} {} /** * @brief Context aware move constructor. * @param area The context from which to search for meta types. * @param other The instance to move from. */ meta_any(const meta_ctx &area, meta_any &&other) : storage{stl::move(other.storage)}, ctx{&area}, node{(ctx == other.ctx) ? stl::exchange(other.node, nullptr) : nullptr}, vtable{stl::exchange(other.vtable, nullptr)} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ meta_any(const meta_any &other) : storage{other.storage}, ctx{other.ctx}, node{(other.storage && !storage) ? nullptr : other.node}, vtable{(other.storage && !storage) ? nullptr : other.vtable} { } /** * @brief Move constructor. * @param other The instance to move from. */ meta_any(meta_any &&other) noexcept : storage{stl::move(other.storage)}, ctx{other.ctx}, node{stl::exchange(other.node, nullptr)}, vtable{stl::exchange(other.vtable, nullptr)} {} /*! @brief Default destructor. */ ~meta_any() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This meta any object. */ meta_any &operator=(const meta_any &other) { if(this != &other) { ctx = other.ctx; storage = other.storage; node = (other.storage && !storage) ? nullptr : other.node; vtable = (other.storage && !storage) ? nullptr : other.vtable; } return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This meta any object. */ meta_any &operator=(meta_any &&other) noexcept { storage = stl::move(other.storage); ctx = other.ctx; node = stl::exchange(other.node, nullptr); vtable = stl::exchange(other.vtable, nullptr); return *this; } /** * @brief Value assignment operator. * @param value An instance of an object to use to initialize the wrapper. * @return This meta any object. */ meta_any &operator=(auto &&value) requires (!stl::same_as, meta_any>) { emplace>(stl::forward(value)); return *this; } /** * @brief Returns the meta type associated with the contained instance. * @return The meta type associated with the contained instance. */ [[nodiscard]] inline meta_type type() const noexcept; /** * @brief Sets a meta type for the contained instance. * @param alias The meta to use with the contained instance. */ inline void type(const meta_type &alias) noexcept; /** * @brief Invokes the underlying function, if possible. * @param id Unique identifier. * @param args Parameters to use to invoke the function. * @return A wrapper containing the returned value, if any. */ meta_any invoke(id_type id, auto &&...args) const; /*! @copydoc invoke */ meta_any invoke(id_type id, auto &&...args); /** * @brief Sets the value of a given variable. * @param id Unique identifier. * @param args Parameters to use to set the underlying variable. * @return True in case of success, false otherwise. */ bool set(id_type id, auto &&...args); /** * @brief Gets the value of a given variable. * @param id Unique identifier. * @param args Parameters to use to set the underlying variable, if any. * @return A wrapper containing the value of the underlying variable. */ [[nodiscard]] meta_any get(id_type id, auto &&...args) const; /*! @copydoc get */ [[nodiscard]] meta_any get(id_type id, auto &&...args); /** * @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 { const auto *elem = any_cast(&storage); return ((elem != nullptr) || !*this) ? elem : static_cast(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), type_hash>::value(), storage.data())); } /*! @copydoc try_cast */ template [[nodiscard]] Type *try_cast() { return ((storage.policy() == any_policy::cref) && !stl::is_const_v) ? nullptr : const_cast(stl::as_const(*this).try_cast>()); } /** * @brief Tries to cast an instance to a given type. * @tparam Type Type to which to cast the instance. * @return A reference to the contained instance. */ template [[nodiscard]] stl::remove_const_t cast() const { auto *const instance = try_cast>(); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(*instance); } /*! @copydoc cast */ template [[nodiscard]] stl::remove_const_t 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. * @param type Meta type to which the cast is requested. * @return A valid meta object if convertible, an invalid one otherwise. */ [[nodiscard]] meta_any allow_cast(const meta_type &type) const; /** * @brief Converts an object in such a way that a given cast becomes viable. * @param type Meta type to which the cast is requested. * @return True if convertible, false otherwise. */ [[nodiscard]] bool allow_cast(const meta_type &type); /** * @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 object if convertible, an invalid one otherwise. */ template [[nodiscard]] meta_any allow_cast() const { if constexpr(!stl::is_reference_v || stl::is_const_v>) { if(storage.has_value>()) { return as_ref(); } else if(*this) { if constexpr(stl::is_arithmetic_v> || stl::is_enum_v>) { if(const auto &from = fetch_node(); from.conversion_helper) { return meta_any{*ctx, static_cast(from.conversion_helper(nullptr, storage.data()))}; } } if(const auto &from = fetch_node(); from.details != nullptr) { if(const auto *elem = internal::find_member(from.details->conv, entt::type_hash>::value()); elem != nullptr) { return elem->conv(*ctx, storage.data()); } for(auto &&curr: from.details->base) { if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == entt::type_hash>::value()) { return other; } else if(auto from_base = stl::as_const(other).template allow_cast(); from_base) { return from_base; } } } } } return meta_any{meta_ctx_arg, *ctx}; } /** * @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 convertible, false otherwise. */ template [[nodiscard]] bool allow_cast() { if constexpr(stl::is_reference_v && !stl::is_const_v>) { return allow_cast &>() && (storage.policy() != any_policy::cref); } else { if(storage.has_value>()) { return true; } else if(auto other = stl::as_const(*this).allow_cast>(); other) { if(other.storage.owner()) { stl::swap(*this, other); } return true; } return false; } } /*! @copydoc any::emplace */ template void emplace(auto &&...args) { storage.emplace(stl::forward(args)...); auto *prev = stl::exchange(vtable, &basic_vtable>); node = (prev == vtable) ? node : nullptr; } /*! @copydoc any::assign */ bool assign(const meta_any &other); /*! @copydoc any::assign */ bool assign(meta_any &&other); /*! @copydoc any::reset */ void reset() { storage.reset(); node = nullptr; vtable = nullptr; } /** * @brief Returns a sequence container proxy. * @return A sequence container proxy for the underlying object. */ [[nodiscard]] meta_sequence_container as_sequence_container() noexcept { meta_sequence_container proxy{}; if(*this) { vtable(internal::meta_traits::is_sequence_container, *this, &proxy); } return proxy; } /*! @copydoc as_sequence_container */ [[nodiscard]] meta_sequence_container as_sequence_container() const noexcept { meta_sequence_container proxy{}; if(*this) { vtable(internal::meta_traits::is_sequence_container, 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() noexcept { meta_associative_container proxy{}; if(*this) { vtable(internal::meta_traits::is_associative_container, *this, &proxy); } return proxy; } /*! @copydoc as_associative_container */ [[nodiscard]] meta_associative_container as_associative_container() const noexcept { meta_associative_container proxy{}; if(*this) { vtable(internal::meta_traits::is_associative_container, 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*() noexcept { meta_any ret{meta_ctx_arg, *ctx}; if(*this) { vtable(internal::meta_traits::is_pointer, *this, &ret); } return ret; } /*! @copydoc operator* */ [[nodiscard]] meta_any operator*() const noexcept { meta_any ret{meta_ctx_arg, *ctx}; if(*this) { vtable(internal::meta_traits::is_pointer, as_ref(), &ret); } return ret; } /*! @copydoc any::operator bool */ [[nodiscard]] explicit operator bool() const noexcept { return !(vtable == nullptr); } /*! @copydoc any::operator== */ [[nodiscard]] bool operator==(const meta_any &other) const noexcept { return (ctx == other.ctx) && (!*this == !other) && (storage == other.storage); } /*! @copydoc any::as_ref */ [[nodiscard]] meta_any as_ref() noexcept { return meta_any{*this, storage.as_ref()}; } /*! @copydoc any::as_ref */ [[nodiscard]] meta_any as_ref() const noexcept { return meta_any{*this, storage.as_ref()}; } /** * @brief Returns the underlying storage. * @return The underlyig storage. */ [[nodiscard]] const any &base() const noexcept { return storage; } /** * @brief Returns the underlying meta context. * @return The underlying meta context. */ [[nodiscard]] const meta_ctx &context() const noexcept { return *ctx; } private: any storage{}; const meta_ctx *ctx{&locator::value_or()}; mutable const internal::meta_type_node *node{}; vtable_type *vtable{}; }; /** * @brief Forwards its argument and avoids copies for lvalue references. * @param value Parameter to use to construct the instance. * @param ctx The context from which to search for meta types. * @return A properly initialized and not necessarily owning wrapper. */ [[nodiscard]] meta_any forward_as_meta(const meta_ctx &ctx, auto &&value) { return meta_any{ctx, stl::in_place_type, stl::forward(value)}; } /** * @brief Forwards its argument and avoids copies for lvalue references. * @param value Parameter to use to construct the instance. * @return A properly initialized and not necessarily owning wrapper. */ [[nodiscard]] meta_any forward_as_meta(auto &&value) { return forward_as_meta(locator::value_or(), stl::forward(value)); } /*! @brief Opaque pointers to instances of any type. */ class meta_handle { meta_handle(int, auto &value, auto &&...args) requires stl::same_as, meta_any> : any{stl::forward(args)..., value.as_ref()} {} meta_handle(char, auto &value, auto &&...args) : any{stl::forward(args)..., stl::in_place_type, value} {} public: /*! Default constructor. */ meta_handle() = default; /** * @brief Creates a handle that points to an unmanaged object. * @param ctx The context from which to search for meta types. * @param value An instance of an object to use to initialize the handle. */ meta_handle(const meta_ctx &ctx, auto &value) requires (!stl::same_as, meta_handle>) : meta_handle{0, value, ctx} {} /** * @brief Creates a handle that points to an unmanaged object. * @param value An instance of an object to use to initialize the handle. */ meta_handle(auto &value) requires (!stl::same_as, meta_handle>) : meta_handle{0, value} {} /** * @brief Context aware move constructor. * @param area The context from which to search for meta types. * @param other The instance to move from. */ meta_handle(const meta_ctx &area, meta_handle &&other) : any{area, stl::move(other.any)} {} /*! @brief Default copy constructor, deleted on purpose. */ meta_handle(const meta_handle &) = delete; /*! @brief Default move constructor. */ meta_handle(meta_handle &&) = default; /*! @brief Default destructor. */ ~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 Returns false if a handle is invalid, true otherwise. * @return False if the handle is invalid, true otherwise. */ [[nodiscard]] explicit operator bool() const 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; } private: meta_any any{}; }; /*! @brief Opaque wrapper for user defined data of any type. */ struct meta_custom { /*! @brief Default constructor. */ meta_custom() noexcept = default; /** * @brief Basic constructor for meta objects. * @param curr The underlying node with which to construct the instance. */ meta_custom(const internal::meta_custom_node &curr) noexcept : node{&curr} {} /** * @brief Generic conversion operator. * @tparam Type Type to which conversion is requested. */ template [[nodiscard]] operator Type *() const noexcept { return ((node != nullptr) && (type_hash>::value() == node->id)) ? static_cast(node->value.get()) : nullptr; } /** * @brief Generic conversion operator. * @tparam Type Type to which conversion is requested. */ template [[nodiscard]] operator Type &() const noexcept { ENTT_ASSERT(static_cast(*this) != nullptr, "Invalid type"); return *static_cast(node->value.get()); } private: const internal::meta_custom_node *node{}; }; /** * @brief Common opaque wrapper for meta objects. * @tparam Type Underlying meta node type. */ template struct meta_object: protected internal::basic_meta_object { /*! @brief Underlying meta node type. */ using node_type = Type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Default constructor. */ meta_object() noexcept = default; /** * @brief Context aware constructor for meta objects. * @param area The context from which to search for meta types. * @param curr The underlying node with which to construct the instance. */ meta_object(const meta_ctx &area, const node_type &curr) noexcept : internal::basic_meta_object{&curr, &area} { } /** * @brief Returns true if an object is valid, false otherwise. * @return True if the object is valid, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return (this->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_object &other) const noexcept { return (this->ctx == other.ctx) && (this->node == other.node); } }; /*! @brief Opaque wrapper for data members. */ struct meta_data: meta_object { using meta_object::meta_object; /** * @brief Returns the name assigned to a data member, if any. * @return The name assigned to the data member, if any. */ [[nodiscard]] stl::string_view name() const noexcept { return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; } /** * @brief Returns the number of arguments of a data member's setter. * @return The number of arguments accepted by the data member's setter. */ [[nodiscard]] size_type set_arity() const noexcept { return node_or_assert().set_arity; } /** * @brief Returns the number of arguments of a data member's getter. * @return The number of arguments accepted by the data member's getter. */ [[nodiscard]] size_type get_arity() const noexcept { return node_or_assert().get_arity; } /** * @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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::is_static); } /*! @copydoc meta_any::type */ [[nodiscard]] inline meta_type type() const noexcept; /** * @brief Sets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to set the underlying variable. * @return True in case of success, false otherwise. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) bool set(Instance &&instance, auto &&...args) const { return (sizeof...(args) >= set_arity()) && node_or_assert().set(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); } /** * @brief Gets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to get the underlying variable, if any. * @return A wrapper containing the value of the underlying variable. */ template [[nodiscard]] meta_any get(Instance &&instance, auto &&...args) const { return (sizeof...(args) >= get_arity()) ? node_or_assert().get(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; } /** * @brief Returns the type of the i-th argument of a data member's setter. * @param index Index of the argument of which to return the type. * @return The type of the i-th argument of a data member's setter. */ [[nodiscard]] inline meta_type set_arg(size_type index) const noexcept; /** * @brief Returns the type of the i-th argument of a data member's getter. * @param index Index of the argument of which to return the type. * @return The type of the i-th argument of a data member's getter. */ [[nodiscard]] inline meta_type get_arg(size_type index) const noexcept; /** * @brief Returns all meta traits for a given meta object. * @tparam Type The type to convert the meta traits to. * @return The registered meta traits, if any. */ template [[nodiscard]] Type traits() const noexcept { return internal::meta_to_user_traits(node_or_assert().traits); } /** * @brief Returns user defined data for a given meta object. * @return User defined arbitrary data. */ [[nodiscard]] meta_custom custom() const noexcept { return {node_or_assert().custom}; } }; /*! @brief Opaque wrapper for member functions. */ struct meta_func: meta_object { using meta_object::meta_object; /** * @brief Returns the name assigned to a member function, if any. * @return The name assigned to the member function, if any. */ [[nodiscard]] stl::string_view name() const noexcept { return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; } /** * @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 noexcept { return node_or_assert().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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::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 noexcept { return !!(node_or_assert().traits & internal::meta_traits::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 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 noexcept; /** * @brief Invokes the underlying function, if possible. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to invoke the function. * @return A wrapper containing the returned value, if any. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) meta_any invoke(Instance &&instance, auto &&...args) const { return (sizeof...(args) == arity()) ? node_or_assert().invoke(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; } /*! @copydoc meta_data::traits */ template [[nodiscard]] Type traits() const noexcept { return internal::meta_to_user_traits(node_or_assert().traits); } /*! @copydoc meta_data::custom */ [[nodiscard]] meta_custom custom() const noexcept { return {node_or_assert().custom}; } /** * @brief Returns the next overload of a given function, if any. * @return The next overload of the given function, if any. */ [[nodiscard]] meta_func next() const { return (node_or_assert().next != nullptr) ? meta_func{*ctx, *node_or_assert().next} : meta_func{}; } }; /*! @brief Opaque wrapper for base types. */ struct meta_base: meta_object { using meta_object::meta_object; /*! @copydoc meta_any::type */ [[nodiscard]] inline meta_type type() const noexcept; }; /*! @brief Opaque wrapper for types. */ class meta_type { friend class meta_any; [[nodiscard]] const auto &fetch_node() const { return (node == nullptr) ? internal::resolve(internal::meta_context::from(*ctx)) : *node; } [[nodiscard]] auto lookup(meta_handle *const args, const auto sz, [[maybe_unused]] bool constness, auto next) const { decltype(next()) candidate = nullptr; size_type same{}; bool ambiguous{}; for(auto curr = next(); curr; curr = next()) { if constexpr(stl::is_same_v, internal::meta_func_node>) { if(constness && !(curr->traits & internal::meta_traits::is_const)) { continue; } } if(curr->arity == sz) { size_type match{}; size_type pos{}; // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) for(; pos < sz; ++pos) { const auto other = curr->arg(*ctx, pos); const auto type = args[pos]->type(); if(const auto &info = other.info(); info == type.info()) { ++match; } else if(!(type.fetch_node().conversion_helper && other.fetch_node().conversion_helper) && !(type.fetch_node().details && (internal::find_member(type.fetch_node().details->base, info.hash()) || internal::find_member(type.fetch_node().details->conv, info.hash())))) { break; } } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) if(pos == sz) { if(!candidate || match > same) { candidate = curr; same = match; ambiguous = false; } else if(match == same) { if constexpr(stl::is_same_v, internal::meta_func_node>) { if(!!(curr->traits & internal::meta_traits::is_const) != !!(candidate->traits & internal::meta_traits::is_const)) { candidate = !!(candidate->traits & internal::meta_traits::is_const) ? curr : candidate; ambiguous = false; continue; } } ambiguous = true; } } } } return ambiguous ? nullptr : candidate; } public: /*! @brief Unsigned integer type. */ using size_type = internal::meta_type_node::size_type; /*! @brief Default constructor. */ meta_type() noexcept = default; /** * @brief Context aware constructor for meta objects. * @param area The context from which to search for meta types. * @param curr The underlying node with which to construct the instance. */ meta_type(const meta_ctx &area, const internal::meta_type_node &curr) noexcept : node{&curr}, ctx{&area} {} /** * @brief Returns the type info object of the underlying type. * @return The type info object of the underlying type. */ [[nodiscard]] const type_info &info() const noexcept { return *fetch_node().info; } /** * @brief Returns the alias assigned to a type. * @return The alias assigned to the type. */ [[nodiscard]] id_type alias() const noexcept { return fetch_node().alias; } /** * @brief Returns the name assigned to a type, if any. * @return The name assigned to the type, if any. */ [[nodiscard]] stl::string_view name() const noexcept { return (fetch_node().name == nullptr) ? stl::string_view{} : stl::string_view{fetch_node().name}; } /** * @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 noexcept { return fetch_node().size_of; } /** * @brief Checks whether a type refers to an arithmetic type or not. * @return True if the underlying type is an arithmetic type, false * otherwise. */ [[nodiscard]] bool is_arithmetic() const noexcept { return !!(fetch_node().traits & internal::meta_traits::is_arithmetic); } /** * @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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_integral); } /** * @brief Checks whether a type refers to a signed type or not. * @return True if the underlying type is a signed type, false otherwise. */ [[nodiscard]] bool is_signed() const noexcept { return !!(fetch_node().traits & internal::meta_traits::is_signed); } /** * @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 noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_enum); } /** * @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 noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_pointer); } /** * @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 noexcept { return meta_type{*ctx, fetch_node().remove_pointer(internal::meta_context::from(*ctx))}; } /** * @brief Checks whether a type is a pointer-like type or not. * @return True if the underlying type is pointer-like, false otherwise. */ [[nodiscard]] bool is_pointer_like() const noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::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 noexcept { return !!(fetch_node().traits & internal::meta_traits::is_associative_container); } /** * @brief Checks whether a type refers to a template specialization or not. * @return True if the type is a template specialization, false otherwise. */ [[nodiscard]] bool is_template_specialization() const noexcept { return (fetch_node().templ.arity != 0u); } /** * @brief Returns the number of template arguments. * @return The number of template arguments. */ [[nodiscard]] size_type template_arity() const noexcept { return fetch_node().templ.arity; } /** * @brief Returns a tag for the class template of the underlying type. * @return The tag for the class template of the underlying type. */ [[nodiscard]] meta_type template_type() const noexcept { return (fetch_node().templ.resolve != nullptr) ? meta_type{*ctx, fetch_node().templ.resolve(internal::meta_context::from(*ctx))} : 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]] meta_type template_arg(const size_type index) const noexcept { return index < template_arity() ? meta_type{*ctx, fetch_node().templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{}; } /** * @brief Checks if a type supports direct casting to another type. * @param other The meta type to test for. * @return True if direct casting is allowed, false otherwise. */ [[nodiscard]] bool can_cast(const meta_type &other) const noexcept { // casting this is UB in all cases but we aren't going to use the resulting pointer, so... return other && ((*this == other) || (internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), other.fetch_node().info->hash(), this) != nullptr)); } /** * @brief Checks whether a type supports conversion to another type. * @param other The meta type to test for. * @return True if the conversion is allowed, false otherwise. */ [[nodiscard]] bool can_convert(const meta_type &other) const noexcept { if(const auto &to = other.info().hash(); (info().hash() == to) || ((fetch_node().conversion_helper != nullptr) && (other.is_arithmetic() || other.is_enum()))) { return true; } else if(const auto &from = fetch_node(); from.details) { if(const auto *elem = internal::find_member(from.details->conv, to); elem != nullptr) { return true; } for(auto &&curr: from.details->base) { if(curr.id == to || meta_type{*ctx, curr.type(internal::meta_context::from(*ctx))}.can_convert(other)) { return true; } } } return false; } /** * @brief Returns a range to visit registered top-level base meta types. * @return An iterable range to visit registered top-level base meta types. */ [[nodiscard]] meta_range base() const noexcept { using range_type = meta_range; return fetch_node().details ? range_type{{*ctx, fetch_node().details->base.cbegin()}, {*ctx, fetch_node().details->base.cend()}} : range_type{}; } /** * @brief Returns a range to visit registered top-level meta data. * @return An iterable range to visit registered top-level meta data. */ [[nodiscard]] meta_range data() const noexcept { using range_type = meta_range; return fetch_node().details ? range_type{{*ctx, fetch_node().details->data.cbegin()}, {*ctx, fetch_node().details->data.cend()}} : range_type{}; } /** * @brief Lookup utility for meta data (bases are also visited). * @param id Unique identifier. * @param recursive True for a search in the base classes, false otherwise. * @return The registered meta data for the given identifier, if any. */ [[nodiscard]] meta_data data(const id_type id, const bool recursive = true) const { const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); return (elem != nullptr) ? meta_data{*ctx, *elem} : meta_data{}; } /** * @brief Returns a range to visit registered top-level functions. * @return An iterable range to visit registered top-level functions. */ [[nodiscard]] meta_range func() const noexcept { using return_type = meta_range; return fetch_node().details ? return_type{{*ctx, fetch_node().details->func.cbegin()}, {*ctx, fetch_node().details->func.cend()}} : return_type{}; } /** * @brief Lookup utility for meta functions (bases are also visited). * @param id Unique identifier. * @param recursive True for a search in the base classes, false otherwise. * @return The registered meta function for the given identifier, if any. */ [[nodiscard]] meta_func func(const id_type id, const bool recursive = true) const { const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); return (elem != nullptr) ? meta_func{*ctx, *elem} : meta_func{}; } /** * @copybrief construct * @param args Parameters to use to construct the instance. * @return A wrapper containing the new instance, if any. */ [[nodiscard]] meta_any construct(auto &&...args) const { if(const auto &ref = fetch_node(); ref.details) { if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), false, [first = ref.details->ctor.cbegin(), last = ref.details->ctor.cend()]() mutable { return first == last ? nullptr : &*(first++); }); candidate) { return candidate->invoke(*ctx, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); } } if(const auto &ref = fetch_node(); (sizeof...(args) == 0u) && (ref.default_constructor != nullptr)) { return ref.default_constructor(*ctx); } return meta_any{meta_ctx_arg, *ctx}; } /** * @brief Wraps an opaque element of the underlying type. * @param elem A valid pointer to an element of the underlying type. * @param transfer_ownership True to transfer ownership, false otherwise. * @return A wrapper that references the given instance. */ [[nodiscard]] meta_any from_void(void *elem, bool transfer_ownership = false) const { return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{meta_ctx_arg, *ctx}; } /** * @brief Wraps an opaque element of the underlying type. * @param elem A valid pointer to an element of the underlying type. * @return A wrapper that references the given instance. */ [[nodiscard]] meta_any from_void(const void *elem) const { return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, nullptr, elem) : meta_any{meta_ctx_arg, *ctx}; } /** * @copybrief invoke * @param id Unique identifier. * @tparam Instance Type of instance to operate on. * @param instance An instance that fits the underlying type. * @param args Parameters to use to invoke the function. * @return A wrapper containing the returned value, if any. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) meta_any invoke(const id_type id, Instance &&instance, auto &&...args) const { meta_handle wrapped{*ctx, stl::forward(instance)}; if(const auto &ref = fetch_node(); ref.details) { if(auto *elem = internal::find_member(ref.details->func, id); elem != nullptr) { if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), (wrapped->base().policy() == any_policy::cref), [curr = elem]() mutable { return (curr != nullptr) ? stl::exchange(curr, curr->next.get()) : nullptr; }); candidate) { return candidate->invoke(stl::move(wrapped), stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); } } } for(auto &&curr: base()) { if(auto elem = curr.second.type().invoke(id, *wrapped.operator->(), stl::forward(args)...); elem) { return elem; } } return meta_any{meta_ctx_arg, *ctx}; } /** * @brief Sets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param id Unique identifier. * @param instance An instance that fits the underlying type. * @param args Parameters to use to set the underlying variable. * @return True in case of success, false otherwise. */ template // NOLINTNEXTLINE(modernize-use-nodiscard) bool set(const id_type id, Instance &&instance, auto &&...args) const { const auto candidate = data(id); return candidate && candidate.set(stl::forward(instance), stl::forward(args)...); } /** * @brief Gets the value of a given variable. * @tparam Instance Type of instance to operate on. * @param id Unique identifier. * @param instance An instance that fits the underlying type. * @param args Parameters to use to set the underlying variable, if any. * @return A wrapper containing the value of the underlying variable. */ template [[nodiscard]] meta_any get(const id_type id, Instance &&instance, auto &&...args) const { const auto candidate = data(id); return candidate ? candidate.get(stl::forward(instance), stl::forward(args)...) : meta_any{meta_ctx_arg, *ctx}; } /*! @copydoc meta_data::traits */ template [[nodiscard]] Type traits() const noexcept { return internal::meta_to_user_traits(fetch_node().traits); } /*! @copydoc meta_data::custom */ [[nodiscard]] meta_custom custom() const noexcept { return fetch_node().custom; } /*! @copydoc meta_data::operator bool */ [[nodiscard]] explicit operator bool() const noexcept { return (node != nullptr); } /*! @copydoc meta_data::operator== */ [[nodiscard]] bool operator==(const meta_type &other) const noexcept { return (ctx == other.ctx) && (fetch_node().alias == other.fetch_node().alias); } private: mutable const internal::meta_type_node *node{}; const meta_ctx *ctx{&locator::value_or()}; }; [[nodiscard]] inline meta_type meta_any::type() const noexcept { return *this ? meta_type{*ctx, fetch_node()} : meta_type{}; } inline void meta_any::type(const meta_type &alias) noexcept { ENTT_ASSERT(storage.info() == alias.info(), "Unexpected type"); node = alias.node; ctx = alias.ctx; } // NOLINTNEXTLINE(modernize-use-nodiscard) meta_any meta_any::invoke(const id_type id, auto &&...args) const { return type().invoke(id, *this, stl::forward(args)...); } meta_any meta_any::invoke(const id_type id, auto &&...args) { return type().invoke(id, *this, stl::forward(args)...); } bool meta_any::set(const id_type id, auto &&...args) { return type().set(id, *this, stl::forward(args)...); } [[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) const { return type().get(id, *this, stl::forward(args)...); } [[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) { return type().get(id, *this, stl::forward(args)...); } [[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { if(storage.has_value(type.info())) { return as_ref(); } else if(*this) { if(const auto &from = fetch_node(); (from.conversion_helper != nullptr) && (type.is_arithmetic() || type.is_enum())) { auto other = type.construct(); const auto value = from.conversion_helper(nullptr, storage.data()); other.fetch_node().conversion_helper(other.storage.data(), &value); return other; } if(const auto &from = fetch_node(); from.details) { if(const auto *elem = internal::find_member(from.details->conv, type.info().hash()); elem != nullptr) { return elem->conv(*ctx, storage.data()); } for(auto &&curr: from.details->base) { if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == type.info().hash()) { return other; } else if(auto from_base = stl::as_const(other).allow_cast(type); from_base) { return from_base; } } } } return meta_any{meta_ctx_arg, *ctx}; } [[nodiscard]] inline bool meta_any::allow_cast(const meta_type &type) { if(storage.has_value(type.info())) { return true; } else if(auto other = stl::as_const(*this).allow_cast(type); other) { if(other.storage.owner()) { stl::swap(*this, other); } return true; } return false; } inline bool meta_any::assign(const meta_any &other) { if(!storage.assign(other.storage)) { auto value = other.allow_cast(type()); return storage.assign(value.storage); } return true; } inline bool meta_any::assign(meta_any &&other) { return storage.assign(stl::move(other.storage)) || storage.assign(stl::as_const(other).allow_cast(type()).storage); } [[nodiscard]] inline meta_type meta_data::type() const noexcept { return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; } [[nodiscard]] inline meta_type meta_data::set_arg(const size_type index) const noexcept { return index < set_arity() ? node_or_assert().set_arg(*ctx, index) : meta_type{}; } [[nodiscard]] inline meta_type meta_data::get_arg(const size_type index) const noexcept { return index < get_arity() ? node_or_assert().get_arg(*ctx, index) : meta_type{}; } [[nodiscard]] inline meta_type meta_func::ret() const noexcept { return meta_type{*ctx, node_or_assert().ret(internal::meta_context::from(*ctx))}; } [[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept { return index < arity() ? node_or_assert().arg(*ctx, index) : meta_type{}; } [[nodiscard]] inline meta_type meta_base::type() const noexcept { return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; } /*! @cond ENTT_INTERNAL */ class meta_sequence_container::meta_iterator final { using vtable_type = void(const void *, const stl::ptrdiff_t, meta_any *); template static void basic_vtable(const void *value, const stl::ptrdiff_t offset, meta_any *other) { const auto &it = *static_cast(value); other ? other->emplace(*it) : stl::advance(const_cast(it), offset); } public: using value_type = meta_any; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::bidirectional_iterator_tag; meta_iterator() = default; meta_iterator(const meta_ctx &area, stl::bidirectional_iterator auto iter) noexcept : ctx{&area}, vtable{&basic_vtable}, handle{iter} {} meta_iterator &operator++() noexcept { return vtable(handle.data(), 1, nullptr), *this; } meta_iterator operator++(int value) noexcept { meta_iterator orig = *this; vtable(handle.data(), ++value, nullptr); return orig; } meta_iterator &operator--() noexcept { return vtable(handle.data(), -1, nullptr), *this; } meta_iterator operator--(int value) noexcept { meta_iterator orig = *this; vtable(handle.data(), --value, nullptr); return orig; } [[nodiscard]] reference operator*() const { reference other{meta_ctx_arg, *ctx}; vtable(handle.data(), 0, &other); return other; } [[nodiscard]] pointer operator->() const { return operator*(); } [[nodiscard]] explicit operator bool() const noexcept { return (vtable != nullptr); } [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { return handle == other.handle; } [[nodiscard]] const any &base() const noexcept { return handle; } private: const meta_ctx *ctx{}; vtable_type *vtable{}; any handle{}; }; class meta_associative_container::meta_iterator final { using vtable_type = void(const void *, stl::pair *); template static void basic_vtable(const void *value, stl::pair *other) { if(const auto &it = *static_cast(value); other) { if constexpr(KeyOnly) { other->first.emplace(*it); } else { other->first.emplacefirst))>(it->first); other->second.emplacesecond))>(it->second); } } else { ++const_cast(it); } } public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; meta_iterator() = default; template meta_iterator(const meta_ctx &area, stl::bool_constant, stl::forward_iterator auto iter) noexcept : ctx{&area}, vtable{&basic_vtable}, handle{iter} {} meta_iterator &operator++() noexcept { return vtable(handle.data(), nullptr), *this; } meta_iterator operator++(int) noexcept { meta_iterator orig = *this; vtable(handle.data(), nullptr); return orig; } [[nodiscard]] reference operator*() const { reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}}; vtable(handle.data(), &other); return other; } [[nodiscard]] pointer operator->() const { return operator*(); } [[nodiscard]] explicit operator bool() const noexcept { return (vtable != nullptr); } [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { return handle == other.handle; } private: const meta_ctx *ctx{}; vtable_type *vtable{}; any handle{}; }; /*! @endcond */ /** * @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 noexcept { return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /** * @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 noexcept { return size_fn(data); } /** * @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(const size_type sz) { return !const_only && resize_fn(const_cast(data), sz); } /** * @brief Clears the content of a container. * @return True in case of success, false otherwise. */ inline bool meta_sequence_container::clear() { return !const_only && clear_fn(const_cast(data)); } /** * @brief Reserves storage for at least the given number of elements. * @param sz The new capacity of the container. * @return True in case of success, false otherwise. */ inline bool meta_sequence_container::reserve(const size_type sz) { return !const_only && reserve_fn(const_cast(data), sz); } /** * @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_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); } /** * @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 begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); } /** * @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 possibly invalid iterator to the inserted element. */ inline meta_sequence_container::iterator meta_sequence_container::insert(const iterator &it, meta_any value) { // this abomination is necessary because only on macos value_type and const_reference are different types for stl::vector if(const auto &vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) { const bool is_value_type = (value.type().info() == *vtype.info); return insert_fn(*ctx, const_cast(data), is_value_type ? value.base().data() : nullptr, is_value_type ? nullptr : value.base().data(), it); } return iterator{}; } /** * @brief Removes a given element from a container. * @param it Iterator to the element to remove. * @return A possibly invalid iterator following the last removed element. */ inline meta_sequence_container::iterator meta_sequence_container::erase(const iterator &it) { return const_only ? iterator{} : erase_fn(*ctx, const_cast(data), it); } /** * @brief Returns a reference to the element at a given location of a container. * @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[](const size_type pos) { auto it = begin(); it.operator++(static_cast(pos) - 1); return *it; } /** * @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 noexcept { return (data != nullptr); } /** * @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 noexcept { return (key_type_node != nullptr) ? meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /** * @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 noexcept { return (mapped_type_node != nullptr) ? meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /*! @copydoc meta_sequence_container::value_type */ [[nodiscard]] inline meta_type meta_associative_container::value_type() const noexcept { return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } /*! @copydoc meta_sequence_container::size */ [[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept { return size_fn(data); } /*! @copydoc meta_sequence_container::clear */ inline bool meta_associative_container::clear() { return !const_only && clear_fn(const_cast(data)); } /*! @copydoc meta_sequence_container::reserve */ inline bool meta_associative_container::reserve(const size_type sz) { return !const_only && reserve_fn(const_cast(data), sz); } /*! @copydoc meta_sequence_container::begin */ [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() { return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); } /*! @copydoc meta_sequence_container::end */ [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() { return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); } /** * @brief Inserts a key-only or key/value element into a container. * @param key The key of the element to insert. * @param value The value of the element to insert, if needed. * @return A bool denoting whether the insertion took place. */ inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) && ((mapped_type_node == nullptr) || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))})) && insert_fn(const_cast(data), key.base().data(), value.base().data()); } /** * @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 meta_associative_container::size_type meta_associative_container::erase(meta_any key) { return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast(data), key.base().data()) : 0u; } /** * @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 key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast(data), data, key.base().data()) : iterator{}; } /** * @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 noexcept { return (data != nullptr); } } // namespace entt #endif // #include "meta/node.hpp" #ifndef ENTT_META_NODE_HPP #define ENTT_META_NODE_HPP // #include "../config/config.h" // #include "../core/bit.hpp" // #include "../core/concepts.hpp" // #include "../core/enum.hpp" // #include "../core/fwd.hpp" // #include "../core/type_info.hpp" // #include "../core/type_traits.hpp" // #include "../core/utility.hpp" // #include "../stl/array.hpp" // #include "../stl/bit.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "context.hpp" // #include "fwd.hpp" // #include "type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { enum class meta_traits : stl::uint32_t { is_none = 0x0000, is_const = 0x0001, is_static = 0x0002, is_arithmetic = 0x0004, is_integral = 0x0008, is_signed = 0x0010, is_array = 0x0020, is_enum = 0x0040, is_class = 0x0080, is_pointer = 0x0100, is_pointer_like = 0x0200, is_sequence_container = 0x0400, is_associative_container = 0x0800, _user_defined_traits = 0xFFFF, _entt_enum_as_bitmask = 0xFFFF }; template requires stl::is_enum_v [[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept { constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); return Type{static_cast>(static_cast>(traits) >> shift)}; } template requires stl::is_enum_v [[nodiscard]] auto user_to_meta_traits(const Type value) noexcept { constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); const auto traits = static_cast>(static_cast>(value)); ENTT_ASSERT(traits < ((~static_cast>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits"); return meta_traits{traits << shift}; } struct meta_type_node; struct meta_custom_node { id_type id{}; stl::shared_ptr value{}; }; struct meta_base_node { id_type id{}; const meta_type_node &(*type)(const meta_context &) noexcept {}; const void *(*cast)(const void *) noexcept {}; }; struct meta_conv_node { id_type id{}; meta_any (*conv)(const meta_ctx &, const void *){}; }; struct meta_ctor_node { using size_type = stl::size_t; id_type id{}; size_type arity{0u}; meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; meta_any (*invoke)(const meta_ctx &, meta_any *const){}; }; struct meta_data_node { using size_type = stl::size_t; id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type set_arity{0u}; size_type get_arity{0u}; meta_type (*set_arg)(const meta_ctx &, const size_type) noexcept {}; meta_type (*get_arg)(const meta_ctx &, const size_type) noexcept {}; const meta_type_node &(*type)(const meta_context &) noexcept {}; bool (*set)(meta_handle, meta_any *const){}; meta_any (*get)(meta_handle, meta_any *const){}; meta_custom_node custom{}; }; struct meta_func_node { using size_type = stl::size_t; id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type arity{0u}; const meta_type_node &(*ret)(const meta_context &) noexcept {}; meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; meta_any (*invoke)(meta_handle, meta_any *const){}; stl::unique_ptr next; meta_custom_node custom{}; }; struct meta_template_node { using size_type = stl::size_t; size_type arity{0u}; const meta_type_node &(*resolve)(const meta_context &) noexcept {}; const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {}; }; struct meta_type_descriptor { stl::vector ctor{}; stl::vector base{}; stl::vector conv{}; stl::vector data{}; stl::vector func{}; }; struct meta_type_node { using size_type = stl::size_t; const type_info *info{}; id_type alias{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type size_of{0u}; const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {}; meta_any (*default_constructor)(const meta_ctx &){}; double (*conversion_helper)(void *, const void *){}; meta_any (*from_void)(const meta_ctx &, void *, const void *){}; meta_template_node templ{}; meta_custom_node custom{}; stl::unique_ptr details{}; }; template [[nodiscard]] auto *find_member(Type &from, const Value value) { for(auto &&elem: from) { if(elem.id == value) { return &elem; } } return static_cast(nullptr); } [[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t *const ref) { while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); } return curr; } template [[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) { using value_type = stl::remove_reference_t*Member))>::value_type; if(node.details) { if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) { return member; } if(recursive) { for(auto &&curr: node.details->base) { if(auto *elem = look_for(context, curr.type(context), id, recursive); elem) { return elem; } } } } return static_cast(nullptr); } template const meta_type_node &resolve(const meta_context &) noexcept; template [[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list, const stl::size_t index) noexcept { using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept; constexpr stl::array list{&resolve>...}; ENTT_ASSERT(index < sizeof...(Args), "Out of bounds"); return list[index](context); } [[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept { if(from.details) { for(auto &&curr: from.details->base) { if(const void *other = curr.cast(instance); curr.id == to) { return other; } else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) { return elem; } } } return nullptr; } template auto setup_node_for() noexcept { meta_type_node node{ &type_id(), type_id().hash(), nullptr, (stl::is_arithmetic_v ? meta_traits::is_arithmetic : meta_traits::is_none) | (stl::is_integral_v ? meta_traits::is_integral : meta_traits::is_none) | (stl::is_signed_v ? meta_traits::is_signed : meta_traits::is_none) | (stl::is_array_v ? meta_traits::is_array : meta_traits::is_none) | (stl::is_enum_v ? meta_traits::is_enum : meta_traits::is_none) | (stl::is_class_v ? meta_traits::is_class : meta_traits::is_none) | (stl::is_pointer_v ? meta_traits::is_pointer : meta_traits::is_none) | (is_meta_pointer_like_v ? meta_traits::is_pointer_like : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_sequence_container : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_associative_container : meta_traits::is_none), size_of_v, &resolve>>}; if constexpr(stl::is_default_constructible_v) { node.default_constructor = +[](const meta_ctx &ctx) { return meta_any{ctx, stl::in_place_type}; }; } if constexpr(stl::is_arithmetic_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { return lhs ? static_cast(*static_cast(lhs) = static_cast(*static_cast(rhs))) : static_cast(*static_cast(rhs)); }; } else if constexpr(stl::is_enum_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { return lhs ? static_cast(*static_cast(lhs) = static_cast(static_cast>(*static_cast(rhs)))) : static_cast(*static_cast(rhs)); }; } if constexpr(!stl::is_void_v && !stl::is_function_v) { node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) { if(elem && celem) { // ownership construction request return meta_any{ctx, stl::in_place, static_cast *>(elem)}; } if(elem) { // non-const reference construction request return meta_any{ctx, stl::in_place_type &>, *static_cast *>(elem)}; } // const reference construction request return meta_any{ctx, stl::in_place_type &>, *static_cast *>(celem)}; }; } if constexpr(is_complete_v>) { node.templ = meta_template_node{ meta_template_traits::args_type::size, &resolve::class_type>, +[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits::args_type{}, index); }}; } return node; } template [[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept { static const meta_type_node node = setup_node_for(); const auto it = context.bucket.find(node.info->hash()); return (it == context.bucket.cend()) ? node : *it->second; } } // namespace internal /*! @endcond */ } // namespace entt #endif // #include "meta/pointer.hpp" // IWYU pragma: always_keep #ifndef ENTT_META_POINTER_HPP #define ENTT_META_POINTER_HPP // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "type_traits.hpp" namespace entt { /** * @brief Makes `stl::shared_ptr`s of any type pointer-like types for the meta * system. * @tparam Type Element type. */ template struct is_meta_pointer_like> : stl::true_type {}; /** * @brief Makes `stl::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> : stl::true_type {}; /** * @brief Specialization for self-proclaimed meta pointer like types. * @tparam Type Element type. */ template requires requires { typename Type::is_meta_pointer_like; } struct is_meta_pointer_like : stl::true_type {}; } // namespace entt #endif // #include "meta/policy.hpp" #ifndef ENTT_META_POLICY_HPP #define ENTT_META_POLICY_HPP // #include "../stl/type_traits.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct meta_policy {}; } // namespace internal /*! @endcond */ /*! @brief Empty class type used to request the _as-is_ policy. */ struct as_value_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = true; /*! @endcond */ }; /*! @brief Empty class type used to request the _as void_ policy. */ struct as_void_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = true; /*! @endcond */ }; /*! @brief Empty class type used to request the _as ref_ policy. */ struct as_ref_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = stl::is_reference_v && !stl::is_const_v>; /*! @endcond */ }; /*! @brief Empty class type used to request the _as cref_ policy. */ struct as_cref_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = stl::is_reference_v; /*! @endcond */ }; /*! @brief Empty class type used to request the _as auto_ policy. */ struct as_is_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ template static constexpr bool value = true; /*! @endcond */ }; /** * @brief Provides the member constant `value` equal to true if a type also is a * meta policy, false otherwise. * @tparam Type Type to check. */ template struct is_meta_policy : stl::bool_constant> {}; /** * @brief Helper variable template. * @tparam Type Type to check. */ template inline constexpr bool is_meta_policy_v = is_meta_policy::value; /** * @brief Specifies whether a type is a meta policy. * @tparam Type Type to check. */ template concept meta_policy = is_meta_policy_v; } // namespace entt #endif // #include "meta/range.hpp" #ifndef ENTT_META_RANGE_HPP #define ENTT_META_RANGE_HPP #include // #include "../core/fwd.hpp" // #include "../core/iterator.hpp" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/utility.hpp" // #include "context.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct meta_base_node; template struct meta_range_iterator final { using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr meta_range_iterator() noexcept : it{}, ctx{} {} constexpr meta_range_iterator(const meta_ctx &area, const It iter) noexcept : it{iter}, ctx{&area} {} constexpr meta_range_iterator &operator++() noexcept { return ++it, *this; } constexpr meta_range_iterator operator++(int) noexcept { const meta_range_iterator orig = *this; return ++(*this), orig; } constexpr meta_range_iterator &operator--() noexcept { return --it, *this; } constexpr meta_range_iterator operator--(int) noexcept { const meta_range_iterator orig = *this; return operator--(), orig; } constexpr meta_range_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr meta_range_iterator operator+(const difference_type value) const noexcept { meta_range_iterator copy = *this; return (copy += value); } constexpr meta_range_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr meta_range_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { if constexpr(stl::is_same_v) { return {it[value].first, Type{*ctx, *it[value].second}}; } else { return {it[value].id, Type{*ctx, it[value]}}; } } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } [[nodiscard]] constexpr stl::ptrdiff_t operator-(const meta_range_iterator &other) const noexcept { return it - other.it; } [[nodiscard]] constexpr bool operator==(const meta_range_iterator &other) const noexcept { return it == other.it; } [[nodiscard]] constexpr auto operator<=>(const meta_range_iterator &other) const noexcept { return it <=> other.it; } private: It it; const meta_ctx *ctx; }; } // namespace internal /*! @endcond */ /** * @brief Iterable range to use to iterate all types of meta objects. * @tparam Type Type of meta objects returned. * @tparam It Type of forward iterator. */ template using meta_range = iterable_adaptor>; } // namespace entt #endif // #include "meta/resolve.hpp" #ifndef ENTT_META_RESOLVE_HPP #define ENTT_META_RESOLVE_HPP // #include "../core/type_info.hpp" // #include "../locator/locator.hpp" // #include "../stl/type_traits.hpp" // #include "context.hpp" // #include "meta.hpp" // #include "node.hpp" // #include "range.hpp" namespace entt { /** * @brief Returns the meta type associated with a given type. * @tparam Type Type to use to search for a meta type. * @param ctx The context from which to search for meta types. * @return The meta type associated with the given type, if any. */ template [[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept { const auto &context = internal::meta_context::from(ctx); return {ctx, internal::resolve>(context)}; } /** * @brief Returns the meta type associated with a given type. * @tparam Type Type to use to search for a meta type. * @return The meta type associated with the given type, if any. */ template [[nodiscard]] meta_type resolve() noexcept { return resolve(locator::value_or()); } /** * @brief Returns a range to use to visit all meta types. * @param ctx The context from which to search for meta types. * @return An iterable range to use to visit all meta types. */ [[nodiscard]] inline meta_range resolve(const meta_ctx &ctx) noexcept { const auto &context = internal::meta_context::from(ctx); return {{ctx, context.bucket.cbegin()}, {ctx, context.bucket.cend()}}; } /** * @brief Returns a range to use to visit all meta types. * @return An iterable range to use to visit all meta types. */ [[nodiscard]] inline meta_range resolve() noexcept { return resolve(locator::value_or()); } /** * @brief Returns the meta type associated with a given identifier, if any. * @param ctx The context from which to search for meta types. * @param alias Unique identifier. * @return The meta type associated with the given identifier, if any. */ [[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const id_type alias) noexcept { const auto &context = internal::meta_context::from(ctx); // fast lookup for unsearchable and overloaded types if(const auto it = context.bucket.find(alias); it != context.bucket.end()) { return meta_type{ctx, *it->second}; } for(auto &&curr: context.bucket) { if(curr.second->alias == alias) { return meta_type{ctx, *curr.second}; } } return meta_type{}; } /** * @brief Returns the meta type associated with a given identifier, if any. * @param alias Unique identifier. * @return The meta type associated with the given identifier, if any. */ [[nodiscard]] inline meta_type resolve(const id_type alias) noexcept { return resolve(locator::value_or(), alias); } /** * @brief Returns the meta type associated with a given type info object. * @param ctx The context from which to search for meta types. * @param info The type info object of the requested type. * @return The meta type associated with the given type info object, if any. */ [[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept { const auto &context = internal::meta_context::from(ctx); const auto it = context.bucket.find(info.hash()); return (it == context.bucket.cend()) ? meta_type{} : meta_type{ctx, *it->second}; } /** * @brief Returns the meta type associated with a given type info object. * @param info The type info object of the requested type. * @return The meta type associated with the given type info object, if any. */ [[nodiscard]] inline meta_type resolve(const type_info &info) noexcept { return resolve(locator::value_or(), info); } } // namespace entt #endif // #include "meta/template.hpp" // IWYU pragma: always_keep #ifndef ENTT_META_TEMPLATE_HPP #define ENTT_META_TEMPLATE_HPP // #include "../core/type_traits.hpp" namespace entt { /*! @brief Utility class to disambiguate class templates. */ template class> 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 class 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; }; } // namespace entt #endif // #include "meta/type_traits.hpp" #ifndef ENTT_META_TYPE_TRAITS_HPP #define ENTT_META_TYPE_TRAITS_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" 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` equal to true if a given type is * a pointer-like type, false otherwise. */ template struct is_meta_pointer_like: stl::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; } // namespace entt #endif // #include "meta/utility.hpp" #ifndef ENTT_META_UTILITY_HPP #define ENTT_META_UTILITY_HPP // #include "../core/type_traits.hpp" // #include "../locator/locator.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "meta.hpp" // #include "node.hpp" // #include "policy.hpp" namespace entt { /** * @brief Meta function descriptor traits. * @tparam Ret Function return type. * @tparam Args Function arguments. * @tparam Static Function staticness. * @tparam Const Function constness. */ template struct meta_function_descriptor_traits { /*! @brief Meta function return type. */ using return_type = Ret; /*! @brief Meta function arguments. */ using args_type = Args; /*! @brief True if the meta function is static, false otherwise. */ static constexpr bool is_static = Static; /*! @brief True if the meta function is const, false otherwise. */ static constexpr bool is_const = Const; }; /*! @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 : meta_function_descriptor_traits< Ret, stl::conditional_t, type_list, type_list>, !stl::is_base_of_v, true> {}; /** * @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 : meta_function_descriptor_traits< Ret, stl::conditional_t, type_list, type_list>, !stl::is_base_of_v, false> {}; /** * @brief Meta function descriptor. * @tparam Type Reflected type to which the meta data is associated. * @tparam Class Actual owner of the data member. * @tparam Ret Data member type. */ template struct meta_function_descriptor : meta_function_descriptor_traits< Ret &, stl::conditional_t, type_list<>, type_list>, !stl::is_base_of_v, false> {}; /** * @brief Meta function descriptor. * @tparam Type Reflected type to which the meta function is associated. * @tparam Ret Function return type. * @tparam MaybeType First function argument. * @tparam Args Other function arguments. */ template struct meta_function_descriptor : meta_function_descriptor_traits< Ret, stl::conditional_t< stl::is_same_v, Type> || stl::is_base_of_v, Type>, type_list, type_list>, !(stl::is_same_v, Type> || stl::is_base_of_v, Type>), stl::is_const_v> && (stl::is_same_v, Type> || stl::is_base_of_v, Type>)> {}; /** * @brief Meta function descriptor. * @tparam Type Reflected type to which the meta function is associated. * @tparam Ret Function return type. */ template struct meta_function_descriptor : meta_function_descriptor_traits< Ret, type_list<>, true, false> {}; /** * @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 meta_function_descriptor get_rid_of_noexcept(Ret (Class::*)(Args...) const); template static meta_function_descriptor get_rid_of_noexcept(Ret (Class::*)(Args...)); template requires stl::is_member_object_pointer_v static meta_function_descriptor get_rid_of_noexcept(Ret Class::*); template static meta_function_descriptor get_rid_of_noexcept(Ret (*)(Args...)); template static meta_function_descriptor get_rid_of_noexcept(Class); public: /*! @brief The meta function descriptor of the given function. */ using type = decltype(get_rid_of_noexcept(stl::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 = meta_function_helper::type; /** * @brief Wraps a value depending on the given policy. * * This function always returns a wrapped value in the requested context.
* Therefore, if the passed value is itself a wrapped object with a different * context, it undergoes a rebinding to the requested context. * * @tparam Policy Optional policy (no policy set by default). * @tparam Type Type of value to wrap. * @param ctx The context from which to search for meta types. * @param value Value to wrap. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) { if constexpr(stl::is_same_v) { static_assert(stl::is_lvalue_reference_v, "Invalid type"); return meta_any{ctx, stl::in_place_type &>, stl::as_const(value)}; } else if constexpr(stl::is_same_v || (stl::is_same_v && stl::is_lvalue_reference_v)) { return meta_any{ctx, stl::in_place_type, value}; } else if constexpr(stl::is_same_v) { return meta_any{ctx, stl::in_place_type}; } else { return meta_any{ctx, stl::forward(value)}; } } /** * @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, if any. */ template [[nodiscard]] meta_any meta_dispatch(Type &&value) { return meta_dispatch(locator::value_or(), stl::forward(value)); } /*! @cond ENTT_INTERNAL */ namespace internal { template [[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) { if constexpr(stl::is_void_v(candidate), args...))>) { stl::invoke(stl::forward(candidate), args...); return meta_any{ctx, stl::in_place_type}; } else { return meta_dispatch(ctx, stl::invoke(stl::forward(candidate), args...)); } } template [[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, stl::index_sequence) { using descriptor = meta_function_helper_t>; // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) if constexpr(stl::is_invocable_v, const Type &, type_list_element_t...>) { if(const auto *const clazz = instance.try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { return meta_invoke_with_args(instance.context(), stl::forward(candidate), *clazz, (args + Index)->cast>()...); } } else if constexpr(stl::is_invocable_v, Type &, type_list_element_t...>) { if(auto *const clazz = instance.try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { return meta_invoke_with_args(instance.context(), stl::forward(candidate), *clazz, (args + Index)->cast>()...); } } else { if(((args + Index)->allow_cast>() && ...)) { return meta_invoke_with_args(instance.context(), stl::forward(candidate), (args + Index)->cast>()...); } } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) return meta_any{meta_ctx_arg, instance.context()}; } template [[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, stl::index_sequence) { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) if(((args + Index)->allow_cast() && ...)) { return meta_any{ctx, stl::in_place_type, (args + Index)->cast()...}; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) return meta_any{meta_ctx_arg, ctx}; } } // namespace internal /*! @endcond */ /** * @brief Returns the meta type of the i-th element of a list of arguments. * @tparam Type Type list of the actual types of arguments. * @param ctx The context from which to search for meta types. * @param index The index of the element for which to return the meta type. * @return The meta type of the i-th element of the list of arguments. */ template [[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept { const auto &context = internal::meta_context::from(ctx); return {ctx, internal::meta_arg_node(context, Type{}, index)}; } /** * @brief Returns the meta type of the i-th element of a list of arguments. * @tparam Type Type list of the actual types of arguments. * @param index The index of the element for which to return the meta type. * @return The meta type of the i-th element of the list of arguments. */ template [[nodiscard]] meta_type meta_arg(const stl::size_t index) noexcept { return meta_arg(locator::value_or(), index); } /** * @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 args Parameters 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 *const args) { if constexpr(stl::is_member_function_pointer_v || stl::is_function_v>>) { return static_cast(internal::meta_invoke(*instance.operator->(), Data, args, stl::make_index_sequence::args_type::size>{})); } else if constexpr(stl::is_member_object_pointer_v) { using data_type = stl::remove_reference_t::return_type>; if constexpr(!stl::is_array_v && !stl::is_const_v) { if(auto *const clazz = instance->try_cast(); clazz && args->allow_cast()) { stl::invoke(Data, *clazz) = args->cast(); return true; } } return false; } else if constexpr(stl::is_pointer_v) { using data_type = stl::remove_reference_t; if constexpr(!stl::is_array_v && !stl::is_const_v) { if(args->allow_cast()) { *Data = args->cast(); return true; } } return false; } else { return false; } } /** * @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(meta_handle instance, meta_any value) { return meta_setter(*instance.operator->(), &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. * @param args Parameters to use to set the variable. * @return A meta any containing the value of the underlying variable. */ template [[nodiscard]] meta_any meta_getter(meta_handle instance, [[maybe_unused]] meta_any *const args) { if constexpr(stl::is_member_function_pointer_v || stl::is_function_v>>) { return internal::meta_invoke(*instance.operator->(), Data, args, stl::make_index_sequence::args_type::size>{}); } else if constexpr(stl::is_member_object_pointer_v) { if constexpr(!stl::is_array_v>>) { if(auto *clazz = instance->try_cast(); clazz) { return meta_dispatch(instance->context(), stl::invoke(Data, *clazz)); } else if(auto *fallback = instance->try_cast(); fallback) { return meta_dispatch(instance->context(), stl::invoke(Data, *fallback)); } } return meta_any{meta_ctx_arg, instance->context()}; } else if constexpr(stl::is_pointer_v) { if constexpr(stl::is_array_v>) { return meta_any{meta_ctx_arg, instance->context()}; } else { return meta_dispatch(instance->context(), *Data); } } else { return meta_dispatch(instance->context(), Data); } } /** * @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(meta_handle instance) { return meta_getter(*instance.operator->(), nullptr); } /** * @brief Tries to _invoke_ an object given a list of erased parameters. * @tparam Type Reflected type to which the object to _invoke_ is associated. * @tparam Policy Optional policy (no policy set by default). * @tparam Candidate The type of the actual object to _invoke_. * @param instance An opaque instance of the underlying type, if required. * @param candidate The actual object to _invoke_. * @param args Parameters to use to _invoke_ the object. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) { return internal::meta_invoke(*instance.operator->(), stl::forward(candidate), args, stl::make_index_sequence>::args_type::size>{}); } /** * @brief Tries to invoke a function given a list of erased parameters. * @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). * @param instance An opaque instance of the underlying type, if required. * @param args Parameters to use to invoke the function. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) { return internal::meta_invoke(*instance.operator->(), Candidate, args, stl::make_index_sequence>::args_type::size>{}); } /** * @brief Tries to construct an instance given a list of erased parameters. * * @warning * The context provided is used only for the return type.
* It's up to the caller to bind the arguments to the right context(s). * * @tparam Type Actual type of the instance to construct. * @tparam Args Types of arguments expected. * @param ctx The context from which to search for meta types. * @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(const meta_ctx &ctx, meta_any *const args) { return internal::meta_construct(ctx, args, stl::index_sequence_for{}); } /** * @brief Tries to construct an instance given a list of erased parameters. * @tparam Type Actual type of the instance to construct. * @tparam Args Types of arguments expected. * @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) { return meta_construct(locator::value_or(), args); } /** * @brief Tries to construct an instance given a list of erased parameters. * * @warning * The context provided is used only for the return type.
* It's up to the caller to bind the arguments to the right context(s). * * @tparam Type Reflected type to which the object to _invoke_ is associated. * @tparam Policy Optional policy (no policy set by default). * @tparam Candidate The type of the actual object to _invoke_. * @param ctx The context from which to search for meta types. * @param candidate The actual object to _invoke_. * @param args Parameters to use to _invoke_ the object. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) { if constexpr(meta_function_helper_t::is_static || stl::is_class_v>) { meta_any placeholder{meta_ctx_arg, ctx}; return internal::meta_invoke(placeholder, stl::forward(candidate), args, stl::make_index_sequence>::args_type::size>{}); } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) return internal::meta_invoke(*args, stl::forward(candidate), args + 1u, stl::make_index_sequence>::args_type::size>{}); } } /** * @brief Tries to construct an instance given a list of erased parameters. * @tparam Type Reflected type to which the object to _invoke_ is associated. * @tparam Policy Optional policy (no policy set by default). * @tparam Candidate The type of the actual object to _invoke_. * @param candidate The actual object to _invoke_. * @param args Parameters to use to _invoke_ the object. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) { return meta_construct(locator::value_or(), stl::forward(candidate), args); } /** * @brief Tries to construct an instance given a list of erased parameters. * * @warning * The context provided is used only for the return type.
* It's up to the caller to bind the arguments to the right context(s). * * @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). * @param ctx The context from which to search for meta types. * @param args Parameters to use to invoke the function. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) { return meta_construct(ctx, Candidate, args); } /** * @brief Tries to construct an instance given a list of erased parameters. * @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). * @param args Parameters to use to invoke the function. * @return A meta any containing the returned value, if any. */ template [[nodiscard]] meta_any meta_construct(meta_any *const args) { return meta_construct(locator::value_or(), args); } } // namespace entt #endif // #include "poly/poly.hpp" #ifndef ENTT_POLY_POLY_HPP #define ENTT_POLY_POLY_HPP // #include "../core/any.hpp" #ifndef ENTT_CORE_ANY_HPP #define ENTT_CORE_ANY_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" #ifndef ENTT_STL_STRING_VIEW_HPP #define ENTT_STL_STRING_VIEW_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string_view; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct fnv_1a_params; template<> struct fnv_1a_params { static constexpr auto offset = 2166136261; static constexpr auto prime = 16777619; }; template<> struct fnv_1a_params { static constexpr auto offset = 14695981039346656037ull; static constexpr auto prime = 1099511628211ull; }; template struct basic_hashed_string { using value_type = Char; using size_type = stl::size_t; using hash_type = id_type; const value_type *repr{}; hash_type hash{fnv_1a_params<>::offset}; size_type length{}; }; } // namespace internal /*! @endcond */ /** * @brief Zero overhead unique identifier. * * A hashed string is a compile-time tool that allows users to use * human-readable identifiers 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. * * @warning * This class doesn't take ownership of user-supplied strings nor does it make a * copy of them. * * @tparam Char Character type. */ template class basic_hashed_string: internal::basic_hashed_string { using base_type = internal::basic_hashed_string; using params = internal::fnv_1a_params<>; struct const_wrapper { // non-explicit constructor on purpose constexpr const_wrapper(const base_type::value_type *str) noexcept : repr{str} {} const base_type::value_type *repr; }; public: /*! @brief Character type. */ using value_type = base_type::value_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Unsigned integer type. */ using hash_type = base_type::hash_type; /** * @brief Returns directly the numeric representation of a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. * @return The numeric representation of the string. */ [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { return basic_hashed_string{str, len}; } /** * @brief Returns directly the numeric representation of a string. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. * @return The numeric representation of the string. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { return basic_hashed_string{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 constexpr hash_type value(const_wrapper wrapper) noexcept { return basic_hashed_string{wrapper}; } /*! @brief Constructs an empty hashed string. */ constexpr basic_hashed_string() noexcept : basic_hashed_string{nullptr, 0u} {} /** * @brief Constructs a hashed string from a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. */ constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; base_type::length < len; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Constructs a hashed string from an array of const characters. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { for(; str[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } } /** * @brief Explicit constructor on purpose to avoid constructing a hashed * string directly from a `const value_type *`. * * @warning * The lifetime of the string is not extended nor is it copied. * * @param wrapper Helps achieving the purpose by relying on overloading. */ explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept : base_type{wrapper.repr} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; wrapper.repr[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Returns the size of a hashed string. * @return The size of the hashed string. */ [[nodiscard]] constexpr size_type size() const noexcept { return base_type::length; } /** * @brief Returns the human-readable representation of a hashed string. * @return The string used to initialize the hashed string. */ [[nodiscard]] constexpr const value_type *data() const noexcept { return base_type::repr; } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr hash_type value() const noexcept { return base_type::hash; } /*! @copydoc data */ [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { return data(); } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr operator hash_type() const noexcept { return value(); } /** * @brief Compares two hashed strings. * @param other A valid hashed string. * @return True if the two hashed strings are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { return value() == other.value(); } /** * @brief Lexicographically compares two hashed strings. * @param other A valid hashed string. * @return The relative order between the two hashed strings. */ [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { return value() <=> other.value(); } }; /** * @brief Deduction guide. * @tparam Char Character type. * @param str Human-readable identifier. * @param len Length of the string to hash. */ template basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; /** * @brief Deduction guide. * @tparam Char Character type. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) basic_hashed_string(const Char (&str)[N]) -> 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]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { return hashed_string{str}; } /** * @brief User defined literal for hashed wstrings. * @param str The literal without its suffix. * @return A properly initialized hashed wstring. */ [[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { return hashed_wstring{str}; } } // namespace literals } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "utility.hpp" #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @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) 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) 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. */ constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) : func{stl::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 constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } /*! @copydoc operator()() */ template constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { return func(*this, stl::forward(args)...); } private: Func func; }; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { enum class any_request : stl::uint8_t { info, transfer, assign, compare, copy, move }; template struct basic_any_storage { static constexpr bool has_buffer = true; union { const void *instance{}; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) alignas(Align) stl::byte buffer[Len]; }; }; template struct basic_any_storage<0u, Align> { static constexpr bool has_buffer = false; const void *instance{}; }; template // NOLINTNEXTLINE(bugprone-sizeof-expression) struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v> {}; template struct in_situ: stl::false_type {}; } // namespace internal /*! @endcond */ /** * @brief A SBO friendly, type-safe container for single values of any type. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Optional alignment requirement. */ template class basic_any: private internal::basic_any_storage { using request = internal::any_request; using base_type = internal::basic_any_storage; using vtable_type = const void *(const request, const basic_any &, const void *); using deleter_type = void(const basic_any &); template static constexpr bool in_situ_v = internal::in_situ::value; template static const void *basic_vtable(const request req, const basic_any &value, const void *other) { switch(const auto *elem = static_cast(value.data()); req) { using enum internal::any_request; case info: return &type_id(); case transfer: if constexpr(stl::is_move_assignable_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) *const_cast(elem) = stl::move(*static_cast(const_cast(other))); return other; } [[fallthrough]]; case assign: if constexpr(stl::is_copy_assignable_v) { *const_cast(elem) = *static_cast(other); return other; } break; case compare: if constexpr(!stl::is_function_v && !stl::is_array_v && is_equality_comparable_v) { return (*elem == *static_cast(other)) ? other : nullptr; } else { return (elem == other) ? other : nullptr; } case copy: if constexpr(stl::is_copy_constructible_v) { // NOLINTNEXTLINE(bugprone-casting-through-void) static_cast(const_cast(other))->initialize(*elem); } break; case move: ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy"); if constexpr(in_situ_v) { // NOLINTNEXTLINE(bugprone-casting-through-void, bugprone-multi-level-implicit-pointer-conversion) return ::new(&static_cast(const_cast(other))->buffer) Type{stl::move(*const_cast(elem))}; } } return nullptr; } template static void basic_deleter(const basic_any &value) { ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::is_trivially_destructible_v), "Unexpected policy"); const auto *elem = static_cast(value.data()); if constexpr(in_situ_v) { (value.mode == any_policy::embedded) ? elem->~Type() : (delete elem); } else if constexpr(stl::is_array_v) { delete[] elem; } else { delete elem; } } template void initialize([[maybe_unused]] Args &&...args) { using plain_type = stl::remove_cvref_t; vtable = basic_vtable; underlying_type = type_hash::value(); if constexpr(stl::is_void_v) { deleter = nullptr; mode = any_policy::empty; this->instance = nullptr; } else if constexpr(stl::is_lvalue_reference_v) { deleter = nullptr; mode = stl::is_const_v> ? any_policy::cref : any_policy::ref; static_assert((stl::is_lvalue_reference_v && ...) && (sizeof...(Args) == 1u), "Invalid arguments"); // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) this->instance = (stl::addressof(args), ...); } else if constexpr(in_situ_v) { if constexpr(stl::is_trivially_destructible_v) { deleter = nullptr; } else { deleter = &basic_deleter; } mode = any_policy::embedded; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { ::new(&this->buffer) plain_type{stl::forward(args)...}; } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) ::new(&this->buffer) plain_type(stl::forward(args)...); } } else { deleter = &basic_deleter; mode = any_policy::dynamic; if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { this->instance = new plain_type{stl::forward(args)...}; } else if constexpr(stl::is_array_v) { static_assert(sizeof...(Args) == 0u, "Invalid arguments"); this->instance = new plain_type[stl::extent_v](); } else { this->instance = new plain_type(stl::forward(args)...); } } } void invoke_deleter_if_exists() { if(deleter != nullptr) { deleter(*this); } } public: /*! @brief Size of the internal buffer. */ static constexpr auto length = Len; /*! @brief Alignment requirement. */ static constexpr auto alignment = Align; /*! @brief Default constructor. */ constexpr basic_any() noexcept : basic_any{stl::in_place_type} {} /** * @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(stl::in_place_type_t, Args &&...args) : base_type{} { initialize(stl::forward(args)...); } /** * @brief Constructs a wrapper taking ownership of the passed object. * @tparam Type Type of object to use to initialize the wrapper. * @param value A pointer to an object to take ownership of. */ template requires (!stl::is_const_v && !stl::is_void_v) explicit basic_any(stl::in_place_t, Type *value) : base_type{} { if(value == nullptr) { initialize(); } else { initialize(*value); deleter = &basic_deleter; mode = any_policy::dynamic; } } /** * @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 requires (!stl::same_as, basic_any>) basic_any(Type &&value) : basic_any{stl::in_place_type>, stl::forward(value)} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ basic_any(const basic_any &other) : basic_any{} { other.vtable(request::copy, other, this); } /** * @brief Move constructor. * @param other The instance to move from. */ basic_any(basic_any &&other) noexcept : base_type{}, vtable{other.vtable}, deleter{other.deleter}, underlying_type{other.underlying_type}, mode{other.mode} { if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } } /*! @brief Frees the internal buffer, whatever it means. */ ~basic_any() { invoke_deleter_if_exists(); } /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This any object. */ basic_any &operator=(const basic_any &other) { if(this != &other) { invoke_deleter_if_exists(); if(other) { other.vtable(request::copy, other, this); } else { initialize(); } } return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This any object. */ basic_any &operator=(basic_any &&other) noexcept { if(this != &other) { invoke_deleter_if_exists(); if(other.mode == any_policy::embedded) { other.vtable(request::move, other, this); } else if(other.mode != any_policy::empty) { this->instance = stl::exchange(other.instance, nullptr); } vtable = other.vtable; deleter = other.deleter; underlying_type = other.underlying_type; 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 requires (!stl::same_as, basic_any>) basic_any &operator=(Type &&value) { emplace>(stl::forward(value)); return *this; } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] bool has_value() const noexcept { return (mode != any_policy::empty); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @param req Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ [[nodiscard]] bool has_value(const type_info &req) const noexcept { return (underlying_type == req.hash()); } /** * @brief Returns false if the wrapper does not contain the expected type, * true otherwise. * @tparam Type Expected type. * @return False if the wrapper does not contain the expected type, true * otherwise. */ template [[nodiscard]] bool has_value() const noexcept { return (underlying_type == type_hash::value()); } /** * @brief Returns the object type info if any, `type_id()` otherwise. * @return The object type info if any, `type_id()` otherwise. */ [[nodiscard]] const type_info &info() const noexcept { return *static_cast(vtable(request::info, *this, nullptr)); } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data() const noexcept { if constexpr(base_type::has_buffer) { return (mode == any_policy::embedded) ? &this->buffer : this->instance; } else { return this->instance; } } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data(const type_info &req) const noexcept { return has_value(req) ? data() : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] const Type *data() const noexcept { return has_value>() ? static_cast(data()) : nullptr; } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data() noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data()); } /** * @brief Returns an opaque pointer to the contained instance. * @param req Expected type. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] void *data(const type_info &req) noexcept { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data(req)); } /** * @brief Returns an opaque pointer to the contained instance. * @tparam Type Expected type. * @return An opaque pointer the contained instance, if any. */ template [[nodiscard]] Type *data() noexcept { if constexpr(stl::is_const_v) { return stl::as_const(*this).template data>(); } else { return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).template data>()); } } /** * @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) { invoke_deleter_if_exists(); initialize(stl::forward(args)...); } /** * @brief Assigns a value to the contained object without replacing it. * @param other The value to assign to the contained object. * @return True in case of success, false otherwise. */ bool assign(const basic_any &other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (vtable(request::assign, *this, other.data()) != nullptr); } return false; } /*! @copydoc assign */ // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) bool assign(basic_any &&other) { if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { return (other.mode == any_policy::cref) ? (vtable(request::assign, *this, stl::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr); } return false; } /*! @brief Destroys contained object */ void reset() { invoke_deleter_if_exists(); initialize(); } /** * @brief Returns false if a wrapper is empty, true otherwise. * @return False if the wrapper is empty, true otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return has_value(); } /** * @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 basic_any &other) const noexcept { if(other && (underlying_type == other.underlying_type)) { return (vtable(request::compare, *this, other.data()) != nullptr); } return (!*this && !other); } /** * @brief Aliasing constructor. * @return A wrapper that shares a reference to an unmanaged object. */ [[nodiscard]] basic_any as_ref() noexcept { basic_any other = stl::as_const(*this).as_ref(); switch(mode) { using enum any_policy; case cref: case empty: other.mode = mode; break; default: other.mode = any_policy::ref; break; } return other; } /*! @copydoc as_ref */ [[nodiscard]] basic_any as_ref() const noexcept { basic_any other{}; other.instance = data(); other.vtable = vtable; other.underlying_type = underlying_type; other.mode = any_policy::cref; return other; } /** * @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 noexcept { return (mode == any_policy::dynamic || mode == any_policy::embedded); } /** * @brief Returns the current mode of an any object. * @return The current mode of the any object. */ [[nodiscard]] any_policy policy() const noexcept { return mode; } private: vtable_type *vtable{}; deleter_type *deleter{}; id_type underlying_type{}; any_policy mode{}; }; /** * @brief Performs type-safe access to the contained object. * @tparam Type Type to which conversion is required. * @tparam Len Size of the buffer reserved for the small buffer optimization. * @tparam Align Alignment requirement. * @param data Target any object. * @return The element converted to the requested type. */ template [[nodiscard]] stl::remove_const_t any_cast(const basic_any &data) noexcept { const auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(*instance); } /*! @copydoc any_cast */ template [[nodiscard]] stl::remove_const_t any_cast(basic_any &data) 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 // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) [[nodiscard]] stl::remove_const_t any_cast(basic_any &&data) noexcept { if constexpr(stl::is_copy_constructible_v>) { if(auto *const instance = any_cast>(&data); instance) { return static_cast(stl::move(*instance)); } return any_cast(data); } else { auto *const instance = any_cast>(&data); ENTT_ASSERT(instance, "Invalid instance"); return static_cast(stl::move(*instance)); } } /*! @copydoc any_cast */ template [[nodiscard]] const Type *any_cast(const basic_any *data) noexcept { return data->template data>(); } /*! @copydoc any_cast */ template [[nodiscard]] Type *any_cast(basic_any *data) noexcept { if constexpr(stl::is_const_v) { // last attempt to make wrappers for const references return their values return any_cast(&stl::as_const(*data)); } else { return data->template data(); } } /** * @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 buffer 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, stl::size_t Align = basic_any::alignment, typename... Args> [[nodiscard]] basic_any make_any(Args &&...args) { return basic_any{stl::in_place_type, stl::forward(args)...}; } /** * @brief Forwards its argument and avoids copies for lvalue references. * @tparam Len Size of the buffer 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, stl::size_t Align = basic_any::alignment, typename Type> [[nodiscard]] basic_any forward_as_any(Type &&value) { return basic_any{stl::in_place_type, stl::forward(value)}; } } // namespace entt #endif // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../core/type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_POLY_FWD_HPP #define ENTT_POLY_FWD_HPP // #include "../stl/cstddef.hpp" namespace entt { // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) template class basic_poly; /** * @brief Alias declaration for the most common use case. * @tparam Concept Concept descriptor. */ template using poly = basic_poly; } // namespace entt #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 [[nodiscard]] poly_inspector invoke(Args &&...args) const; /*! @copydoc invoke */ template [[nodiscard]] 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 = Concept::template type; template requires stl::derived_from> static auto vtable_entry(Ret (*)(Clazz &, Args...)) -> Ret (*)(constness_as_t, Clazz> &, Args...); template static auto vtable_entry(Ret (*)(Args...)) -> Ret (*)(const basic_any &, Args...); template requires stl::derived_from static auto vtable_entry(Ret (Clazz::*)(Args...)) -> Ret (*)(basic_any &, Args...); template requires stl::derived_from static auto vtable_entry(Ret (Clazz::*)(Args...) const) -> Ret (*)(const basic_any &, Args...); template static auto make_vtable(value_list) noexcept -> decltype(stl::make_tuple(vtable_entry(Candidate)...)); template [[nodiscard]] static ENTT_CONSTEVAL auto make_vtable(type_list) noexcept { if constexpr(sizeof...(Func) == 0u) { return decltype(make_vtable(typename Concept::template impl{})){}; } else if constexpr((stl::is_function_v && ...)) { return decltype(stl::make_tuple(vtable_entry(stl::declval())...)){}; } } template static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept { if constexpr(stl::is_invocable_r_v) { entry = +[](Any &, Args... args) -> Ret { return stl::invoke(Candidate, stl::forward(args)...); }; } else { entry = +[](Any &instance, Args... args) -> Ret { return static_cast(stl::invoke(Candidate, any_cast &>(instance), stl::forward(args)...)); }; } } template [[nodiscard]] static auto fill_vtable(stl::index_sequence) noexcept { vtable_type impl{}; (fill_vtable_entry>>(stl::get(impl)), ...); return impl; } using vtable_type = decltype(make_vtable(Concept{})); static constexpr bool is_mono = stl::tuple_size_v == 1u; public: /*! @brief Virtual table type. */ using type = stl::conditional_t, const vtable_type *>; /** * @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 type instance() noexcept { static const vtable_type vtable = fill_vtable(stl::make_index_sequence::size>{}); if constexpr(is_mono) { return stl::get<0>(vtable); } else { 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); if constexpr(stl::is_function_v>) { return poly.vtable(poly.storage, stl::forward(args)...); } else { return stl::get(*poly.vtable)(poly.storage, stl::forward(args)...); } } /*! @copydoc invoke */ template [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) { auto &poly = static_cast(self); if constexpr(stl::is_function_v>) { static_assert(Member == 0u, "Unknown member"); return poly.vtable(poly.storage, stl::forward(args)...); } else { return stl::get(*poly.vtable)(poly.storage, stl::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 stl::forward(self).template invoke(self, stl::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>> { friend struct poly_base; public: /*! @brief Concept type. */ using concept_type = Concept::template type>; /*! @brief Virtual table type. */ using vtable_type = poly_vtable::type; /*! @brief Default constructor. */ basic_poly() noexcept = default; /** * @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(stl::in_place_type_t, Args &&...args) : storage{stl::in_place_type, stl::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 requires (!stl::same_as, basic_poly>) basic_poly(Type &&value) noexcept : basic_poly{stl::in_place_type>, stl::forward(value)} {} /** * @brief Returns the object type info if any, `type_id()` otherwise. * @return The object type info if any, `type_id()` otherwise. */ [[nodiscard]] const type_info &info() const noexcept { return storage.info(); } /** * @brief Returns an opaque pointer to the contained instance. * @return An opaque pointer the contained instance, if any. */ [[nodiscard]] const void *data() const noexcept { return storage.data(); } /*! @copydoc data */ [[nodiscard]] void *data() 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) { storage.template emplace(stl::forward(args)...); vtable = poly_vtable::template instance>(); } /*! @brief Destroys contained object */ void reset() { storage.reset(); vtable = {}; } /** * @brief Returns false if a poly is empty, true otherwise. * @return False if the poly is empty, true otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return static_cast(storage); } /** * @brief Returns a pointer to the underlying concept. * @return A pointer to the underlying concept. */ [[nodiscard]] concept_type *operator->() noexcept { return this; } /*! @copydoc operator-> */ [[nodiscard]] const concept_type *operator->() const noexcept { return this; } /** * @brief Aliasing constructor. * @return A poly that shares a reference to an unmanaged object. */ [[nodiscard]] basic_poly as_ref() noexcept { basic_poly ref{}; ref.storage = storage.as_ref(); ref.vtable = vtable; return ref; } /*! @copydoc as_ref */ [[nodiscard]] basic_poly as_ref() const noexcept { basic_poly ref{}; ref.storage = storage.as_ref(); ref.vtable = vtable; return ref; } private: basic_any storage{}; vtable_type vtable{}; }; } // namespace entt #endif // #include "process/process.hpp" #ifndef ENTT_PROCESS_PROCESS_HPP #define ENTT_PROCESS_PROCESS_HPP // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_PROCESS_FWD_HPP #define ENTT_PROCESS_FWD_HPP // #include "../stl/cstdint.hpp" // #include "../stl/memory.hpp" namespace entt { template> class basic_process; /*! @brief Alias declaration for the most common use case. */ using process = basic_process; template> class basic_scheduler; /*! @brief Alias declaration for the most common use case. */ using scheduler = basic_scheduler; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct process_adaptor; } // namespace internal /*! @endcond */ /** * @brief Base class for processes. * * Derived classes must specify what's the intended type for elapsed times.
* A process can implement the following member functions whether required: * * * @code{.cpp} * void update(Delta, void *) override; * @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 succeeded() override; * @endcode * * It's invoked in case of success, immediately after an update and during the * same tick. * * * @code{.cpp} * void failed() override; * @endcode * * It's invoked in case of errors, immediately after an update and during the * same tick. * * * @code{.cpp} * void aborted() override; * @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` member functions and even pause or unpause the process * itself. * * @sa scheduler * * @tparam Delta Type to use to provide elapsed time. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_process: public stl::enable_shared_from_this> { enum class state : stl::uint8_t { idle = 0, running, paused, succeeded, failed, aborted, finished, rejected }; virtual void update(const Delta, void *) { abort(); } virtual void succeeded() {} virtual void failed() {} virtual void aborted() {} public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Type used to provide elapsed time. */ using delta_type = Delta; /*! @brief Handle type. */ using handle_type = stl::shared_ptr; /*! @brief Default constructor. */ basic_process() : basic_process{allocator_type{}} {} /** * @brief Constructs a scheduler with a given allocator. * @param allocator The allocator to use. */ explicit basic_process(const allocator_type &allocator) : next{nullptr, allocator}, current{state::idle} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_process(const basic_process &) = delete; /*! @brief Default move constructor, deleted on purpose. */ basic_process(basic_process &&) = delete; /*! @brief Default destructor. */ virtual ~basic_process() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This process scheduler. */ basic_process &operator=(const basic_process &) = delete; /** * @brief Default move assignment operator, deleted on purpose. * @return This process scheduler. */ basic_process &operator=(basic_process &&) = delete; /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return next.second(); } /*! @brief Aborts a process if it's still alive, otherwise does nothing. */ void abort() { if(alive()) { current = state::aborted; } } /** * @brief Terminates a process with success if it's still alive, otherwise * does nothing. */ void succeed() noexcept { if(alive()) { current = state::succeeded; } } /** * @brief Terminates a process with errors if it's still alive, otherwise * does nothing. */ void fail() noexcept { if(alive()) { current = state::failed; } } /*! @brief Stops a process if it's running, otherwise does nothing. */ void pause() noexcept { if(alive()) { current = state::paused; } } /*! @brief Restarts a process if it's paused, otherwise does nothing. */ void unpause() noexcept { if(alive()) { current = state::running; } } /** * @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 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 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 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 noexcept { return current == state::rejected; } /** * @brief Assigns a child process to run in case of success. * @tparam Type Type of child process to create. * @tparam Args Types of arguments to use to initialize the child process. * @param args Parameters to use to initialize the child process. * @return A reference to the newly created child process. */ template basic_process &then(Args &&...args) { const auto &allocator = next.second(); return *(next.first() = stl::allocate_shared(allocator, allocator, stl::forward(args)...)); } /** * @brief Assigns a child process to run in case of success. * @tparam Func Type of child process to create. * @param func Either a lambda or a functor to use as a child process. * @return A reference to the newly created child process. */ template basic_process &then(Func func) { const auto &allocator = next.second(); using process_type = internal::process_adaptor; return *(next.first() = stl::allocate_shared(allocator, allocator, stl::move(func))); } /** * @brief Returns the child process without releasing ownership, if any. * @return The child process attached to the object, if any. */ handle_type peek() { return next.first(); } /** * @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::idle: case state::running: current = state::running; update(delta, data); break; default: // suppress warnings break; } // if it's dead, it must be notified and removed immediately switch(current) { case state::succeeded: succeeded(); current = state::finished; break; case state::failed: failed(); current = state::rejected; break; case state::aborted: aborted(); current = state::rejected; break; default: // suppress warnings break; } } private: compressed_pair next; state current; }; /*! @cond ENTT_INTERNAL */ namespace internal { template struct process_adaptor: public basic_process { using allocator_type = Allocator; using base_type = basic_process; using delta_type = base_type::delta_type; process_adaptor(const allocator_type &allocator, Func proc) : base_type{allocator}, func{stl::move(proc)} {} void update(const delta_type delta, void *data) override { func(*this, delta, data); } private: Func func; }; } // namespace internal /*! @endcond */ } // namespace entt #endif // #include "process/scheduler.hpp" #ifndef ENTT_PROCESS_SCHEDULER_HPP #define ENTT_PROCESS_SCHEDULER_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/compressed_pair.hpp" // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" // #include "process.hpp" #ifndef ENTT_PROCESS_PROCESS_HPP #define ENTT_PROCESS_PROCESS_HPP // #include "../core/compressed_pair.hpp" // #include "../core/type_traits.hpp" // #include "../stl/cstdint.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct process_adaptor; } // namespace internal /*! @endcond */ /** * @brief Base class for processes. * * Derived classes must specify what's the intended type for elapsed times.
* A process can implement the following member functions whether required: * * * @code{.cpp} * void update(Delta, void *) override; * @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 succeeded() override; * @endcode * * It's invoked in case of success, immediately after an update and during the * same tick. * * * @code{.cpp} * void failed() override; * @endcode * * It's invoked in case of errors, immediately after an update and during the * same tick. * * * @code{.cpp} * void aborted() override; * @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` member functions and even pause or unpause the process * itself. * * @sa scheduler * * @tparam Delta Type to use to provide elapsed time. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_process: public stl::enable_shared_from_this> { enum class state : stl::uint8_t { idle = 0, running, paused, succeeded, failed, aborted, finished, rejected }; virtual void update(const Delta, void *) { abort(); } virtual void succeeded() {} virtual void failed() {} virtual void aborted() {} public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Type used to provide elapsed time. */ using delta_type = Delta; /*! @brief Handle type. */ using handle_type = stl::shared_ptr; /*! @brief Default constructor. */ basic_process() : basic_process{allocator_type{}} {} /** * @brief Constructs a scheduler with a given allocator. * @param allocator The allocator to use. */ explicit basic_process(const allocator_type &allocator) : next{nullptr, allocator}, current{state::idle} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_process(const basic_process &) = delete; /*! @brief Default move constructor, deleted on purpose. */ basic_process(basic_process &&) = delete; /*! @brief Default destructor. */ virtual ~basic_process() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This process scheduler. */ basic_process &operator=(const basic_process &) = delete; /** * @brief Default move assignment operator, deleted on purpose. * @return This process scheduler. */ basic_process &operator=(basic_process &&) = delete; /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return next.second(); } /*! @brief Aborts a process if it's still alive, otherwise does nothing. */ void abort() { if(alive()) { current = state::aborted; } } /** * @brief Terminates a process with success if it's still alive, otherwise * does nothing. */ void succeed() noexcept { if(alive()) { current = state::succeeded; } } /** * @brief Terminates a process with errors if it's still alive, otherwise * does nothing. */ void fail() noexcept { if(alive()) { current = state::failed; } } /*! @brief Stops a process if it's running, otherwise does nothing. */ void pause() noexcept { if(alive()) { current = state::paused; } } /*! @brief Restarts a process if it's paused, otherwise does nothing. */ void unpause() noexcept { if(alive()) { current = state::running; } } /** * @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 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 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 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 noexcept { return current == state::rejected; } /** * @brief Assigns a child process to run in case of success. * @tparam Type Type of child process to create. * @tparam Args Types of arguments to use to initialize the child process. * @param args Parameters to use to initialize the child process. * @return A reference to the newly created child process. */ template basic_process &then(Args &&...args) { const auto &allocator = next.second(); return *(next.first() = stl::allocate_shared(allocator, allocator, stl::forward(args)...)); } /** * @brief Assigns a child process to run in case of success. * @tparam Func Type of child process to create. * @param func Either a lambda or a functor to use as a child process. * @return A reference to the newly created child process. */ template basic_process &then(Func func) { const auto &allocator = next.second(); using process_type = internal::process_adaptor; return *(next.first() = stl::allocate_shared(allocator, allocator, stl::move(func))); } /** * @brief Returns the child process without releasing ownership, if any. * @return The child process attached to the object, if any. */ handle_type peek() { return next.first(); } /** * @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::idle: case state::running: current = state::running; update(delta, data); break; default: // suppress warnings break; } // if it's dead, it must be notified and removed immediately switch(current) { case state::succeeded: succeeded(); current = state::finished; break; case state::failed: failed(); current = state::rejected; break; case state::aborted: aborted(); current = state::rejected; break; default: // suppress warnings break; } } private: compressed_pair next; state current; }; /*! @cond ENTT_INTERNAL */ namespace internal { template struct process_adaptor: public basic_process { using allocator_type = Allocator; using base_type = basic_process; using delta_type = base_type::delta_type; process_adaptor(const allocator_type &allocator, Func proc) : base_type{allocator}, func{stl::move(proc)} {} void update(const delta_type delta, void *data) override { func(*this, delta, data); } private: Func func; }; } // namespace internal /*! @endcond */ } // namespace entt #endif namespace entt { /** * @brief Cooperative scheduler for processes. * * A cooperative scheduler runs processes and helps managing their life cycles. * * Each process is invoked once per tick. If a process terminates, it's * removed automatically from the scheduler and it's never invoked again.
* A process can also have a child. In this case, the process is replaced with * its child when it terminates if it returns with success. In case of errors, * both the process and its child are discarded. * * In order to invoke all scheduled processes, call the `update` member function * passing it the elapsed time to forward to the tasks. * * @sa process * * @tparam Delta Type to use to provide elapsed time. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_scheduler { using base_type = basic_process; using alloc_traits = stl::allocator_traits; using container_allocator = alloc_traits::template rebind_alloc>; using container_type = stl::vector, container_allocator>; public: /*! @brief Process type. */ using type = base_type; /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Unsigned integer type. */ using delta_type = Delta; /*! @brief Default constructor. */ basic_scheduler() : basic_scheduler{allocator_type{}} {} /** * @brief Constructs a scheduler with a given allocator. * @param allocator The allocator to use. */ explicit basic_scheduler(const allocator_type &allocator) : handlers{allocator, allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_scheduler(const basic_scheduler &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_scheduler(basic_scheduler &&other) noexcept : handlers{stl::move(other.handlers)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_scheduler(basic_scheduler &&other, const allocator_type &allocator) : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); } /*! @brief Default destructor. */ ~basic_scheduler() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This process scheduler. */ basic_scheduler &operator=(const basic_scheduler &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This process scheduler. */ basic_scheduler &operator=(basic_scheduler &&other) noexcept { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); swap(other); return *this; } /** * @brief Exchanges the contents with those of a given scheduler. * @param other Scheduler to exchange the content with. */ void swap(basic_scheduler &other) noexcept { using stl::swap; swap(handlers, other.handlers); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return handlers.second(); } /** * @brief Number of processes currently scheduled. * @return Number of processes currently scheduled. */ [[nodiscard]] size_type size() const noexcept { return handlers.first().size(); } /** * @brief Returns true if at least a process is currently scheduled. * @return True if there are scheduled processes, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return handlers.first().empty(); } /** * @brief Discards all scheduled processes. * * Processes aren't aborted. They are discarded along with their children * and never executed again. */ void clear() { handlers.first().clear(); } /** * @brief Schedules a process for the next tick. * @tparam Type Type of process to create. * @tparam Args Types of arguments to use to initialize the process. * @param args Parameters to use to initialize the process. * @return A reference to the newly created process. */ template type &attach(Args &&...args) { const auto &allocator = handlers.second(); return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::forward(args)...)); } /** * @brief Schedules a process for the next tick. * @tparam Func Type of process to create. * @param func Either a lambda or a functor to use as a process. * @return A reference to the newly created process. */ template type &attach(Func func) { const auto &allocator = handlers.second(); using process_type = internal::process_adaptor; return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::move(func))); } /** * @brief Updates all scheduled processes. * * All scheduled processes are executed in no specific order.
* If a process terminates with success, it's replaced with its child, if * any. Otherwise, if a process terminates with an error, it's removed along * with its child. * * @param delta Elapsed time. * @param data Optional data. */ void update(const delta_type delta, void *data = nullptr) { for(auto next = handlers.first().size(); next; --next) { const auto pos = next - 1u; handlers.first()[pos]->tick(delta, data); // updating might spawn/reallocate, cannot hold refs until here auto &elem = handlers.first()[pos]; if(elem->finished()) { elem = elem->peek(); } if(!elem || elem->rejected()) { elem = stl::move(handlers.first().back()); handlers.first().pop_back(); } } } /** * @brief Aborts all scheduled processes. * * Unless an immediate operation is requested, the abort is scheduled for * the next tick. Processes won't be executed anymore in any case.
* Once a process is fully aborted and thus finished, it's discarded along * with its child, if any. * * @param immediate Requests an immediate operation. */ void abort(const bool immediate = false) { for(auto &&curr: handlers.first()) { curr->abort(); if(immediate) { curr->tick({}); } } } private: compressed_pair handlers; }; } // namespace entt #endif // #include "resource/cache.hpp" #ifndef ENTT_RESOURCE_RESOURCE_CACHE_HPP #define ENTT_RESOURCE_RESOURCE_CACHE_HPP #include // #include "../container/dense_map.hpp" #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" namespace entt { template< typename Key, typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator>> class dense_map; template< typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator> class dense_set; template class basic_table; /** * @brief Alias declaration for the most common use case. * @tparam Type Element types. */ template using table = basic_table...>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { using value_type = stl::pair; template dense_map_node(const stl::size_t pos, Args &&...args) : next{pos}, element{stl::forward(args)...} {} template dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) : next{pos}, element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, other.element)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} stl::size_t next; value_type element; }; template class dense_map_iterator final { template friend class dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr dense_map_iterator() noexcept : it{} {} constexpr dense_map_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_iterator(const dense_map_iterator &other) noexcept : it{other.it} {} constexpr dense_map_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_map_iterator operator++(int) noexcept { const dense_map_iterator orig = *this; return ++(*this), orig; } constexpr dense_map_iterator &operator--() noexcept { return --it, *this; } constexpr dense_map_iterator operator--(int) noexcept { const dense_map_iterator orig = *this; return operator--(), orig; } constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_map_iterator operator+(const difference_type value) const noexcept { dense_map_iterator copy = *this; return (copy += value); } constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_map_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].element.first, it[value].element.second}; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_map_local_iterator final { template friend class dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr dense_map_local_iterator() noexcept = default; constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_map_local_iterator &operator++() noexcept { return (offset = it[static_cast(offset)].next), *this; } constexpr dense_map_local_iterator operator++(int) noexcept { const dense_map_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { const auto idx = static_cast(offset); return {it[idx].element.first, it[idx].element.second}; } template [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_map_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for key-value pairs with unique keys. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on the hash of its key. Keys with the same hash * code appear in the same bucket. * * @tparam Key Key type of the associative container. * @tparam Type Mapped type of the associative container. * @tparam Hash Type of function to use to hash the keys. * @tparam KeyEqual Type of function to use to compare the keys for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_map { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; using node_type = internal::dense_map_node; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v>, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) return fast_mod(static_cast(sparse.second()(key)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } template [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { it->second = stl::forward(value); return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].next) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Key; /*! @brief Mapped type of the container. */ using mapped_type = Type; /*! @brief Key-value type of the container. */ using value_type = stl::pair; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the keys. */ using hasher = Hash; /*! @brief Type of function to use to compare the keys for equality. */ using key_equal = KeyEqual; /*! @brief Input iterator type. */ using iterator = internal::dense_map_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::dense_map_iterator; /*! @brief Input iterator type. */ using local_iterator = internal::dense_map_local_iterator; /*! @brief Constant input iterator type. */ using const_local_iterator = internal::dense_map_local_iterator; /*! @brief Default constructor. */ dense_map() : dense_map{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_map(const allocator_type &allocator) : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const allocator_type &allocator) : dense_map{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_map{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_map(const dense_map &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_map(const dense_map &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_map(dense_map &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_map(dense_map &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_map() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_map &operator=(const dense_map &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_map &operator=(dense_map &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_map &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if the key does not exist. * @param value A key-value pair eventually convertible to the value type. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value.first, value.second); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); } /** * @copydoc insert * @tparam Arg Type of the key-value pair to insert into the container. */ template requires stl::constructible_from stl::pair insert(Arg &&value) { return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); } /** * @brief Inserts elements into the container, if their keys do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Inserts an element into the container or assigns to the current * element if the key already exists. * @tparam Arg Type of the value to insert or assign. * @param key A key used both to look up and to insert if not found. * @param value A value to insert or assign. * @return A pair consisting of an iterator to the element and a bool * denoting whether the insertion took place. */ template stl::pair insert_or_assign(const key_type &key, Arg &&value) { return insert_or_overwrite(key, stl::forward(value)); } /*! @copydoc insert_or_assign */ template stl::pair insert_or_assign(key_type &&key, Arg &&value) { return insert_or_overwrite(stl::move(key), stl::forward(value)); } /** * @brief Constructs an element in-place, if the key does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace([[maybe_unused]] Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return insert_or_do_nothing(key_type{}); } else if constexpr(sizeof...(Args) == 1u) { return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); } else if constexpr(sizeof...(Args) == 2u) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); const auto index = key_to_bucket(node.element.first); if(auto it = constrained_find(node.element.first, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.next, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Inserts in-place if the key does not exist, does nothing if the * key exists. * @tparam Args Types of arguments to forward to the constructor of the * element. * @param key A key used both to look up and to insert if not found. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair try_emplace(const key_type &key, Args &&...args) { return insert_or_do_nothing(key, stl::forward(args)...); } /*! @copydoc try_emplace */ template stl::pair try_emplace(key_type &&key, Args &&...args) { return insert_or_do_nothing(stl::move(key), stl::forward(args)...); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(pos->first); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].element.first); } return (begin() + dist); } /** * @brief Removes the element associated with a given key. * @param key A key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const key_type &key) { for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { if(packed.second()(packed.first()[*curr].element.first, key)) { const auto index = *curr; *curr = packed.first()[*curr].next; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &at(const key_type &key) { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] const mapped_type &at(const key_type &key) const { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type const &at(const auto &key) const requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] mapped_type &at(const auto &key) requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](const key_type &key) { return insert_or_do_nothing(key).first->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](key_type &&key) { return insert_or_do_nothing(stl::move(key)).first->second; } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const key_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const key_type &key) { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const key_type &key) const { return constrained_find(key, key_to_bucket(key)); } /** * @brief Finds an element with a key that compares _equivalent_ to a given * key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &key) requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &key) const requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /** * @brief Returns a range containing all elements with a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const key_type &key) { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const key_type &key) const { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &key) requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &key) const requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given key. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const key_type &key) const { return (find(key) != cend()); } /** * @brief Checks if the container contains an element with a key that * compares _equivalent_ to a given value. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &key) const requires is_transparent_v && is_transparent_v { return (find(key) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given key. * @param key The value of the key to examine. * @return The bucket for the given key. */ [[nodiscard]] size_type bucket(const key_type &key) const { return key_to_bucket(key); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = key_to_bucket(packed.first()[pos].element.first); packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the keys. * @return The function used to hash the keys. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare keys for equality. * @return The function used to compare keys for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::true_type {}; } // namespace std /*! @endcond */ #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_RESOURCE_FWD_HPP #define ENTT_RESOURCE_FWD_HPP // #include "../stl/memory.hpp" namespace entt { template struct resource_loader; template, typename = stl::allocator> class resource_cache; template class resource; } // namespace entt #endif // #include "loader.hpp" #ifndef ENTT_RESOURCE_LOADER_HPP #define ENTT_RESOURCE_LOADER_HPP // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /** * @brief Transparent loader for shared resources. * @tparam Type Type of resources created by the loader. */ template struct resource_loader { /*! @brief Result type. */ using result_type = stl::shared_ptr; /** * @brief Constructs a shared pointer to a resource from its arguments. * @tparam Args Types of arguments to use to construct the resource. * @param args Parameters to use to construct the resource. * @return A shared pointer to a resource of the given type. */ template result_type operator()(Args &&...args) const { return stl::make_shared(stl::forward(args)...); } }; } // namespace entt #endif // #include "resource.hpp" #ifndef ENTT_RESOURCE_RESOURCE_HPP #define ENTT_RESOURCE_RESOURCE_HPP #include // #include "../stl/concepts.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /** * @brief Basic resource handle. * * A handle wraps a resource and extends its lifetime. It also shares the same * resource with all other handles constructed from the same element.
* As a rule of thumb, resources should never be copied nor moved. Handles are * the way to go to push references around. * * @tparam Type Type of resource managed by a handle. */ template class resource { template friend class resource; public: /*! @brief Resource type. */ using element_type = Type; /*! @brief Handle type. */ using handle_type = stl::shared_ptr; /*! @brief Default constructor. */ resource() noexcept : value{} {} /** * @brief Creates a new resource handle. * @param res A handle to a resource. */ explicit resource(handle_type res) noexcept : value{stl::move(res)} {} /*! @brief Default copy constructor. */ resource(const resource &) noexcept = default; /*! @brief Default move constructor. */ resource(resource &&) noexcept = default; /** * @brief Aliasing constructor. * @tparam Other Type of resource managed by the received handle. * @param other The handle with which to share ownership information. * @param res Unrelated and unmanaged resources. */ template resource(const resource &other, element_type &res) noexcept : value{other.value, stl::addressof(res)} {} /** * @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 requires (!stl::same_as && stl::constructible_from) resource(const resource &other) noexcept : value{other.value} {} /** * @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 requires (!stl::same_as && stl::constructible_from) resource(resource &&other) noexcept : value{stl::move(other.value)} {} /*! @brief Default destructor. */ ~resource() = default; /** * @brief Default copy assignment operator. * @return This resource handle. */ resource &operator=(const resource &) noexcept = default; /** * @brief Default move assignment operator. * @return This resource handle. */ resource &operator=(resource &&) 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 requires (!stl::same_as && stl::constructible_from) resource &operator=(const resource &other) noexcept { value = other.value; 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 requires (!stl::same_as && stl::constructible_from) resource &operator=(resource &&other) noexcept { value = stl::move(other.value); return *this; } /** * @brief Exchanges the content with that of a given resource. * @param other Resource to exchange the content with. */ void swap(resource &other) noexcept { using stl::swap; swap(value, other.value); } /** * @brief Returns 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]] element_type &operator*() const noexcept { return *value; } /*! @copydoc operator* */ [[nodiscard]] operator element_type &() const noexcept { return *value; } /** * @brief Returns a pointer to the managed resource. * @return A pointer to the managed resource. */ [[nodiscard]] element_type *operator->() const noexcept { return value.get(); } /** * @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 noexcept { return static_cast(value); } /** * @brief Compares two handles. * @tparam Other Type of resource managed by the other handle. * @param other A valid handle. * @return True if both handles refer to the same resource, false otherwise. */ template [[nodiscard]] bool operator==(const resource &other) const noexcept { return (value == other.value); } /** * @brief Lexicographically compares two handles. * @tparam Other Type of resource managed by the other handle. * @param other A valid handle. * @return The relative order between the two handles. */ template [[nodiscard]] auto operator<=>(const resource &other) const noexcept { return (value <=> other.value); } /*! @brief Releases the ownership of the managed resource. */ void reset() { value.reset(); } /** * @brief Replaces the managed resource. * @param other A handle to a resource. */ void reset(handle_type other) { value = stl::move(other); } /** * @brief Returns the underlying resource handle. * @return The underlying resource handle. */ [[nodiscard]] handle_type handle() const noexcept { return value; } private: handle_type value; }; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template class resource_cache_iterator final { template friend class resource_cache_iterator; public: using value_type = stl::pair>; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr resource_cache_iterator() noexcept = default; constexpr resource_cache_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr resource_cache_iterator(const resource_cache_iterator, Other> &other) noexcept : it{other.it} {} constexpr resource_cache_iterator &operator++() noexcept { return ++it, *this; } constexpr resource_cache_iterator operator++(int) noexcept { const resource_cache_iterator orig = *this; return ++(*this), orig; } constexpr resource_cache_iterator &operator--() noexcept { return --it, *this; } constexpr resource_cache_iterator operator--(int) noexcept { const resource_cache_iterator orig = *this; return operator--(), orig; } constexpr resource_cache_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr resource_cache_iterator operator+(const difference_type value) const noexcept { resource_cache_iterator copy = *this; return (copy += value); } constexpr resource_cache_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr resource_cache_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].first, resource{it[value].second}}; } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const resource_cache_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const resource_cache_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const resource_cache_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; } // namespace internal /*! @endcond */ /** * @brief Basic cache for resources of any type. * @tparam Type Type of resources managed by a cache. * @tparam Loader Type of loader used to create the resources. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class resource_cache { using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v, "Invalid value type"); using container_allocator = alloc_traits::template rebind_alloc>; using container_type = dense_map, container_allocator>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Resource type. */ using value_type = Type; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Loader type. */ using loader_type = Loader; /*! @brief Input iterator type. */ using iterator = internal::resource_cache_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::resource_cache_iterator; /*! @brief Default constructor. */ resource_cache() : resource_cache{loader_type{}} {} /** * @brief Constructs an empty cache with a given allocator. * @param allocator The allocator to use. */ explicit resource_cache(const allocator_type &allocator) : resource_cache{loader_type{}, allocator} {} /** * @brief Constructs an empty cache with a given allocator and loader. * @param callable The loader to use. * @param allocator The allocator to use. */ explicit resource_cache(const loader_type &callable, const allocator_type &allocator = allocator_type{}) : pool{container_type{allocator}, callable} {} /*! @brief Default copy constructor. */ resource_cache(const resource_cache &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ resource_cache(const resource_cache &other, const allocator_type &allocator) : pool{stl::piecewise_construct, stl::forward_as_tuple(other.pool.first(), allocator), stl::forward_as_tuple(other.pool.second())} {} /*! @brief Default move constructor. */ resource_cache(resource_cache &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ resource_cache(resource_cache &&other, const allocator_type &allocator) : pool{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.pool.first()), allocator), stl::forward_as_tuple(stl::move(other.pool.second()))} {} /*! @brief Default destructor. */ ~resource_cache() = default; /** * @brief Default copy assignment operator. * @return This cache. */ resource_cache &operator=(const resource_cache &) = default; /** * @brief Default move assignment operator. * @return This cache. */ resource_cache &operator=(resource_cache &&) noexcept = default; /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return pool.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the cache is empty, the returned iterator will be equal to `end()`. * * @return An iterator to the first instance of the internal cache. */ [[nodiscard]] const_iterator cbegin() const noexcept { return pool.first().begin(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return pool.first().begin(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal cache. */ [[nodiscard]] const_iterator cend() const noexcept { return pool.first().end(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return pool.first().end(); } /** * @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 noexcept { return pool.first().empty(); } /** * @brief Number of resources managed by a cache. * @return Number of resources currently stored. */ [[nodiscard]] size_type size() const noexcept { return pool.first().size(); } /*! @brief Clears a cache. */ void clear() noexcept { pool.first().clear(); } /** * @brief Loads a resource, if its identifier does not exist. * * Arguments are forwarded directly to the loader and _consumed_ only if the * resource doesn't already exist. * * @warning * If the resource isn't loaded correctly, the returned handle could be * invalid and any use of it will result in undefined behavior. * * @tparam Args Types of arguments to use to load the resource if required. * @param id Unique resource identifier. * @param args Arguments to use to load the resource if required. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair load(const id_type id, Args &&...args) { if(auto it = pool.first().find(id); it != pool.first().end()) { return {it, false}; } return pool.first().emplace(id, pool.second()(stl::forward(args)...)); } /** * @brief Force loads a resource, even if its identifier already exists. * @copydetails load */ template stl::pair force_load(const id_type id, Args &&...args) { return {pool.first().insert_or_assign(id, pool.second()(stl::forward(args)...)).first, true}; } /** * @brief Returns a handle for a given resource identifier. * * @warning * There is no guarantee that the returned handle is valid.
* If it is not, any use will result in undefined behavior. * * @param id Unique resource identifier. * @return A handle for the given resource. */ [[nodiscard]] resource operator[](const id_type id) const { if(auto it = pool.first().find(id); it != pool.first().cend()) { return resource{it->second}; } return {}; } /*! @copydoc operator[] */ [[nodiscard]] resource operator[](const id_type id) { if(auto it = pool.first().find(id); it != pool.first().end()) { return resource{it->second}; } return {}; } /** * @brief Checks if a cache contains a given identifier. * @param id Unique resource identifier. * @return True if the cache contains the resource, false otherwise. */ [[nodiscard]] bool contains(const id_type id) const { return pool.first().contains(id); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto it = pool.first().begin(); return pool.first().erase(it + (pos - const_iterator{it})); } /** * @brief Removes the given elements from a cache. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto it = pool.first().begin(); return pool.first().erase(it + (first - const_iterator{it}), it + (last - const_iterator{it})); } /** * @brief Removes the given elements from a cache. * @param id Unique resource identifier. * @return Number of resources erased (either 0 or 1). */ size_type erase(const id_type id) { return pool.first().erase(id); } /** * @brief Returns the loader used to create resources. * @return The loader used to create resources. */ [[nodiscard]] loader_type loader() const { return pool.second(); } private: compressed_pair pool; }; } // namespace entt #endif // #include "resource/loader.hpp" #ifndef ENTT_RESOURCE_LOADER_HPP #define ENTT_RESOURCE_LOADER_HPP // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /** * @brief Transparent loader for shared resources. * @tparam Type Type of resources created by the loader. */ template struct resource_loader { /*! @brief Result type. */ using result_type = stl::shared_ptr; /** * @brief Constructs a shared pointer to a resource from its arguments. * @tparam Args Types of arguments to use to construct the resource. * @param args Parameters to use to construct the resource. * @return A shared pointer to a resource of the given type. */ template result_type operator()(Args &&...args) const { return stl::make_shared(stl::forward(args)...); } }; } // namespace entt #endif // #include "resource/resource.hpp" #ifndef ENTT_RESOURCE_RESOURCE_HPP #define ENTT_RESOURCE_RESOURCE_HPP #include // #include "../stl/concepts.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /** * @brief Basic resource handle. * * A handle wraps a resource and extends its lifetime. It also shares the same * resource with all other handles constructed from the same element.
* As a rule of thumb, resources should never be copied nor moved. Handles are * the way to go to push references around. * * @tparam Type Type of resource managed by a handle. */ template class resource { template friend class resource; public: /*! @brief Resource type. */ using element_type = Type; /*! @brief Handle type. */ using handle_type = stl::shared_ptr; /*! @brief Default constructor. */ resource() noexcept : value{} {} /** * @brief Creates a new resource handle. * @param res A handle to a resource. */ explicit resource(handle_type res) noexcept : value{stl::move(res)} {} /*! @brief Default copy constructor. */ resource(const resource &) noexcept = default; /*! @brief Default move constructor. */ resource(resource &&) noexcept = default; /** * @brief Aliasing constructor. * @tparam Other Type of resource managed by the received handle. * @param other The handle with which to share ownership information. * @param res Unrelated and unmanaged resources. */ template resource(const resource &other, element_type &res) noexcept : value{other.value, stl::addressof(res)} {} /** * @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 requires (!stl::same_as && stl::constructible_from) resource(const resource &other) noexcept : value{other.value} {} /** * @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 requires (!stl::same_as && stl::constructible_from) resource(resource &&other) noexcept : value{stl::move(other.value)} {} /*! @brief Default destructor. */ ~resource() = default; /** * @brief Default copy assignment operator. * @return This resource handle. */ resource &operator=(const resource &) noexcept = default; /** * @brief Default move assignment operator. * @return This resource handle. */ resource &operator=(resource &&) 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 requires (!stl::same_as && stl::constructible_from) resource &operator=(const resource &other) noexcept { value = other.value; 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 requires (!stl::same_as && stl::constructible_from) resource &operator=(resource &&other) noexcept { value = stl::move(other.value); return *this; } /** * @brief Exchanges the content with that of a given resource. * @param other Resource to exchange the content with. */ void swap(resource &other) noexcept { using stl::swap; swap(value, other.value); } /** * @brief Returns 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]] element_type &operator*() const noexcept { return *value; } /*! @copydoc operator* */ [[nodiscard]] operator element_type &() const noexcept { return *value; } /** * @brief Returns a pointer to the managed resource. * @return A pointer to the managed resource. */ [[nodiscard]] element_type *operator->() const noexcept { return value.get(); } /** * @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 noexcept { return static_cast(value); } /** * @brief Compares two handles. * @tparam Other Type of resource managed by the other handle. * @param other A valid handle. * @return True if both handles refer to the same resource, false otherwise. */ template [[nodiscard]] bool operator==(const resource &other) const noexcept { return (value == other.value); } /** * @brief Lexicographically compares two handles. * @tparam Other Type of resource managed by the other handle. * @param other A valid handle. * @return The relative order between the two handles. */ template [[nodiscard]] auto operator<=>(const resource &other) const noexcept { return (value <=> other.value); } /*! @brief Releases the ownership of the managed resource. */ void reset() { value.reset(); } /** * @brief Replaces the managed resource. * @param other A handle to a resource. */ void reset(handle_type other) { value = stl::move(other); } /** * @brief Returns the underlying resource handle. * @return The underlying resource handle. */ [[nodiscard]] handle_type handle() const noexcept { return value; } private: handle_type value; }; } // namespace entt #endif // #include "signal/delegate.hpp" #ifndef ENTT_SIGNAL_DELEGATE_HPP #define ENTT_SIGNAL_DELEGATE_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_SIGNAL_FWD_HPP #define ENTT_SIGNAL_FWD_HPP // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif namespace entt { template class delegate; template> class basic_dispatcher; template> class emitter; class connection; struct scoped_connection; template class sink; template> class sigh; /*! @brief Alias declaration for the most common use case. */ using dispatcher = basic_dispatcher<>; /*! @brief Disambiguation tag for constructors and the like. */ template struct connect_arg_t { /*! @brief Default constructor. */ explicit connect_arg_t() = default; }; /** * @brief Constant of type connect_arg_t used to disambiguate calls. * @tparam Candidate Element to connect (likely a free or member function). */ template inline constexpr connect_arg_t connect_arg{}; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ 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 requires stl::is_member_object_pointer_v auto function_pointer(Type Class::*, Other &&...) -> Type (*)(); template using function_pointer_t = decltype(function_pointer(stl::declval()...)); template [[nodiscard]] ENTT_CONSTEVAL auto index_sequence_for(Ret (*)(Args...)) { return stl::index_sequence_for{}; } } // namespace internal /*! @endcond */ /** * @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 { using return_type = stl::remove_const_t; using delegate_type = return_type(const void *, Args...); template [[nodiscard]] auto wrap(stl::index_sequence) noexcept { return [](const void *, Args... args) -> return_type { [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, stl::forward>>(stl::get(arguments))...)); }; } template [[nodiscard]] auto wrap(Type &, stl::index_sequence) noexcept { return [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, *curr, stl::forward>>(stl::get(arguments))...)); }; } template [[nodiscard]] auto wrap(Type *, stl::index_sequence) noexcept { return [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, curr, stl::forward>>(stl::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() noexcept = default; /** * @brief Constructs a delegate with a given object or payload, if any. * @tparam Candidate Function or member to connect to the delegate. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance Optional valid object that fits the purpose. */ template delegate(connect_arg_t, Type &&...value_or_instance) noexcept { connect(stl::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) 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() noexcept { instance = nullptr; if constexpr(stl::is_invocable_r_v) { fn = [](const void *, Args... args) -> return_type { return Ret(stl::invoke(Candidate, stl::forward(args)...)); }; } else if constexpr(stl::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) noexcept { instance = &value_or_instance; if constexpr(stl::is_invocable_r_v) { fn = [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); return Ret(stl::invoke(Candidate, *curr, stl::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) noexcept { instance = value_or_instance; if constexpr(stl::is_invocable_r_v) { fn = [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); return Ret(stl::invoke(Candidate, curr, stl::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) noexcept { ENTT_ASSERT(function != nullptr, "Uninitialized function pointer"); instance = payload; fn = function; } /** * @brief Resets a delegate. * * After a reset, a delegate cannot be invoked anymore. */ void reset() noexcept { instance = nullptr; fn = nullptr; } /** * @brief Returns a pointer to the stored callable function target, if any. * @return An opaque pointer to the stored callable function target. */ [[nodiscard]] function_type *target() const noexcept { return fn; } /** * @brief Returns the instance or the payload linked to a delegate, if any. * @return An opaque pointer to the underlying data. */ [[nodiscard]] const void *data() const noexcept { return instance; } /** * @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(instance, stl::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 noexcept { // no need to also test instance 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 noexcept { return fn == other.fn && instance == other.instance; } private: const void *instance{}; delegate_type *fn{}; }; /** * @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; } // namespace entt #endif // #include "signal/dispatcher.hpp" #ifndef ENTT_SIGNAL_DISPATCHER_HPP #define ENTT_SIGNAL_DISPATCHER_HPP // #include "../container/dense_map.hpp" #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP #include // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../core/bit.hpp" #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP // #include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /** * @brief Fast module utility function (powers of two only). * @tparam Type Unsigned integer type. * @param value A value of unsigned integer type. * @param mod _Modulus_, it must be a power of two. * @return The common remainder. */ template [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); return static_cast(value & (mod - 1u)); } } // namespace entt #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/iterator.hpp" #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Helper type to use as pointer with input iterators. * @tparam Type of wrapped value. */ template struct input_iterator_pointer final { /*! @brief Value type. */ using value_type = Type; /*! @brief Pointer type. */ using pointer = Type *; /*! @brief Reference type. */ using reference = Type &; /** * @brief Constructs a proxy object by move. * @param val Value to use to initialize the proxy object. */ constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) : value{stl::move(val)} {} /** * @brief Access operator for accessing wrapped values. * @return A pointer to the wrapped value. */ [[nodiscard]] constexpr pointer operator->() noexcept { return stl::addressof(value); } /** * @brief Dereference operator for accessing wrapped values. * @return A reference to the wrapped value. */ [[nodiscard]] constexpr reference operator*() noexcept { return value; } private: Type value; }; /** * @brief Plain iota iterator (waiting for C++20). * @tparam Type Value type. */ template struct iota_iterator final { /*! @brief Value type, likely an integral one. */ using value_type = Type; /*! @brief Invalid pointer type. */ using pointer = void; /*! @brief Non-reference type, same as value type. */ using reference = value_type; /*! @brief Difference type. */ using difference_type = stl::ptrdiff_t; /*! @brief Iterator category. */ using iterator_category = stl::input_iterator_tag; /*! @brief Default constructor. */ constexpr iota_iterator() noexcept : current{} {} /** * @brief Constructs an iota iterator from a given value. * @param init The initial value assigned to the iota iterator. */ constexpr iota_iterator(const value_type init) noexcept : current{init} {} /** * @brief Pre-increment operator. * @return This iota iterator. */ constexpr iota_iterator &operator++() noexcept { return ++current, *this; } /** * @brief Post-increment operator. * @return This iota iterator. */ constexpr iota_iterator operator++(int) noexcept { const iota_iterator orig = *this; return ++(*this), orig; } /** * @brief Dereference operator. * @return The underlying value. */ [[nodiscard]] constexpr reference operator*() const noexcept { return current; } /** * @brief Comparison operator. * @param other A properly initialized iota iterator. * @return True if the two iterators are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { return current == other.current; } private: value_type current; }; /** * @brief Utility class to create an iterable object from a pair of iterators. * @tparam It Type of iterator. * @tparam Sentinel Type of sentinel. */ template Sentinel = It> struct iterable_adaptor final { /*! @brief Value type. */ using value_type = stl::iterator_traits::value_type; /*! @brief Iterator type. */ using iterator = It; /*! @brief Sentinel type. */ using sentinel = Sentinel; /*! @brief Default constructor. */ constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) : first{}, last{} {} /** * @brief Creates an iterable object from a pair of iterators. * @param from Begin iterator. * @param to End iterator. */ constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) : first{stl::move(from)}, last{stl::move(to)} {} /** * @brief Returns an iterator to the beginning. * @return An iterator to the first element of the range. */ [[nodiscard]] constexpr iterator begin() const noexcept { return first; } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last element of the * range. */ [[nodiscard]] constexpr sentinel end() const noexcept { return last; } /*! @copydoc begin */ [[nodiscard]] constexpr iterator cbegin() const noexcept { return begin(); } /*! @copydoc end */ [[nodiscard]] constexpr sentinel cend() const noexcept { return end(); } private: It first; Sentinel last; }; } // namespace entt #endif // #include "../core/memory.hpp" #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" namespace entt { /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { lhs = rhs; } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { lhs = stl::move(rhs); } } /** * @brief Utility function to design allocation-aware containers. * @tparam Allocator Type of allocator. * @param lhs A valid allocator. * @param rhs Another valid allocator. */ template constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { using stl::swap; swap(lhs, rhs); } else { ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); } } /** * @brief Deleter for allocator-aware unique pointers (waiting for C++20). * @tparam Allocator Type of allocator used to manage memory and elements. */ template struct allocation_deleter: private Allocator { /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Pointer type. */ using pointer = stl::allocator_traits::pointer; /** * @brief Inherited constructors. * @param alloc The allocator to use. */ constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) : Allocator{alloc} {} /** * @brief Destroys the pointed object and deallocates its memory. * @param ptr A valid pointer to an object of the given type. */ constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { using alloc_traits = stl::allocator_traits; alloc_traits::destroy(*this, stl::to_address(ptr)); alloc_traits::deallocate(*this, ptr, 1u); } }; /** * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). * @tparam Type Type of object to allocate for and to construct. * @tparam Allocator Type of allocator used to manage memory and elements. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A properly initialized unique pointer with a custom deleter. */ template constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { static_assert(!stl::is_array_v, "Array types are not supported"); using alloc_traits = stl::allocator_traits::template rebind_traits; using allocator_type = alloc_traits::allocator_type; allocator_type alloc{allocator}; auto ptr = alloc_traits::allocate(alloc, 1u); ENTT_TRY { alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); } ENTT_CATCH { alloc_traits::deallocate(alloc, ptr, 1u); ENTT_THROW; } return stl::unique_ptr>{ptr, alloc}; } /*! @cond ENTT_INTERNAL */ namespace internal { template struct uses_allocator_construction { template static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { return stl::forward_as_tuple(stl::forward(params)...); } else { static_assert(stl::uses_allocator_v, "Ill-formed request"); if constexpr(stl::is_constructible_v) { return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; } else { static_assert(stl::is_constructible_v, "Ill-formed request"); return stl::forward_as_tuple(stl::forward(params)..., allocator); } } } }; template struct uses_allocator_construction> { using type = stl::pair; template static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { return stl::make_tuple( stl::piecewise_construct, stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); } static constexpr auto args(const auto &allocator) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); } template static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); } template static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); } template static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); } }; } // namespace internal /*! @endcond */ /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Prepares the argument list needed to * create an object of a given type by means of uses-allocator construction. * * @tparam Type Type to return arguments for. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return The arguments needed to create an object of the given type. */ template constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A newly created object of the given type. */ template constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } /** * @brief Uses-allocator construction utility (waiting for C++20). * * Primarily intended for internal use. Creates an object of a given type by * means of uses-allocator construction at an uninitialized memory location. * * @tparam Type Type of object to create. * @tparam Args Types of arguments to use to construct the object. * @param value Memory location in which to place the object. * @param allocator The allocator to use. * @param args Parameters to use to construct the object. * @return A pointer to the newly created object of the given type. */ template constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } } // namespace entt #endif // #include "../core/type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif // #include "../stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "../stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "../stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "../stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" namespace entt { template< typename Key, typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator>> class dense_map; template< typename Type, typename = stl::hash, typename = stl::equal_to<>, typename = stl::allocator> class dense_set; template class basic_table; /** * @brief Alias declaration for the most common use case. * @tparam Type Element types. */ template using table = basic_table...>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { using value_type = stl::pair; template dense_map_node(const stl::size_t pos, Args &&...args) : next{pos}, element{stl::forward(args)...} {} template dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) : next{pos}, element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, other.element)} {} dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) : next{other.next}, element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} stl::size_t next; value_type element; }; template class dense_map_iterator final { template friend class dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::random_access_iterator_tag; constexpr dense_map_iterator() noexcept : it{} {} constexpr dense_map_iterator(const It iter) noexcept : it{iter} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_iterator(const dense_map_iterator &other) noexcept : it{other.it} {} constexpr dense_map_iterator &operator++() noexcept { return ++it, *this; } constexpr dense_map_iterator operator++(int) noexcept { const dense_map_iterator orig = *this; return ++(*this), orig; } constexpr dense_map_iterator &operator--() noexcept { return --it, *this; } constexpr dense_map_iterator operator--(int) noexcept { const dense_map_iterator orig = *this; return operator--(), orig; } constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { it += value; return *this; } constexpr dense_map_iterator operator+(const difference_type value) const noexcept { dense_map_iterator copy = *this; return (copy += value); } constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { return (*this += -value); } constexpr dense_map_iterator operator-(const difference_type value) const noexcept { return (*this + -value); } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { return {it[value].element.first, it[value].element.second}; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { return operator[](0); } template [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { return it - other.it; } template [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { return it == other.it; } template [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { return it <=> other.it; } private: It it; }; template class dense_map_local_iterator final { template friend class dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); using second_type = decltype((stl::declval()->element.second)); public: using value_type = stl::pair; using pointer = input_iterator_pointer; using reference = value_type; using difference_type = stl::ptrdiff_t; using iterator_category = stl::input_iterator_tag; using iterator_concept = stl::forward_iterator_tag; constexpr dense_map_local_iterator() noexcept = default; constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept : it{iter}, offset{pos} {} template requires (!stl::same_as && stl::constructible_from) constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept : it{other.it}, offset{other.offset} {} constexpr dense_map_local_iterator &operator++() noexcept { return (offset = it[static_cast(offset)].next), *this; } constexpr dense_map_local_iterator operator++(int) noexcept { const dense_map_local_iterator orig = *this; return ++(*this), orig; } [[nodiscard]] constexpr pointer operator->() const noexcept { return operator*(); } [[nodiscard]] constexpr reference operator*() const noexcept { const auto idx = static_cast(offset); return {it[idx].element.first, it[idx].element.second}; } template [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { return offset == other.offset; } [[nodiscard]] constexpr stl::size_t index() const noexcept { return offset; } private: It it{}; stl::size_t offset{dense_map_placeholder_position}; }; } // namespace internal /*! @endcond */ /** * @brief Associative container for key-value pairs with unique keys. * * Internally, elements are organized into buckets. Which bucket an element is * placed into depends entirely on the hash of its key. Keys with the same hash * code appear in the same bucket. * * @tparam Key Key type of the associative container. * @tparam Type Mapped type of the associative container. * @tparam Hash Type of function to use to hash the keys. * @tparam KeyEqual Type of function to use to compare the keys for equality. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class dense_map { static constexpr float default_threshold = 0.875f; static constexpr stl::size_t minimum_capacity = 8u; static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; using node_type = internal::dense_map_node; using alloc_traits = stl::allocator_traits; static_assert(stl::is_same_v>, "Invalid value type"); using sparse_container_type = stl::vector>; using packed_container_type = stl::vector>; [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) return fast_mod(static_cast(sparse.second()(key)), bucket_count()); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return begin() + static_cast(offset); } } return end(); } [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { if(packed.second()(packed.first()[offset].element.first, key)) { return cbegin() + static_cast(offset); } } return cend(); } template [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } template [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { const auto index = key_to_bucket(key); if(auto it = constrained_find(key, index); it != end()) { it->second = stl::forward(value); return stl::make_pair(it, false); } packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); sparse.first()[index] = packed.first().size() - 1u; rehash_if_required(); return stl::make_pair(--end(), true); } void move_and_pop(const stl::size_t pos) { if(const auto last = size() - 1u; pos != last) { size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; packed.first()[pos] = stl::move(packed.first().back()); for(; *curr != last; curr = &packed.first()[*curr].next) {} *curr = pos; } packed.first().pop_back(); } void rehash_if_required() { if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { rehash(bc * 2u); } } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Key type of the container. */ using key_type = Key; /*! @brief Mapped type of the container. */ using mapped_type = Type; /*! @brief Key-value type of the container. */ using value_type = stl::pair; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Signed integer type. */ using difference_type = stl::ptrdiff_t; /*! @brief Type of function to use to hash the keys. */ using hasher = Hash; /*! @brief Type of function to use to compare the keys for equality. */ using key_equal = KeyEqual; /*! @brief Input iterator type. */ using iterator = internal::dense_map_iterator; /*! @brief Constant input iterator type. */ using const_iterator = internal::dense_map_iterator; /*! @brief Input iterator type. */ using local_iterator = internal::dense_map_local_iterator; /*! @brief Constant input iterator type. */ using const_local_iterator = internal::dense_map_local_iterator; /*! @brief Default constructor. */ dense_map() : dense_map{minimum_capacity} {} /** * @brief Constructs an empty container with a given allocator. * @param allocator The allocator to use. */ explicit dense_map(const allocator_type &allocator) : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator and user * supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const allocator_type &allocator) : dense_map{cnt, hasher{}, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param allocator The allocator to use. */ dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) : dense_map{cnt, hash, key_equal{}, allocator} {} /** * @brief Constructs an empty container with a given allocator, hash * function, compare function and user supplied minimal number of buckets. * @param cnt Minimal number of buckets. * @param hash Hash function to use. * @param equal Compare function to use. * @param allocator The allocator to use. */ explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) : sparse{allocator, hash}, packed{allocator, equal} { rehash(cnt); } /*! @brief Default copy constructor. */ dense_map(const dense_map &) = default; /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ dense_map(const dense_map &other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, threshold{other.threshold} {} /*! @brief Default move constructor. */ dense_map(dense_map &&) noexcept = default; /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ dense_map(dense_map &&other, const allocator_type &allocator) : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, threshold{other.threshold} {} /*! @brief Default destructor. */ ~dense_map() = default; /** * @brief Default copy assignment operator. * @return This container. */ dense_map &operator=(const dense_map &) = default; /** * @brief Default move assignment operator. * @return This container. */ dense_map &operator=(dense_map &&) noexcept = default; /** * @brief Exchanges the contents with those of a given container. * @param other Container to exchange the content with. */ void swap(dense_map &other) noexcept { using stl::swap; swap(sparse, other.sparse); swap(packed, other.packed); swap(threshold, other.threshold); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return sparse.first().get_allocator(); } /** * @brief Returns an iterator to the beginning. * * If the array 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 noexcept { return packed.first().data(); } /*! @copydoc cbegin */ [[nodiscard]] const_iterator begin() const noexcept { return cbegin(); } /*! @copydoc begin */ [[nodiscard]] iterator begin() noexcept { return packed.first().data(); } /** * @brief Returns an iterator to the end. * @return An iterator to the element following the last instance of the * internal array. */ [[nodiscard]] const_iterator cend() const noexcept { return packed.first().data() + packed.first().size(); } /*! @copydoc cend */ [[nodiscard]] const_iterator end() const noexcept { return cend(); } /*! @copydoc end */ [[nodiscard]] iterator end() noexcept { return packed.first().data() + packed.first().size(); } /** * @brief Checks whether a container is empty. * @return True if the container is empty, false otherwise. */ [[nodiscard]] bool empty() const noexcept { return packed.first().empty(); } /** * @brief Returns the number of elements in a container. * @return Number of elements in a container. */ [[nodiscard]] size_type size() const noexcept { return packed.first().size(); } /** * @brief Returns the maximum possible number of elements. * @return Maximum possible number of elements. */ [[nodiscard]] size_type max_size() const noexcept { return packed.first().max_size(); } /*! @brief Clears the container. */ void clear() noexcept { sparse.first().clear(); packed.first().clear(); rehash(0u); } /** * @brief Inserts an element into the container, if the key does not exist. * @param value A key-value pair eventually convertible to the value type. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ stl::pair insert(const value_type &value) { return insert_or_do_nothing(value.first, value.second); } /*! @copydoc insert */ stl::pair insert(value_type &&value) { return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); } /** * @copydoc insert * @tparam Arg Type of the key-value pair to insert into the container. */ template requires stl::constructible_from stl::pair insert(Arg &&value) { return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); } /** * @brief Inserts elements into the container, if their keys do not exist. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. */ void insert(stl::input_iterator auto first, stl::input_iterator auto last) { for(; first != last; ++first) { insert(*first); } } /** * @brief Inserts an element into the container or assigns to the current * element if the key already exists. * @tparam Arg Type of the value to insert or assign. * @param key A key used both to look up and to insert if not found. * @param value A value to insert or assign. * @return A pair consisting of an iterator to the element and a bool * denoting whether the insertion took place. */ template stl::pair insert_or_assign(const key_type &key, Arg &&value) { return insert_or_overwrite(key, stl::forward(value)); } /*! @copydoc insert_or_assign */ template stl::pair insert_or_assign(key_type &&key, Arg &&value) { return insert_or_overwrite(stl::move(key), stl::forward(value)); } /** * @brief Constructs an element in-place, if the key does not exist. * * The element is also constructed when the container already has the key, * in which case the newly constructed object is destroyed immediately. * * @tparam Args Types of arguments to forward to the constructor of the * element. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair emplace([[maybe_unused]] Args &&...args) { if constexpr(sizeof...(Args) == 0u) { return insert_or_do_nothing(key_type{}); } else if constexpr(sizeof...(Args) == 1u) { return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); } else if constexpr(sizeof...(Args) == 2u) { return insert_or_do_nothing(stl::forward(args)...); } else { auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); const auto index = key_to_bucket(node.element.first); if(auto it = constrained_find(node.element.first, index); it != end()) { packed.first().pop_back(); return stl::make_pair(it, false); } stl::swap(node.next, sparse.first()[index]); rehash_if_required(); return stl::make_pair(--end(), true); } } /** * @brief Inserts in-place if the key does not exist, does nothing if the * key exists. * @tparam Args Types of arguments to forward to the constructor of the * element. * @param key A key used both to look up and to insert if not found. * @param args Arguments to forward to the constructor of the element. * @return A pair consisting of an iterator to the inserted element (or to * the element that prevented the insertion) and a bool denoting whether the * insertion took place. */ template stl::pair try_emplace(const key_type &key, Args &&...args) { return insert_or_do_nothing(key, stl::forward(args)...); } /*! @copydoc try_emplace */ template stl::pair try_emplace(key_type &&key, Args &&...args) { return insert_or_do_nothing(stl::move(key), stl::forward(args)...); } /** * @brief Removes an element from a given position. * @param pos An iterator to the element to remove. * @return An iterator following the removed element. */ iterator erase(const_iterator pos) { const auto diff = pos - cbegin(); erase(pos->first); return begin() + diff; } /** * @brief Removes the given elements from a container. * @param first An iterator to the first element of the range of elements. * @param last An iterator past the last element of the range of elements. * @return An iterator following the last removed element. */ iterator erase(const_iterator first, const_iterator last) { const auto dist = first - cbegin(); for(auto from = last - cbegin(); from != dist; --from) { erase(packed.first()[static_cast(from) - 1u].element.first); } return (begin() + dist); } /** * @brief Removes the element associated with a given key. * @param key A key value of an element to remove. * @return Number of elements removed (either 0 or 1). */ size_type erase(const key_type &key) { for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { if(packed.second()(packed.first()[*curr].element.first, key)) { const auto index = *curr; *curr = packed.first()[*curr].next; move_and_pop(index); return 1u; } } return 0u; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &at(const key_type &key) { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] const mapped_type &at(const key_type &key) const { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /** * @brief Accesses a given element with bounds checking. * @param key A key of an element to find. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type const &at(const auto &key) const requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != cend(), "Invalid key"); return it->second; } /*! @copydoc at */ [[nodiscard]] mapped_type &at(const auto &key) requires is_transparent_v && is_transparent_v { auto it = find(key); ENTT_ASSERT(it != end(), "Invalid key"); return it->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](const key_type &key) { return insert_or_do_nothing(key).first->second; } /** * @brief Accesses or inserts a given element. * @param key A key of an element to find or insert. * @return A reference to the mapped value of the requested element. */ [[nodiscard]] mapped_type &operator[](key_type &&key) { return insert_or_do_nothing(stl::move(key)).first->second; } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const key_type &key) const { return find(key) != end(); } /** * @brief Returns the number of elements matching a key (either 1 or 0). * @param key Key value of an element to search for. * @return Number of elements matching the key (either 1 or 0). */ [[nodiscard]] size_type count(const auto &key) const requires is_transparent_v && is_transparent_v { return find(key) != end(); } /** * @brief Finds an element with a given key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const key_type &key) { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const key_type &key) const { return constrained_find(key, key_to_bucket(key)); } /** * @brief Finds an element with a key that compares _equivalent_ to a given * key. * @param key Key value of an element to search for. * @return An iterator to an element with the given key. If no such element * is found, a past-the-end iterator is returned. */ [[nodiscard]] iterator find(const auto &key) requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /*! @copydoc find */ [[nodiscard]] const_iterator find(const auto &key) const requires is_transparent_v && is_transparent_v { return constrained_find(key, key_to_bucket(key)); } /** * @brief Returns a range containing all elements with a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const key_type &key) { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const key_type &key) const { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Returns a range containing all elements that compare _equivalent_ * to a given key. * @param key Key value of an element to search for. * @return A pair of iterators pointing to the first element and past the * last element of the range. */ [[nodiscard]] stl::pair equal_range(const auto &key) requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == end())}; } /*! @copydoc equal_range */ [[nodiscard]] stl::pair equal_range(const auto &key) const requires is_transparent_v && is_transparent_v { const auto it = find(key); return {it, it + !(it == cend())}; } /** * @brief Checks if the container contains an element with a given key. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const key_type &key) const { return (find(key) != cend()); } /** * @brief Checks if the container contains an element with a key that * compares _equivalent_ to a given value. * @param key Key value of an element to search for. * @return True if there is such an element, false otherwise. */ [[nodiscard]] bool contains(const auto &key) const requires is_transparent_v && is_transparent_v { return (find(key) != cend()); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator cbegin(const size_type index) const { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] const_local_iterator begin(const size_type index) const { return cbegin(index); } /** * @brief Returns an iterator to the beginning of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the beginning of the given bucket. */ [[nodiscard]] local_iterator begin(const size_type index) { return {packed.first().data(), sparse.first()[index]}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { return {}; } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] const_local_iterator end(const size_type index) const { return cend(index); } /** * @brief Returns an iterator to the end of a given bucket. * @param index An index of a bucket to access. * @return An iterator to the end of the given bucket. */ [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { return {}; } /** * @brief Returns the number of buckets. * @return The number of buckets. */ [[nodiscard]] size_type bucket_count() const { return sparse.first().size(); } /** * @brief Returns the maximum number of buckets. * @return The maximum number of buckets. */ [[nodiscard]] size_type max_bucket_count() const { return sparse.first().max_size(); } /** * @brief Returns the number of elements in a given bucket. * @param index The index of the bucket to examine. * @return The number of elements in the given bucket. */ [[nodiscard]] size_type bucket_size(const size_type index) const { return static_cast(stl::distance(begin(index), end(index))); } /** * @brief Returns the bucket for a given key. * @param key The value of the key to examine. * @return The bucket for the given key. */ [[nodiscard]] size_type bucket(const key_type &key) const { return key_to_bucket(key); } /** * @brief Returns the average number of elements per bucket. * @return The average number of elements per bucket. */ [[nodiscard]] float load_factor() const { return static_cast(size()) / static_cast(bucket_count()); } /** * @brief Returns the maximum average number of elements per bucket. * @return The maximum average number of elements per bucket. */ [[nodiscard]] float max_load_factor() const { return threshold; } /** * @brief Sets the desired maximum average number of elements per bucket. * @param value A desired maximum average number of elements per bucket. */ void max_load_factor(const float value) { ENTT_ASSERT(value > 0.f, "Invalid load factor"); threshold = value; rehash(0u); } /** * @brief Reserves at least the specified number of buckets and regenerates * the hash table. * @param cnt New number of buckets. */ void rehash(const size_type cnt) { auto value = cnt > minimum_capacity ? cnt : minimum_capacity; const auto cap = static_cast(static_cast(size()) / max_load_factor()); value = value > cap ? value : cap; if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { sparse.first().resize(sz); for(auto &&elem: sparse.first()) { elem = placeholder_position; } for(size_type pos{}, last = size(); pos < last; ++pos) { const auto index = key_to_bucket(packed.first()[pos].element.first); packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); } } } /** * @brief Reserves space for at least the specified number of elements and * regenerates the hash table. * @param cnt New number of elements. */ void reserve(const size_type cnt) { packed.first().reserve(cnt); rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); } /** * @brief Returns the function used to hash the keys. * @return The function used to hash the keys. */ [[nodiscard]] hasher hash_function() const { return sparse.second(); } /** * @brief Returns the function used to compare keys for equality. * @return The function used to compare keys for equality. */ [[nodiscard]] key_equal key_eq() const { return packed.second(); } private: compressed_pair sparse; compressed_pair packed; float threshold{default_threshold}; }; } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct uses_allocator, Allocator> : entt::stl::true_type {}; } // namespace std /*! @endcond */ #endif // #include "../core/compressed_pair.hpp" #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "type_traits.hpp" #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP // #include "../config/config.h" // #include "../stl/concepts.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/iterator.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #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 ENTT_INTERNAL */ 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 A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. * @tparam Type The type of which to return the size. */ template struct size_of: stl::integral_constant {}; /*! @copydoc size_of */ template requires requires { sizeof(Type); } struct size_of // NOLINTNEXTLINE(bugprone-sizeof-expression) : stl::integral_constant {}; /** * @brief Helper variable template. * @tparam Type The type of which to return the size. */ template inline constexpr stl::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_type = 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_value = Value; /** * @brief Wraps a static constant. * @tparam Value A static constant. */ template using integral_constant = stl::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 First 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 First 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 = First; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Type list to search into. */ template using type_list_element_t = type_list_element::type; /*! @brief Primary template isn't defined on purpose. */ template struct type_list_index; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam First First type provided by the type list. * @tparam Other Other types provided by the type list. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 1u + type_list_index>::value; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. * @tparam Other Other types provided by the type list. */ template requires (type_list_index>::value == sizeof...(Other)) struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the types of a type list. * @tparam Type Type to look for and for which to return the index. */ template struct type_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Type list. * @tparam Type Type to look for and for which to return the index. */ template inline constexpr stl::size_t type_list_index_v = type_list_index::value; /** * @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 ENTT_CONSTEVAL 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 = 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 = type_list_cat::type; /*! @cond ENTT_INTERNAL */ namespace internal { template struct type_list_unique; template struct type_list_unique, Type...> : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; template struct type_list_unique, Type...> { using type = type_list; }; } // namespace internal /*! @endcond */ /** * @brief Removes duplicates types from a type list. * @tparam List Type list. */ template struct type_list_unique { /*! @brief A type list without duplicate types. */ using type = internal::type_list_unique::type; }; /** * @brief Helper type. * @tparam List Type list. */ template using type_list_unique_t = type_list_unique::type; /** * @brief Provides the member constant `value` equal 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> : stl::bool_constant<(stl::is_same_v || ...)> {}; /** * @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 = type_list_diff::type; /*! @brief Primary template isn't defined on purpose. */ template class> struct type_list_transform; /** * @brief Applies a given _function_ to a type list and generates a new list. * @tparam Type Types provided by the type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> struct type_list_transform, Op> { /*! @brief Resulting type list after applying the transform function. */ // NOLINTNEXTLINE(modernize-type-traits) using type = type_list::type...>; }; /** * @brief Helper type. * @tparam List Type list. * @tparam Op Unary operation as template class with a type member named `type`. */ template class Op> using type_list_transform_t = type_list_transform::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 type. */ using type = decltype(Value); /*! @brief Searched value. */ static constexpr auto value = Value; }; /** * @brief Helper type. * @tparam Index Index of the type to return. * @tparam List Value list to search into. */ template using value_list_element_t = value_list_element::type; /** * @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 Primary template isn't defined on purpose. */ template struct value_list_index; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam First First value provided by the value list. * @tparam Other Other values provided by the value list. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 1u + value_list_index>::value; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. * @tparam Other Other values provided by the value list. */ template requires (value_list_index>::value == sizeof...(Other)) struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given value in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Provides compile-time type access to the values of a value list. * @tparam Value Value to look for and for which to return the index. */ template struct value_list_index> { /*! @brief Unsigned integer type. */ using value_type = stl::size_t; /*! @brief Compile-time position of the given type in the sublist. */ static constexpr value_type value = 0u; }; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for and for which to return the index. */ template inline constexpr stl::size_t value_list_index_v = value_list_index::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 ENTT_CONSTEVAL 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 = 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 = value_list_cat::type; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_unique; /** * @brief Removes duplicates values from a value list. * @tparam Value One of the values provided by the given value list. * @tparam Other The other values provided by the given value list. */ template struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = stl::conditional_t< ((Value == Other) || ...), typename value_list_unique>::type, value_list_cat_t, typename value_list_unique>::type>>; }; /*! @brief Removes duplicates values from a value list. */ template<> struct value_list_unique> { /*! @brief A value list without duplicate types. */ using type = value_list<>; }; /** * @brief Helper type. * @tparam Type A value list. */ template using value_list_unique_t = value_list_unique::type; /** * @brief Provides the member constant `value` equal to true if a value list * contains a given value, false otherwise. * @tparam List Value list. * @tparam Value Value to look for. */ template struct value_list_contains; /** * @copybrief value_list_contains * @tparam Value Values provided by the value list. * @tparam Other Value to look for. */ template struct value_list_contains, Other> : stl::bool_constant<((Value == Other) || ...)> {}; /** * @brief Helper variable template. * @tparam List Value list. * @tparam Value Value to look for. */ template inline constexpr bool value_list_contains_v = value_list_contains::value; /*! @brief Primary template isn't defined on purpose. */ template struct value_list_diff; /** * @brief Computes the difference between two value lists. * @tparam Value Values provided by the first value list. * @tparam Other Values provided by the second value list. */ template struct value_list_diff, value_list> { /*! @brief A value list that is the difference between the two lists. */ using type = value_list_cat_t, Value>, value_list<>, value_list>...>; }; /** * @brief Helper type. * @tparam List Value lists between which to compute the difference. */ template using value_list_diff_t = value_list_diff::type; /*! @brief Same as stl::is_invocable, but with tuples. */ template struct is_applicable: stl::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>: stl::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>: stl::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 stl::is_invocable_r, but with tuples for arguments. */ template struct is_applicable_r: stl::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>: stl::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` equal to true if a given type is * complete, false otherwise. * @tparam Type The type to test. */ template struct is_complete: stl::false_type {}; /*! @copydoc is_complete */ template requires requires { sizeof(Type); } struct is_complete: stl::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` equal to true if a given type is * an iterator, false otherwise. * @tparam Type The type to test. */ template struct is_iterator: stl::false_type {}; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_iterator_category: stl::false_type {}; template requires requires { typename stl::iterator_traits::iterator_category; } struct has_iterator_category: stl::true_type {}; } // namespace internal /*! @endcond */ /*! @copydoc is_iterator */ template requires (!stl::is_void_v>>) struct is_iterator: internal::has_iterator_category {}; /** * @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` equal to true if a given type is * both an empty and non-final class, false otherwise. * @tparam Type The type to test */ template struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; /** * @brief Provides the member constant `value` equal to true if * `Type::is_transparent` is valid and denotes a type, false otherwise. * @tparam Type The type to test. */ template struct is_transparent: stl::false_type {}; /*! @copydoc is_transparent */ template requires requires { typename Type::is_transparent; } struct is_transparent: stl::true_type {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_transparent_v = is_transparent::value; /*! @cond ENTT_INTERNAL */ namespace internal { template struct has_tuple_size_value: stl::false_type {}; template requires is_complete_v> struct has_tuple_size_value: stl::true_type {}; template struct has_value_type: stl::false_type {}; template requires requires { typename Type::value_type; } struct has_value_type: stl::true_type {}; template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); template [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { return (dispatch_is_equality_comparable>() && ...); } template [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; } template [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { return true; } template [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { // NOLINTBEGIN(modernize-use-transparent-functors) if constexpr(stl::is_array_v) { return false; } else if constexpr(is_complete_v>>) { if constexpr(has_tuple_size_value::value) { return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); } else { return maybe_equality_comparable(0); } } else if constexpr(has_value_type::value) { if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { return maybe_equality_comparable(0); } else { return false; } } else { return maybe_equality_comparable(0); } // NOLINTEND(modernize-use-transparent-functors) } } // namespace internal /*! @endcond */ /** * @brief Provides the member constant `value` equal to true if a given type is * equality comparable, false otherwise. * @tparam Type The type to test. */ template struct is_equality_comparable: stl::bool_constant()> {}; /*! @copydoc is_equality_comparable */ template struct is_equality_comparable: is_equality_comparable {}; /** * @brief Helper variable template. * @tparam Type The type to test. */ template inline constexpr bool is_equality_comparable_v = is_equality_comparable::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 = stl::remove_const_t; }; /*! @copydoc constness_as */ template struct constness_as { /*! @brief The type resulting from the transcription of the constness. */ using type = const To; }; /** * @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 = constness_as::type; /*! @brief Primary template isn't defined on purpose. */ template class member_class; /** * @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 requires stl::is_member_pointer_v class member_class { 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 = stl::remove_pointer_t()))>; }; /** * @brief Helper type. * @tparam Member A pointer to a non-static member object or function. */ template using member_class_t = member_class::type; /** * @brief Extracts the n-th argument of a _callable_ type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid _callable_ type. */ template class nth_argument { template static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); template static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); template static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); template static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); public: /*! @brief N-th argument of the _callable_ type. */ using type = type_list_element_t()))>; }; /** * @brief Helper type. * @tparam Index The index of the argument to extract. * @tparam Candidate A valid function, member function or data member type. */ template using nth_argument_t = nth_argument::type; } // namespace entt template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::type_list_element> {}; template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; template struct entt::stl::tuple_element>: entt::value_list_element> {}; #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct compressed_pair_element { using reference = Type &; using const_reference = const Type &; // NOLINTNEXTLINE(modernize-use-equals-default) constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : value{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : value{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return value; } [[nodiscard]] constexpr const_reference get() const noexcept { return value; } private: Type value{}; }; template requires is_ebco_eligible_v struct compressed_pair_element: Type { using reference = Type &; using const_reference = const Type &; using base_type = Type; constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) requires stl::default_initializable : base_type{} {} template constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) requires (!stl::same_as, compressed_pair_element>) : base_type{stl::forward(arg)} {} template constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) : base_type{stl::forward(stl::get(args))...} {} [[nodiscard]] constexpr reference get() noexcept { return *this; } [[nodiscard]] constexpr const_reference get() const noexcept { return *this; } }; } // namespace internal /*! @endcond */ /** * @brief A compressed pair. * * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to * reduce its final size to a minimum. * * @tparam First The type of the first element that the pair stores. * @tparam Second The type of the second element that the pair stores. */ template class compressed_pair final : internal::compressed_pair_element, internal::compressed_pair_element { using first_base = internal::compressed_pair_element; using second_base = internal::compressed_pair_element; public: /*! @brief The type of the first element that the pair stores. */ using first_type = First; /*! @brief The type of the second element that the pair stores. */ using second_type = Second; /** * @brief Default constructor, conditionally enabled. * * This constructor is only available when the types that the pair stores * are both at least default constructible. */ constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) requires stl::default_initializable && stl::default_initializable : first_base{}, second_base{} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ constexpr compressed_pair(const compressed_pair &other) = default; /** * @brief Move constructor. * @param other The instance to move from. */ constexpr compressed_pair(compressed_pair &&other) noexcept = default; /** * @brief Constructs a pair from its values. * @tparam Arg Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. * @param arg Value to use to initialize the first element. * @param other Value to use to initialize the second element. */ template constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::forward(arg)}, second_base{stl::forward(other)} {} /** * @brief Constructs a pair by forwarding the arguments to its parts. * @tparam Args Types of arguments to use to initialize the first element. * @tparam Other Types of arguments to use to initialize the second element. * @param args Arguments to use to initialize the first element. * @param other Arguments to use to initialize the second element. */ template constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) : first_base{stl::move(args), stl::index_sequence_for{}}, second_base{stl::move(other), stl::index_sequence_for{}} {} /*! @brief Default destructor. */ ~compressed_pair() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(const compressed_pair &other) = default; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This compressed pair object. */ constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; /** * @brief Returns the first element that a pair stores. * @return The first element that a pair stores. */ [[nodiscard]] constexpr first_type &first() noexcept { return static_cast(*this).get(); } /*! @copydoc first */ [[nodiscard]] constexpr const first_type &first() const noexcept { return static_cast(*this).get(); } /** * @brief Returns the second element that a pair stores. * @return The second element that a pair stores. */ [[nodiscard]] constexpr second_type &second() noexcept { return static_cast(*this).get(); } /*! @copydoc second */ [[nodiscard]] constexpr const second_type &second() const noexcept { return static_cast(*this).get(); } /** * @brief Swaps two compressed pair objects. * @param other The compressed pair to swap with. */ constexpr void swap(compressed_pair &other) noexcept { using stl::swap; swap(first(), other.first()); swap(second(), other.second()); } /** * @brief Extracts an element from the compressed pair. * @tparam Index An integer value that is either 0 or 1. * @return Returns a reference to the first element if `Index` is 0 and a * reference to the second element if `Index` is 1. */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } /*! @copydoc get */ template requires (Index <= 1u) [[nodiscard]] constexpr decltype(auto) get() const noexcept { if constexpr(Index == 0u) { return first(); } else { return second(); } } }; /** * @brief Deduction guide. * @tparam Type Type of value to use to initialize the first element. * @tparam Other Type of value to use to initialize the second element. */ template compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; /** * @brief Swaps two compressed pair objects. * @tparam First The type of the first element that the pairs store. * @tparam Second The type of the second element that the pairs store. * @param lhs A valid compressed pair object. * @param rhs A valid compressed pair object. */ template constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { lhs.swap(rhs); } } // namespace entt /*! @cond ENTT_INTERNAL */ #include namespace std { template struct tuple_size>: integral_constant {}; template requires (Index <= 1u) struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ #endif // #include "../core/concepts.hpp" #ifndef ENTT_CORE_CONCEPTS_HPP #define ENTT_CORE_CONCEPTS_HPP // #include "../stl/type_traits.hpp" namespace entt { /** * @brief Specifies that a type is not a cv-qualified reference. * @tparam Type Type to check. */ template concept cvref_unqualified = stl::is_same_v, Type>; } // namespace entt #endif // #include "../core/fwd.hpp" #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP // #include "../config/config.h" // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" namespace entt { /*! @brief Possible modes of an any object. */ enum class any_policy : stl::uint8_t { /*! @brief Default mode, no element available. */ empty, /*! @brief Owning mode, dynamically allocated element. */ dynamic, /*! @brief Owning mode, embedded element. */ embedded, /*! @brief Aliasing mode, non-const reference. */ ref, /*! @brief Const aliasing mode, const reference. */ cref }; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) 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<>; template class compressed_pair; template class basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_string = basic_hashed_string; /*! @brief Aliases for common character types. */ using hashed_wstring = basic_hashed_string; // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) struct type_info; } // namespace entt #endif // #include "../core/type_info.hpp" #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP #include // #include "../config/config.h" // #include "../stl/string_view.hpp" #ifndef ENTT_STL_STRING_VIEW_HPP #define ENTT_STL_STRING_VIEW_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string_view; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" // #include "hashed_string.hpp" #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP // #include "../stl/cstddef.hpp" // #include "../stl/cstdint.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { template struct fnv_1a_params; template<> struct fnv_1a_params { static constexpr auto offset = 2166136261; static constexpr auto prime = 16777619; }; template<> struct fnv_1a_params { static constexpr auto offset = 14695981039346656037ull; static constexpr auto prime = 1099511628211ull; }; template struct basic_hashed_string { using value_type = Char; using size_type = stl::size_t; using hash_type = id_type; const value_type *repr{}; hash_type hash{fnv_1a_params<>::offset}; size_type length{}; }; } // namespace internal /*! @endcond */ /** * @brief Zero overhead unique identifier. * * A hashed string is a compile-time tool that allows users to use * human-readable identifiers 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. * * @warning * This class doesn't take ownership of user-supplied strings nor does it make a * copy of them. * * @tparam Char Character type. */ template class basic_hashed_string: internal::basic_hashed_string { using base_type = internal::basic_hashed_string; using params = internal::fnv_1a_params<>; struct const_wrapper { // non-explicit constructor on purpose constexpr const_wrapper(const base_type::value_type *str) noexcept : repr{str} {} const base_type::value_type *repr; }; public: /*! @brief Character type. */ using value_type = base_type::value_type; /*! @brief Unsigned integer type. */ using size_type = base_type::size_type; /*! @brief Unsigned integer type. */ using hash_type = base_type::hash_type; /** * @brief Returns directly the numeric representation of a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. * @return The numeric representation of the string. */ [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { return basic_hashed_string{str, len}; } /** * @brief Returns directly the numeric representation of a string. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. * @return The numeric representation of the string. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { return basic_hashed_string{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 constexpr hash_type value(const_wrapper wrapper) noexcept { return basic_hashed_string{wrapper}; } /*! @brief Constructs an empty hashed string. */ constexpr basic_hashed_string() noexcept : basic_hashed_string{nullptr, 0u} {} /** * @brief Constructs a hashed string from a string view. * @param str Human-readable identifier. * @param len Length of the string to hash. */ constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; base_type::length < len; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Constructs a hashed string from an array of const characters. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) : base_type{str} { for(; str[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; } } /** * @brief Explicit constructor on purpose to avoid constructing a hashed * string directly from a `const value_type *`. * * @warning * The lifetime of the string is not extended nor is it copied. * * @param wrapper Helps achieving the purpose by relying on overloading. */ explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept : base_type{wrapper.repr} { // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) for(; wrapper.repr[base_type::length]; ++base_type::length) { base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; } // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) } /** * @brief Returns the size of a hashed string. * @return The size of the hashed string. */ [[nodiscard]] constexpr size_type size() const noexcept { return base_type::length; } /** * @brief Returns the human-readable representation of a hashed string. * @return The string used to initialize the hashed string. */ [[nodiscard]] constexpr const value_type *data() const noexcept { return base_type::repr; } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr hash_type value() const noexcept { return base_type::hash; } /*! @copydoc data */ [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { return data(); } /** * @brief Returns the numeric representation of a hashed string. * @return The numeric representation of the hashed string. */ [[nodiscard]] constexpr operator hash_type() const noexcept { return value(); } /** * @brief Compares two hashed strings. * @param other A valid hashed string. * @return True if the two hashed strings are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { return value() == other.value(); } /** * @brief Lexicographically compares two hashed strings. * @param other A valid hashed string. * @return The relative order between the two hashed strings. */ [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { return value() <=> other.value(); } }; /** * @brief Deduction guide. * @tparam Char Character type. * @param str Human-readable identifier. * @param len Length of the string to hash. */ template basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; /** * @brief Deduction guide. * @tparam Char Character type. * @tparam N Number of characters of the identifier. * @param str Human-readable identifier. */ template // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) basic_hashed_string(const Char (&str)[N]) -> 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]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { return hashed_string{str}; } /** * @brief User defined literal for hashed wstrings. * @param str The literal without its suffix. * @return A properly initialized hashed wstring. */ [[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { return hashed_wstring{str}; } } // namespace literals } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct ENTT_API type_index final { [[nodiscard]] static id_type next() noexcept { static ENTT_MAYBE_ATOMIC(id_type) value{}; return value++; } }; template [[nodiscard]] constexpr const char *pretty_function() noexcept { #if defined ENTT_PRETTY_FUNCTION return static_cast(ENTT_PRETTY_FUNCTION); #else return ""; #endif } template [[nodiscard]] constexpr auto stripped_type_name() noexcept { #if defined ENTT_PRETTY_FUNCTION const stl::string_view full_name{pretty_function()}; auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); return value; #else return stl::string_view{}; #endif } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { constexpr auto value = stripped_type_name(); return value; } template [[nodiscard]] stl::string_view type_name(char) noexcept { static const auto value = stripped_type_name(); return value; } template().find_first_of('.')> [[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { constexpr auto stripped = stripped_type_name(); constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); return value; } template [[nodiscard]] id_type type_hash(char) noexcept { static const auto value = [](const auto stripped) { return hashed_string::value(stripped.data(), stripped.size()); }(stripped_type_name()); return value; } } // namespace internal /*! @endcond */ /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. */ template struct ENTT_API type_index final { /** * @brief Returns the sequential identifier of a given type. * @return The sequential identifier of a given type. */ [[nodiscard]] static id_type value() noexcept { static const id_type value = internal::type_index::next(); return value; } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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() noexcept { return internal::type_hash(0); #else [[nodiscard]] static constexpr id_type value() noexcept { return type_index::value(); #endif } /*! @copydoc value */ [[nodiscard]] constexpr operator id_type() const 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 stl::string_view value() noexcept { return internal::type_name(0); } /*! @copydoc value */ [[nodiscard]] constexpr operator stl::string_view() const noexcept { return value(); } }; /*! @brief Implementation specific information about a type. */ struct type_info final { /** * @brief Constructs a type info object for a given type. * @tparam Type Type for which to construct a type info object. */ template // NOLINTBEGIN(modernize-use-transparent-functors) constexpr type_info(stl::in_place_type_t) noexcept : seq{type_index>::value()}, identifier{type_hash>::value()}, alias{type_name>::value()} {} // NOLINTEND(modernize-use-transparent-functors) /** * @brief Type index. * @return Type index. */ [[nodiscard]] constexpr id_type index() const noexcept { return seq; } /** * @brief Type hash. * @return Type hash. */ [[nodiscard]] constexpr id_type hash() const noexcept { return identifier; } /** * @brief Type name. * @return Type name. */ [[nodiscard]] constexpr stl::string_view name() const noexcept { return alias; } /** * @brief Compares two type info objects. * @param other A type info object. * @return True if the two type info objects are identical, false otherwise. */ [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { return identifier == other.identifier; } /** * @brief Lexicographically compares two type info objects. * @param other A type info object. * @return The relative order between the two type info objects. */ [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { return seq <=> other.seq; } private: id_type seq; id_type identifier; stl::string_view alias; }; /** * @brief Returns the type info object associated to a given type. * * The returned element refers to an object with static storage duration.
* The type doesn't need to be a complete type. If the type is a reference, the * result refers to the referenced type. In all cases, top-level cv-qualifiers * are ignored. * * @tparam Type Type for which to generate a type info object. * @return A reference to a properly initialized type info object. */ template [[nodiscard]] const type_info &type_id() noexcept { if constexpr(stl::is_same_v>) { static const type_info instance{stl::in_place_type}; return instance; } else { return type_id>(); } } /*! @copydoc type_id */ template [[nodiscard]] const type_info &type_id(const Type &) noexcept { return type_id>(); } } // namespace entt #endif // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "fwd.hpp" // #include "sigh.hpp" #ifndef ENTT_SIGNAL_SIGH_HPP #define ENTT_SIGNAL_SIGH_HPP // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #include "delegate.hpp" #ifndef ENTT_SIGNAL_DELEGATE_HPP #define ENTT_SIGNAL_DELEGATE_HPP // #include "../config/config.h" // #include "../core/type_traits.hpp" // #include "../stl/cstddef.hpp" // #include "../stl/functional.hpp" // #include "../stl/tuple.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /*! @cond ENTT_INTERNAL */ 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 requires stl::is_member_object_pointer_v auto function_pointer(Type Class::*, Other &&...) -> Type (*)(); template using function_pointer_t = decltype(function_pointer(stl::declval()...)); template [[nodiscard]] ENTT_CONSTEVAL auto index_sequence_for(Ret (*)(Args...)) { return stl::index_sequence_for{}; } } // namespace internal /*! @endcond */ /** * @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 { using return_type = stl::remove_const_t; using delegate_type = return_type(const void *, Args...); template [[nodiscard]] auto wrap(stl::index_sequence) noexcept { return [](const void *, Args... args) -> return_type { [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, stl::forward>>(stl::get(arguments))...)); }; } template [[nodiscard]] auto wrap(Type &, stl::index_sequence) noexcept { return [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, *curr, stl::forward>>(stl::get(arguments))...)); }; } template [[nodiscard]] auto wrap(Type *, stl::index_sequence) noexcept { return [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); return static_cast(stl::invoke(Candidate, curr, stl::forward>>(stl::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() noexcept = default; /** * @brief Constructs a delegate with a given object or payload, if any. * @tparam Candidate Function or member to connect to the delegate. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance Optional valid object that fits the purpose. */ template delegate(connect_arg_t, Type &&...value_or_instance) noexcept { connect(stl::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) 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() noexcept { instance = nullptr; if constexpr(stl::is_invocable_r_v) { fn = [](const void *, Args... args) -> return_type { return Ret(stl::invoke(Candidate, stl::forward(args)...)); }; } else if constexpr(stl::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) noexcept { instance = &value_or_instance; if constexpr(stl::is_invocable_r_v) { fn = [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); return Ret(stl::invoke(Candidate, *curr, stl::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) noexcept { instance = value_or_instance; if constexpr(stl::is_invocable_r_v) { fn = [](const void *payload, Args... args) -> return_type { Type *curr = static_cast(const_cast *>(payload)); return Ret(stl::invoke(Candidate, curr, stl::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) noexcept { ENTT_ASSERT(function != nullptr, "Uninitialized function pointer"); instance = payload; fn = function; } /** * @brief Resets a delegate. * * After a reset, a delegate cannot be invoked anymore. */ void reset() noexcept { instance = nullptr; fn = nullptr; } /** * @brief Returns a pointer to the stored callable function target, if any. * @return An opaque pointer to the stored callable function target. */ [[nodiscard]] function_type *target() const noexcept { return fn; } /** * @brief Returns the instance or the payload linked to a delegate, if any. * @return An opaque pointer to the underlying data. */ [[nodiscard]] const void *data() const noexcept { return instance; } /** * @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(instance, stl::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 noexcept { // no need to also test instance 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 noexcept { return fn == other.fn && instance == other.instance; } private: const void *instance{}; delegate_type *fn{}; }; /** * @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; } // namespace entt #endif // #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 Type A valid signal handler 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 Type A valid function type. * @tparam Allocator Type of allocator used to manage memory and elements. */ 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class sigh { friend class sink>; using alloc_traits = stl::allocator_traits; using delegate_type = delegate; using container_type = stl::vector>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Sink type. */ using sink_type = sink>; /*! @brief Default constructor. */ sigh() noexcept(noexcept(allocator_type{})) : sigh{allocator_type{}} {} /** * @brief Constructs a signal handler with a given allocator. * @param allocator The allocator to use. */ explicit sigh(const allocator_type &allocator) noexcept : calls{allocator} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ sigh(const sigh &other) : calls{other.calls} {} /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ sigh(const sigh &other, const allocator_type &allocator) : calls{other.calls, allocator} {} /** * @brief Move constructor. * @param other The instance to move from. */ sigh(sigh &&other) noexcept : calls{stl::move(other.calls)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ sigh(sigh &&other, const allocator_type &allocator) : calls{stl::move(other.calls), allocator} {} /*! @brief Default destructor. */ ~sigh() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This signal handler. */ sigh &operator=(const sigh &other) { calls = other.calls; return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This signal handler. */ sigh &operator=(sigh &&other) noexcept { swap(other); return *this; } /** * @brief Exchanges the contents with those of a given signal handler. * @param other Signal handler to exchange the content with. */ void swap(sigh &other) noexcept { using stl::swap; swap(calls, other.calls); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return calls.get_allocator(); } /** * @brief Number of listeners connected to the signal. * @return Number of listeners currently connected. */ [[nodiscard]] size_type size() const 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 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 pos = calls.size(); pos; --pos) { calls[pos - 1u](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 pos = calls.size(); pos; --pos) { if constexpr(stl::is_void_v || !stl::is_invocable_v) { calls[pos - 1u](args...); if constexpr(stl::is_invocable_r_v) { if(func()) { break; } } else { func(); } } else if constexpr(stl::is_invocable_r_v) { if(func(calls[pos - 1u](args...))) { break; } } else { func(calls[pos - 1u](args...)); } } } private: container_type calls; }; /** * @brief Connection class. * * Opaque object the aim of which is to allow users to release an already * established connection without having to keep a reference to the signal or * the sink that generated it. */ class connection { template friend class sink; connection(delegate fn, void *ref) : disconnect{fn}, signal{ref} {} public: /*! @brief Default constructor. */ connection() : signal{} {} /** * @brief Checks whether a connection is properly initialized. * @return True if the connection is properly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const 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 * established 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 Move constructor. * @param other The scoped connection to move from. */ scoped_connection(scoped_connection &&other) noexcept : conn{stl::exchange(other.conn, {})} {} /*! @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 Move assignment operator. * @param other The scoped connection to move from. * @return This scoped connection. */ scoped_connection &operator=(scoped_connection &&other) noexcept { conn = stl::exchange(other.conn, {}); return *this; } /** * @brief Acquires a connection. * @param other The connection object to acquire. * @return This scoped connection. */ scoped_connection &operator=(connection other) { conn = 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 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class sink> { using signal_type = sigh; using delegate_type = signal_type::delegate_type; using difference_type = signal_type::container_type::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(); } template void disconnect_if(Func callback) { auto &ref = signal_or_assert(); for(auto pos = ref.calls.size(); pos; --pos) { if(auto &elem = ref.calls[pos - 1u]; callback(elem)) { elem = stl::move(ref.calls.back()); ref.calls.pop_back(); } } } [[nodiscard]] auto &signal_or_assert() const noexcept { ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal"); return *signal; } public: /*! @brief Constructs an invalid sink. */ sink() noexcept : signal{} {} /** * @brief Constructs a sink that is allowed to modify a given signal. * @param ref A valid reference to a signal object. */ sink(sigh &ref) noexcept : 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 noexcept { return signal_or_assert().calls.empty(); } /** * @brief Connects a free function or an unbound member to a signal. * @tparam Candidate Function or member to connect to the signal. * @return A properly initialized connection object. */ template connection connect() { disconnect(); delegate_type call{}; call.template connect(); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(); return {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.
* 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 reference that fits the purpose. * @return A properly initialized connection object. */ template connection connect(Type &value_or_instance) { disconnect(value_or_instance); delegate_type call{}; call.template connect(value_or_instance); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(value_or_instance); return {conn, signal}; } /** * @brief Connects a free function with payload or a bound member to a * signal. * * @sa connect(Type &) * * @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 pointer that fits the purpose. * @return A properly initialized connection object. */ template connection connect(Type *value_or_instance) { disconnect(value_or_instance); delegate_type call{}; call.template connect(value_or_instance); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(value_or_instance); return {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() { delegate_type call{}; call.template connect(); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects a free function with payload or a bound member from 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.
* 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 disconnect from the signal. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance A valid reference that fits the purpose. */ template void disconnect(Type &value_or_instance) { delegate_type call{}; call.template connect(value_or_instance); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects a free function with payload or a bound member from a * signal. * * @sa disconnect(Type &) * * @tparam Candidate Function or member to disconnect from the signal. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance A valid pointer that fits the purpose. */ template void disconnect(Type *value_or_instance) { delegate_type call{}; call.template connect(value_or_instance); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects free functions with payload or bound members from a * signal. * @param value_or_instance A valid object that fits the purpose. */ void disconnect(const void *value_or_instance) { ENTT_ASSERT(value_or_instance != nullptr, "Invalid value or instance"); disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; }); } /*! @brief Disconnects all the listeners from a signal. */ void disconnect() { signal_or_assert().calls.clear(); } /** * @brief Returns true if a sink is correctly initialized, false otherwise. * @return True if a sink is correctly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return signal != nullptr; } private: signal_type *signal; }; /** * @brief Deduction guide. * * It allows to deduce the signal handler 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template sink(sigh &) -> sink>; } // namespace entt #endif namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { struct basic_dispatcher_handler { virtual ~basic_dispatcher_handler() = default; virtual void publish() = 0; virtual void disconnect(void *) = 0; virtual void clear() noexcept = 0; [[nodiscard]] virtual stl::size_t size() const noexcept = 0; }; template class dispatcher_handler final: public basic_dispatcher_handler { using alloc_traits = stl::allocator_traits; using signal_type = sigh; using container_type = stl::vector>; public: using allocator_type = Allocator; dispatcher_handler(const allocator_type &allocator) : signal{allocator}, events{allocator} {} void publish() override { container_type other{}; other.swap(events); for(auto &&elem: other) { signal.publish(elem); } } void disconnect(void *instance) override { bucket().disconnect(instance); } void clear() noexcept override { events.clear(); } [[nodiscard]] auto bucket() noexcept { return typename signal_type::sink_type{signal}; } void trigger(Type &event) { signal.publish(event); } template void enqueue(Args &&...args) { if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { events.push_back(Type{stl::forward(args)...}); } else { events.emplace_back(stl::forward(args)...); } } [[nodiscard]] stl::size_t size() const noexcept override { return events.size(); } private: signal_type signal; container_type events; }; } // namespace internal /*! @endcond */ /** * @brief Basic dispatcher implementation. * * A dispatcher can be used either to trigger an immediate event or to enqueue * events to be published all together once per tick.
* Listeners are provided in the form of member functions. For each event of * type `Type`, listeners are such that they can be invoked with an argument of * type `Type &`, 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. * * @tparam Allocator Type of allocator used to manage memory and elements. */ template class basic_dispatcher { template using handler_type = internal::dispatcher_handler; using key_type = id_type; // stl::shared_ptr because of its type erased allocator which is useful here using mapped_type = stl::shared_ptr; using alloc_traits = stl::allocator_traits; using container_allocator = alloc_traits::template rebind_alloc>; using container_type = dense_map, container_allocator>; template [[nodiscard]] handler_type &assure(const id_type id) { auto &&ptr = pools.first()[id]; if(!ptr) { const auto &allocator = get_allocator(); ptr = stl::allocate_shared>(allocator, allocator); } return static_cast &>(*ptr); } template [[nodiscard]] const handler_type *assure(const id_type id) const { if(auto it = pools.first().find(id); it != pools.first().cend()) { return static_cast *>(it->second.get()); } return nullptr; } public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Default constructor. */ basic_dispatcher() : basic_dispatcher{allocator_type{}} {} /** * @brief Constructs a dispatcher with a given allocator. * @param allocator The allocator to use. */ explicit basic_dispatcher(const allocator_type &allocator) : pools{allocator, allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ basic_dispatcher(const basic_dispatcher &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ basic_dispatcher(basic_dispatcher &&other) noexcept : pools{stl::move(other.pools)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ basic_dispatcher(basic_dispatcher &&other, const allocator_type &allocator) : pools{container_type{stl::move(other.pools.first()), allocator}, allocator} { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a dispatcher is not allowed"); } /*! @brief Default destructor. */ ~basic_dispatcher() = default; /** * @brief Default copy assignment operator, deleted on purpose. * @return This dispatcher. */ basic_dispatcher &operator=(const basic_dispatcher &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This dispatcher. */ basic_dispatcher &operator=(basic_dispatcher &&other) noexcept { ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a dispatcher is not allowed"); swap(other); return *this; } /** * @brief Exchanges the contents with those of a given dispatcher. * @param other Dispatcher to exchange the content with. */ void swap(basic_dispatcher &other) noexcept { using stl::swap; swap(pools, other.pools); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return pools.second(); } /** * @brief Returns the number of pending events for a given type. * @tparam Type Type of event for which to return the count. * @param id Name used to map the event queue within the dispatcher. * @return The number of pending events for the given type. */ template [[nodiscard]] size_type size(const id_type id = type_hash::value()) const noexcept { const auto *cpool = assure>(id); return cpool ? cpool->size() : 0u; } /** * @brief Returns the total number of pending events. * @return The total number of pending events. */ [[nodiscard]] size_type size() const noexcept { size_type count{}; for(auto &&cpool: pools.first()) { count += cpool.second->size(); } return count; } /** * @brief Returns a sink object for the given event and queue. * * A sink is an opaque object used to connect listeners to events. * * The function type for a listener is _compatible_ with: * * @code{.cpp} * void(Type &); * @endcode * * The order of invocation of the listeners isn't guaranteed. * * @sa sink * * @tparam Type Type of event of which to get the sink. * @param id Name used to map the event queue within the dispatcher. * @return A temporary sink object. */ template [[nodiscard]] auto sink(const id_type id = type_hash::value()) { return assure(id).bucket(); } /** * @brief Triggers an immediate event of a given type. * @tparam Type Type of event to trigger. * @param value An instance of the given type of event. */ template void trigger(Type value) { trigger(type_hash>::value(), value); } /** * @brief Triggers an immediate event on a queue of a given type. * @tparam Type Type of event to trigger. * @param value An instance of the given type of event. * @param id Name used to map the event queue within the dispatcher. */ template void trigger(const id_type id, Type value) { assure>(id).trigger(value); } /** * @brief Enqueues an event of the given type. * @tparam Type Type of event to enqueue. * @tparam Args Types of arguments to use to construct the event. * @param args Arguments to use to construct the event. */ template void enqueue(Args &&...args) { enqueue_hint(type_hash::value(), stl::forward(args)...); } /** * @brief Enqueues an event of the given type. * @tparam Type Type of event to enqueue. * @param value An instance of the given type of event. */ template void enqueue(Type &&value) { enqueue_hint(type_hash>::value(), stl::forward(value)); } /** * @brief Enqueues an event of the given type. * @tparam Type Type of event to enqueue. * @tparam Args Types of arguments to use to construct the event. * @param id Name used to map the event queue within the dispatcher. * @param args Arguments to use to construct the event. */ template void enqueue_hint(const id_type id, Args &&...args) { assure(id).enqueue(stl::forward(args)...); } /** * @brief Enqueues an event of the given type. * @tparam Type Type of event to enqueue. * @param id Name used to map the event queue within the dispatcher. * @param value An instance of the given type of event. */ template void enqueue_hint(const id_type id, Type &&value) { assure>(id).enqueue(stl::forward(value)); } /** * @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.first()) { cpool.second->disconnect(value_or_instance); } } /** * @brief Discards all the events stored so far in a given queue. * @tparam Type Type of event to discard. * @param id Name used to map the event queue within the dispatcher. */ template void clear(const id_type id = type_hash::value()) { assure(id).clear(); } /*! @brief Discards all the events queued so far. */ void clear() noexcept { for(auto &&cpool: pools.first()) { cpool.second->clear(); } } /** * @brief Delivers all the pending events of a given queue. * @tparam Type Type of event to send. * @param id Name used to map the event queue within the dispatcher. */ template void update(const id_type id = type_hash::value()) { assure(id).publish(); } /*! @brief Delivers all the pending events. */ void update() const { for(auto &&cpool: pools.first()) { cpool.second->publish(); } } private: compressed_pair pools; }; } // namespace entt #endif // #include "signal/emitter.hpp" #ifndef ENTT_SIGNAL_EMITTER_HPP #define ENTT_SIGNAL_EMITTER_HPP // #include "../container/dense_map.hpp" // #include "../core/compressed_pair.hpp" // #include "../core/fwd.hpp" // #include "../core/type_info.hpp" // #include "../stl/functional.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "fwd.hpp" namespace entt { /** * @brief General purpose event emitter. * * To create an emitter type, derived classes must inherit from the base as: * * @code{.cpp} * struct my_emitter: emitter { * // ... * } * @endcode * * Handlers for the different events are created internally on the fly. It's not * required to specify in advance the full list of accepted events.
* Moreover, whenever an event is published, an emitter also passes a reference * to itself to its listeners. * * @tparam Derived Emitter type. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class emitter { using key_type = id_type; using mapped_type = stl::function; using alloc_traits = stl::allocator_traits; using container_allocator = alloc_traits::template rebind_alloc>; using container_type = dense_map, container_allocator>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Default constructor. */ emitter() : emitter{allocator_type{}} {} /** * @brief Constructs an emitter with a given allocator. * @param allocator The allocator to use. */ explicit emitter(const allocator_type &allocator) : handlers{allocator, allocator} {} /*! @brief Default copy constructor, deleted on purpose. */ emitter(const emitter &) = delete; /** * @brief Move constructor. * @param other The instance to move from. */ emitter(emitter &&other) noexcept : handlers{stl::move(other.handlers)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ emitter(emitter &&other, const allocator_type &allocator) : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); } /*! @brief Default destructor. */ virtual ~emitter() { static_assert(stl::is_base_of_v, Derived>, "Invalid emitter type"); } /** * @brief Default copy assignment operator, deleted on purpose. * @return This emitter. */ emitter &operator=(const emitter &) = delete; /** * @brief Move assignment operator. * @param other The instance to move from. * @return This emitter. */ emitter &operator=(emitter &&other) noexcept { ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); swap(other); return *this; } /** * @brief Exchanges the contents with those of a given emitter. * @param other Emitter to exchange the content with. */ void swap(emitter &other) noexcept { using stl::swap; swap(handlers, other.handlers); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return handlers.second(); } /** * @brief Publishes a given event. * @tparam Type Type of event to trigger. * @param value An instance of the given type of event. */ template void publish(Type value) { if(const auto id = type_id().hash(); handlers.first().contains(id)) { handlers.first()[id](&value); } } /** * @brief Registers a listener with the event emitter. * @tparam Type Type of event to which to connect the listener. * @param func The listener to register. */ template void on(stl::function func) { handlers.first().insert_or_assign(type_id().hash(), [func = stl::move(func), this](void *value) { func(*static_cast(value), static_cast(*this)); }); } /** * @brief Disconnects a listener from the event emitter. * @tparam Type Type of event of the listener. */ template void erase() { handlers.first().erase(type_hash>::value()); } /*! @brief Disconnects all the listeners. */ void clear() noexcept { handlers.first().clear(); } /** * @brief Checks if there are listeners registered for the specific event. * @tparam Type Type of event to test. * @return True if there are no listeners registered, false otherwise. */ template [[nodiscard]] bool contains() const { return handlers.first().contains(type_hash>::value()); } /** * @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 noexcept { return handlers.first().empty(); } private: compressed_pair handlers; }; } // namespace entt #endif // #include "signal/sigh.hpp" #ifndef ENTT_SIGNAL_SIGH_HPP #define ENTT_SIGNAL_SIGH_HPP // #include "../stl/cstddef.hpp" // #include "../stl/memory.hpp" // #include "../stl/type_traits.hpp" // #include "../stl/utility.hpp" // #include "../stl/vector.hpp" // #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 Type A valid signal handler 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 Type A valid function type. * @tparam Allocator Type of allocator used to manage memory and elements. */ 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class sigh { friend class sink>; using alloc_traits = stl::allocator_traits; using delegate_type = delegate; using container_type = stl::vector>; public: /*! @brief Allocator type. */ using allocator_type = Allocator; /*! @brief Unsigned integer type. */ using size_type = stl::size_t; /*! @brief Sink type. */ using sink_type = sink>; /*! @brief Default constructor. */ sigh() noexcept(noexcept(allocator_type{})) : sigh{allocator_type{}} {} /** * @brief Constructs a signal handler with a given allocator. * @param allocator The allocator to use. */ explicit sigh(const allocator_type &allocator) noexcept : calls{allocator} {} /** * @brief Copy constructor. * @param other The instance to copy from. */ sigh(const sigh &other) : calls{other.calls} {} /** * @brief Allocator-extended copy constructor. * @param other The instance to copy from. * @param allocator The allocator to use. */ sigh(const sigh &other, const allocator_type &allocator) : calls{other.calls, allocator} {} /** * @brief Move constructor. * @param other The instance to move from. */ sigh(sigh &&other) noexcept : calls{stl::move(other.calls)} {} /** * @brief Allocator-extended move constructor. * @param other The instance to move from. * @param allocator The allocator to use. */ sigh(sigh &&other, const allocator_type &allocator) : calls{stl::move(other.calls), allocator} {} /*! @brief Default destructor. */ ~sigh() = default; /** * @brief Copy assignment operator. * @param other The instance to copy from. * @return This signal handler. */ sigh &operator=(const sigh &other) { calls = other.calls; return *this; } /** * @brief Move assignment operator. * @param other The instance to move from. * @return This signal handler. */ sigh &operator=(sigh &&other) noexcept { swap(other); return *this; } /** * @brief Exchanges the contents with those of a given signal handler. * @param other Signal handler to exchange the content with. */ void swap(sigh &other) noexcept { using stl::swap; swap(calls, other.calls); } /** * @brief Returns the associated allocator. * @return The associated allocator. */ [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { return calls.get_allocator(); } /** * @brief Number of listeners connected to the signal. * @return Number of listeners currently connected. */ [[nodiscard]] size_type size() const 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 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 pos = calls.size(); pos; --pos) { calls[pos - 1u](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 pos = calls.size(); pos; --pos) { if constexpr(stl::is_void_v || !stl::is_invocable_v) { calls[pos - 1u](args...); if constexpr(stl::is_invocable_r_v) { if(func()) { break; } } else { func(); } } else if constexpr(stl::is_invocable_r_v) { if(func(calls[pos - 1u](args...))) { break; } } else { func(calls[pos - 1u](args...)); } } } private: container_type calls; }; /** * @brief Connection class. * * Opaque object the aim of which is to allow users to release an already * established connection without having to keep a reference to the signal or * the sink that generated it. */ class connection { template friend class sink; connection(delegate fn, void *ref) : disconnect{fn}, signal{ref} {} public: /*! @brief Default constructor. */ connection() : signal{} {} /** * @brief Checks whether a connection is properly initialized. * @return True if the connection is properly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const 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 * established 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 Move constructor. * @param other The scoped connection to move from. */ scoped_connection(scoped_connection &&other) noexcept : conn{stl::exchange(other.conn, {})} {} /*! @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 Move assignment operator. * @param other The scoped connection to move from. * @return This scoped connection. */ scoped_connection &operator=(scoped_connection &&other) noexcept { conn = stl::exchange(other.conn, {}); return *this; } /** * @brief Acquires a connection. * @param other The connection object to acquire. * @return This scoped connection. */ scoped_connection &operator=(connection other) { conn = 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 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template class sink> { using signal_type = sigh; using delegate_type = signal_type::delegate_type; using difference_type = signal_type::container_type::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(); } template void disconnect_if(Func callback) { auto &ref = signal_or_assert(); for(auto pos = ref.calls.size(); pos; --pos) { if(auto &elem = ref.calls[pos - 1u]; callback(elem)) { elem = stl::move(ref.calls.back()); ref.calls.pop_back(); } } } [[nodiscard]] auto &signal_or_assert() const noexcept { ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal"); return *signal; } public: /*! @brief Constructs an invalid sink. */ sink() noexcept : signal{} {} /** * @brief Constructs a sink that is allowed to modify a given signal. * @param ref A valid reference to a signal object. */ sink(sigh &ref) noexcept : 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 noexcept { return signal_or_assert().calls.empty(); } /** * @brief Connects a free function or an unbound member to a signal. * @tparam Candidate Function or member to connect to the signal. * @return A properly initialized connection object. */ template connection connect() { disconnect(); delegate_type call{}; call.template connect(); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(); return {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.
* 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 reference that fits the purpose. * @return A properly initialized connection object. */ template connection connect(Type &value_or_instance) { disconnect(value_or_instance); delegate_type call{}; call.template connect(value_or_instance); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(value_or_instance); return {conn, signal}; } /** * @brief Connects a free function with payload or a bound member to a * signal. * * @sa connect(Type &) * * @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 pointer that fits the purpose. * @return A properly initialized connection object. */ template connection connect(Type *value_or_instance) { disconnect(value_or_instance); delegate_type call{}; call.template connect(value_or_instance); signal_or_assert().calls.push_back(stl::move(call)); delegate conn{}; conn.template connect<&release>(value_or_instance); return {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() { delegate_type call{}; call.template connect(); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects a free function with payload or a bound member from 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.
* 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 disconnect from the signal. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance A valid reference that fits the purpose. */ template void disconnect(Type &value_or_instance) { delegate_type call{}; call.template connect(value_or_instance); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects a free function with payload or a bound member from a * signal. * * @sa disconnect(Type &) * * @tparam Candidate Function or member to disconnect from the signal. * @tparam Type Type of class or type of payload, if any. * @param value_or_instance A valid pointer that fits the purpose. */ template void disconnect(Type *value_or_instance) { delegate_type call{}; call.template connect(value_or_instance); disconnect_if([&call](const auto &elem) { return elem == call; }); } /** * @brief Disconnects free functions with payload or bound members from a * signal. * @param value_or_instance A valid object that fits the purpose. */ void disconnect(const void *value_or_instance) { ENTT_ASSERT(value_or_instance != nullptr, "Invalid value or instance"); disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; }); } /*! @brief Disconnects all the listeners from a signal. */ void disconnect() { signal_or_assert().calls.clear(); } /** * @brief Returns true if a sink is correctly initialized, false otherwise. * @return True if a sink is correctly initialized, false otherwise. */ [[nodiscard]] explicit operator bool() const noexcept { return signal != nullptr; } private: signal_type *signal; }; /** * @brief Deduction guide. * * It allows to deduce the signal handler 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. * @tparam Allocator Type of allocator used to manage memory and elements. */ template sink(sigh &) -> sink>; } // namespace entt #endif // #include "stl/algorithm.hpp" #ifndef ENTT_STL_ALGORITHM_HPP #define ENTT_STL_ALGORITHM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::all_of; using std::any_of; using std::find_if; using std::none_of; using std::sort; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/array.hpp" #ifndef ENTT_STL_ARRAY_HPP #define ENTT_STL_ARRAY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::array; using std::get; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/bit.hpp" #ifndef ENTT_STL_BIT_HPP #define ENTT_STL_BIT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bit_ceil; using std::has_single_bit; using std::popcount; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/cmath.hpp" #ifndef ENTT_STL_CMATH_HPP #define ENTT_STL_CMATH_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ceil; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/concepts.hpp" #ifndef ENTT_STL_CONCEPTS_HPP #define ENTT_STL_CONCEPTS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::constructible_from; using std::default_initializable; using std::derived_from; using std::integral; using std::invocable; using std::same_as; using std::unsigned_integral; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/cstddef.hpp" #ifndef ENTT_STL_CSTDDEF_HPP #define ENTT_STL_CSTDDEF_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::byte; using std::nullptr_t; using std::ptrdiff_t; using std::size_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/functional.hpp" #ifndef ENTT_STL_FUNCTIONAL_HPP #define ENTT_STL_FUNCTIONAL_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" #ifndef ENTT_CONFIG_CONFIG_H #define ENTT_CONFIG_CONFIG_H #if __has_include() # include #endif #include // #include "version.h" #ifndef ENTT_CONFIG_VERSION_H #define ENTT_CONFIG_VERSION_H // #include "macro.h" #ifndef ENTT_CONFIG_MACRO_H #define ENTT_CONFIG_MACRO_H // NOLINTBEGIN(cppcoreguidelines-macro-usage) #define ENTT_STR(arg) #arg #define ENTT_XSTR(arg) ENTT_STR(arg) // NOLINTEND(cppcoreguidelines-macro-usage) #endif // NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) #define ENTT_VERSION_MAJOR 4 #define ENTT_VERSION_MINOR 0 #define ENTT_VERSION_PATCH 0 #define ENTT_VERSION \ ENTT_XSTR(ENTT_VERSION_MAJOR) \ "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) // NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) #endif // NOLINTBEGIN(cppcoreguidelines-macro-usage) #ifdef ENTT_USE_STL # define ENTT_FORCE_STL #endif #if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) # define ENTT_THROW throw # define ENTT_TRY try # define ENTT_CATCH catch(...) #else # define ENTT_THROW # define ENTT_TRY if(true) # define ENTT_CATCH if(false) #endif #if defined(__cpp_consteval) # define ENTT_CONSTEVAL consteval #else # define ENTT_CONSTEVAL constexpr #endif #ifdef ENTT_USE_ATOMIC // # include "../stl/atomic.hpp" #ifndef ENTT_STL_ATOMIC_HPP #define ENTT_STL_ATOMIC_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::atomic; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_MAYBE_ATOMIC(Type) stl::atomic #else # define ENTT_MAYBE_ATOMIC(Type) Type #endif #ifndef ENTT_ID_TYPE // # include "../stl/cstdint.hpp" #ifndef ENTT_STL_CSTDINT_HPP #define ENTT_STL_CSTDINT_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::uint16_t; using std::uint32_t; using std::uint64_t; using std::uint8_t; } // namespace entt::stl #endif /*! @endcond */ #endif # define ENTT_ID_TYPE stl::uint32_t #else // # include "../stl/cstdint.hpp" // provides coverage for types in the std namespace #endif #ifndef ENTT_SPARSE_PAGE # define ENTT_SPARSE_PAGE 4096 #endif #ifndef ENTT_PACKED_PAGE # define ENTT_PACKED_PAGE 1024 #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT # define ENTT_ASSERT(condition, msg) (void(0)) #elif !defined ENTT_ASSERT # include # define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) #endif #ifdef ENTT_DISABLE_ASSERT # undef ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) #elif !defined ENTT_ASSERT_CONSTEXPR # define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) #endif #define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); #ifdef ENTT_NO_ETO # define ENTT_ETO_TYPE(Type) void #else # define ENTT_ETO_TYPE(Type) Type #endif #ifdef ENTT_NO_MIXIN # define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ #else # define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> #endif #ifdef ENTT_STANDARD_CPP # define ENTT_NONSTD false #else # define ENTT_NONSTD true # 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 #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 #if defined _MSC_VER # pragma detect_mismatch("entt.version", ENTT_VERSION) # pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) # pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) # pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) #endif // NOLINTEND(cppcoreguidelines-macro-usage) #endif namespace entt::stl { using std::equal_to; using std::function; using std::hash; using std::invoke; using std::less; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_IDENTITY namespace entt::stl { using std::identity; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_IDENTITY # include namespace entt::stl { struct identity { using is_transparent = void; template [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { return std::forward(value); } }; } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_IDENTITY #endif // #include "stl/ios.hpp" #ifndef ENTT_STL_IOS_HPP #define ENTT_STL_IOS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::boolalpha; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/iterator.hpp" #ifndef ENTT_STL_ITERATOR_HPP #define ENTT_STL_ITERATOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::advance; using std::bidirectional_iterator_tag; using std::distance; using std::forward_iterator_tag; using std::input_iterator_tag; using std::iterator_traits; using std::make_reverse_iterator; using std::random_access_iterator_tag; using std::reverse_iterator; # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_ranges) # define ENTT_HAS_ITERATOR_CONCEPTS using std::bidirectional_iterator; using std::forward_iterator; using std::input_iterator; using std::input_or_output_iterator; using std::output_iterator; using std::random_access_iterator; using std::sentinel_for; # endif # endif # ifndef ENTT_HAS_ITERATOR_CONCEPTS # include # include namespace internal { template concept has_iterator_category = requires { typename std::iterator_traits::iterator_category; }; template concept has_iterator_concept = has_iterator_category && requires { typename It::iterator_concept; }; template struct iterator_tag { using type = typename std::iterator_traits::iterator_category; }; template struct iterator_tag { using type = typename It::iterator_concept; }; template concept has_iterator_tag = std::derived_from::type, Tag>; } // namespace internal // Bare minimum definitions to support broken platforms like PS4. // EnTT does not provide full featured definitions for iterator concepts. template concept input_or_output_iterator = requires(It it) { *it; { ++it } -> std::same_as; it++; }; template concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; template concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { *it++ = std::forward(value); }; template concept forward_iterator = input_iterator && internal::has_iterator_tag; template concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; template concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; template concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { { it == sentinel } -> std::same_as; }; # endif } // namespace entt::stl #endif /*! @endcond */ #undef ENTT_HAS_ITERATOR_CONCEPTS #endif // #include "stl/limits.hpp" #ifndef ENTT_STL_LIMITS_HPP #define ENTT_STL_LIMITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::numeric_limits; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/memory.hpp" #ifndef ENTT_STL_MEMORY_HPP #define ENTT_STL_MEMORY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include # include // # include "../config/config.h" namespace entt::stl { using std::addressof; using std::allocate_shared; using std::allocator; using std::allocator_arg; using std::allocator_arg_t; using std::allocator_traits; using std::default_delete; using std::destroy; using std::enable_shared_from_this; using std::make_shared; using std::make_unique; using std::pointer_traits; using std::shared_ptr; using std::static_pointer_cast; using std::uninitialized_fill; using std::unique_ptr; using std::uses_allocator_v; } // namespace entt::stl # ifndef ENTT_FORCE_STL # if defined(__cpp_lib_to_address) # define ENTT_HAS_TO_ADDRESS namespace entt::stl { using std::to_address; } // namespace entt::stl # endif # endif # ifndef ENTT_HAS_TO_ADDRESS # include namespace entt::stl { template constexpr Type *to_address(Type *ptr) noexcept { static_assert(!std::is_function_v, "Invalid type"); return ptr; } template constexpr auto to_address(const Type &ptr) noexcept { if constexpr(requires { std::pointer_traits::to_address(ptr); }) { return std::pointer_traits::to_address(ptr); } else { return to_address(ptr.operator->()); } } } // namespace entt::stl # endif #endif /*! @endcond */ #undef ENTT_HAS_TO_ADDRESS #endif // #include "stl/ostream.hpp" #ifndef ENTT_STL_OSTREAM_HPP #define ENTT_STL_OSTREAM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::ostream; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/sstream.hpp" #ifndef ENTT_STL_SSTREAM_HPP #define ENTT_STL_SSTREAM_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::stringstream; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/string.hpp" #ifndef ENTT_STL_STRING_HPP #define ENTT_STL_STRING_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/string_view.hpp" #ifndef ENTT_STL_STRING_VIEW_HPP #define ENTT_STL_STRING_VIEW_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::string_view; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/tuple.hpp" #ifndef ENTT_STL_TUPLE_HPP #define ENTT_STL_TUPLE_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::apply; using std::forward_as_tuple; using std::get; using std::make_from_tuple; using std::make_tuple; using std::tuple; using std::tuple_cat; using std::tuple_element; using std::tuple_element_t; using std::tuple_size; using std::tuple_size_v; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/type_traits.hpp" #ifndef ENTT_STL_TYPE_TRAITS_HPP #define ENTT_STL_TYPE_TRAITS_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::bool_constant; using std::common_type_t; using std::conditional_t; using std::decay_t; using std::extent_v; using std::false_type; using std::integral_constant; using std::invoke_result_t; using std::is_aggregate_v; using std::is_arithmetic_v; using std::is_array_v; using std::is_base_of_v; using std::is_class_v; using std::is_const_v; using std::is_constructible_v; using std::is_convertible_v; using std::is_copy_assignable_v; using std::is_copy_constructible_v; using std::is_default_constructible_v; using std::is_empty_v; using std::is_enum_v; using std::is_final_v; using std::is_function_v; using std::is_integral_v; using std::is_invocable; using std::is_invocable_r; using std::is_invocable_r_v; using std::is_invocable_v; using std::is_lvalue_reference_v; using std::is_member_function_pointer_v; using std::is_member_object_pointer_v; using std::is_member_pointer_v; using std::is_move_assignable_v; using std::is_move_constructible_v; using std::is_nothrow_constructible_v; using std::is_nothrow_copy_constructible_v; using std::is_nothrow_default_constructible_v; using std::is_nothrow_destructible_v; using std::is_nothrow_invocable_v; using std::is_nothrow_move_constructible_v; using std::is_pointer_v; using std::is_reference_v; using std::is_same_v; using std::is_signed_v; using std::is_trivially_destructible_v; using std::is_void_v; using std::remove_const_t; using std::remove_cvref_t; using std::remove_pointer_t; using std::remove_reference_t; using std::true_type; using std::type_identity; using std::underlying_type_t; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/utility.hpp" #ifndef ENTT_STL_UTILITY_HPP #define ENTT_STL_UTILITY_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::as_const; using std::declval; using std::exchange; using std::forward; using std::in_place; using std::in_place_t; using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; using std::make_index_sequence; using std::make_pair; using std::move; using std::pair; using std::piecewise_construct; using std::piecewise_construct_t; using std::swap; } // namespace entt::stl #endif /*! @endcond */ #endif // #include "stl/vector.hpp" #ifndef ENTT_STL_VECTOR_HPP #define ENTT_STL_VECTOR_HPP /*! @cond ENTT_INTERNAL */ #if __has_include() # include #else # include namespace entt::stl { using std::vector; } // namespace entt::stl #endif /*! @endcond */ #endif // IWYU pragma: end_exports