diff --git a/single_include/entt/entt.hpp b/single_include/entt/entt.hpp index 61e113ef7..f089a3197 100644 --- a/single_include/entt/entt.hpp +++ b/single_include/entt/entt.hpp @@ -5,7 +5,7 @@ #define ENTT_VERSION_MAJOR 3 #define ENTT_VERSION_MINOR 7 -#define ENTT_VERSION_PATCH 0 +#define ENTT_VERSION_PATCH 1 #endif @@ -146,7 +146,8 @@ struct overloaded: Func... { * @tparam Func Types of function objects. */ template -overloaded(Func...) -> overloaded; +overloaded(Func...) +-> overloaded; /** @@ -629,7 +630,7 @@ private: * @param str Human-readable identifer. */ template -basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT +basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; @@ -1505,30 +1506,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -1647,117 +1624,151 @@ class basic_any { template static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - using base_type = std::remove_const_t>; + if constexpr(std::is_void_v) { + switch(op) { + case operation::COPY: + case operation::MOVE: + case operation::REF: + case operation::CREF: + as(to).vtable = from.vtable; + break; + default: + break; + } + } else if constexpr(std::is_lvalue_reference_v) { + using base_type = std::decay_t; - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).template emplace(*static_cast(from.instance)); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to) = *static_cast(from.instance); } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif + break; + case operation::MOVE: + as(to).instance = from.instance; + as(to).vtable = from.vtable; + [[fallthrough]]; + case operation::DTOR: + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + return std::is_const_v> ? nullptr : from.instance; + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else if constexpr(in_situ) { + #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L + auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); + #else + auto *instance = const_cast(reinterpret_cast(&from.storage)); + #endif - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - [[fallthrough]]; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + new (&as(to).storage) Type{std::as_const(*instance)}; + as(to).vtable = from.vtable; } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = from.instance; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + break; + case operation::MOVE: + new (&as(to).storage) Type{std::move(*instance)}; + as(to).vtable = from.vtable; + break; + case operation::DTOR: + instance->~Type(); + break; + case operation::COMP: + return compare(instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return instance; + case operation::REF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else { + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to).instance = new Type{*static_cast(from.instance)}; + as(to).vtable = from.vtable; } + break; + case operation::MOVE: + as(to).instance = std::exchange(as(&from).instance, nullptr); + as(to).vtable = from.vtable; + break; + case operation::DTOR: + if constexpr(std::is_array_v) { + delete[] static_cast(from.instance); + } else { + delete static_cast(from.instance); + } + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; } } return nullptr; } + template + void initialize([[maybe_unused]] Args &&... args) { + if constexpr(!std::is_void_v) { + if constexpr(std::is_lvalue_reference_v) { + static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); + instance = (std::addressof(args), ...); + } else if constexpr(in_situ) { + if constexpr(std::is_aggregate_v) { + new (&storage) Type{std::forward(args)...}; + } else { + new (&storage) Type(std::forward(args)...); + } + } else { + if constexpr(std::is_aggregate_v) { + instance = new Type{std::forward(args)...}; + } else { + instance = new Type(std::forward(args)...); + } + } + } + } + public: /*! @brief Default constructor. */ basic_any() ENTT_NOEXCEPT @@ -1771,20 +1782,11 @@ public: * @param args Parameters to use to construct the instance. */ template - explicit basic_any(std::in_place_type_t, [[maybe_unused]] Args &&... args) + explicit basic_any(std::in_place_type_t, Args &&... args) : instance{}, vtable{&basic_vtable} { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - new (&storage) Type(std::forward(args)...); - } else { - instance = new Type(std::forward(args)...); - } - } + initialize(std::forward(args)...); } /** @@ -1812,7 +1814,7 @@ public: * @param other The instance to copy from. */ basic_any(const basic_any &other) - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::COPY, other, this); } @@ -1822,10 +1824,9 @@ public: * @param other The instance to move from. */ basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::MOVE, other, this); - vtable = std::exchange(other.vtable, &basic_vtable); } /*! @brief Frees the internal storage, whatever it means. */ @@ -1834,12 +1835,49 @@ public: } /** - * @brief Assignment operator. - * @param other The instance to assign from. + * @brief Copy assignment operator. + * @param other The instance to copy from. * @return This any object. */ - basic_any & operator=(basic_any other) { - swap(*this, other); + basic_any & operator=(const basic_any &other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::COPY, other, this); + return *this; + } + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This any object. + */ + basic_any & operator=(basic_any &&other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::MOVE, other, this); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { + emplace(value.get()); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + std::enable_if_t, basic_any>, basic_any &> + operator=(Type &&value) { + emplace>(std::forward(value)); return *this; } @@ -1848,7 +1886,7 @@ public: * @return The type of the contained object, if any. */ [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info; + type_info info{}; vtable(operation::TYPE, *this, &info); return info; } @@ -1874,12 +1912,13 @@ public: */ template void emplace(Args &&... args) { - *this = basic_any{std::in_place_type, std::forward(args)...}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); + initialize(std::forward(args)...); } /*! @brief Destroys contained object */ void reset() { - *this = basic_any{}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); } /** @@ -1899,19 +1938,6 @@ public: return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); } - /** - * @brief Swaps two any objects. - * @param lhs A valid any object. - * @param rhs A valid any object. - */ - friend void swap(basic_any &lhs, basic_any &rhs) { - basic_any tmp{}; - lhs.vtable(operation::MOVE, lhs, &tmp); - rhs.vtable(operation::MOVE, rhs, &lhs); - lhs.vtable(operation::MOVE, tmp, &rhs); - std::swap(lhs.vtable, rhs.vtable); - } - /** * @brief Aliasing constructor. * @return An any that shares a reference to an unmanaged object. @@ -1969,7 +1995,7 @@ Type any_cast(const basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(*instance); } @@ -1979,7 +2005,7 @@ Type any_cast(basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &&data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(std::move(*instance)); } @@ -2298,7 +2324,7 @@ private: * @param str Human-readable identifer. */ template -basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT +basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; @@ -3322,30 +3348,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -3492,7 +3494,8 @@ struct overloaded: Func... { * @tparam Func Types of function objects. */ template -overloaded(Func...) -> overloaded; +overloaded(Func...) +-> overloaded; /** @@ -4463,30 +4466,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -5031,7 +5010,8 @@ struct overloaded: Func... { * @tparam Func Types of function objects. */ template -overloaded(Func...) -> overloaded; +overloaded(Func...) +-> overloaded; /** @@ -6580,30 +6560,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -7014,7 +6970,7 @@ template * @tparam Candidate Function or member to connect to the delegate. */ template -delegate(connect_arg_t) ENTT_NOEXCEPT +delegate(connect_arg_t) -> delegate>>; @@ -7024,7 +6980,7 @@ delegate(connect_arg_t) ENTT_NOEXCEPT * @tparam Type Type of class or type of payload. */ template -delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT +delegate(connect_arg_t, Type &&) -> delegate>>; @@ -7034,7 +6990,7 @@ delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT * @tparam Args Types of arguments of a function type. */ template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT +delegate(Ret(*)(const void *, Args...), const void * = nullptr) -> delegate; @@ -7580,7 +7536,8 @@ private: * @tparam Args Types of arguments of a function type. */ template -sink(sigh &) ENTT_NOEXCEPT -> sink; +sink(sigh &) +-> sink; } @@ -8549,7 +8506,7 @@ class basic_group, get_t> final { private: It it; - const std::tuple *...> pools; + std::tuple *...> pools; }; iterable_group(basic_sparse_set * const ref, const std::tuple *...> &cpools) @@ -9715,7 +9672,7 @@ private: * @param str Human-readable identifer. */ template -basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT +basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; @@ -10591,30 +10548,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -10733,117 +10666,151 @@ class basic_any { template static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - using base_type = std::remove_const_t>; + if constexpr(std::is_void_v) { + switch(op) { + case operation::COPY: + case operation::MOVE: + case operation::REF: + case operation::CREF: + as(to).vtable = from.vtable; + break; + default: + break; + } + } else if constexpr(std::is_lvalue_reference_v) { + using base_type = std::decay_t; - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).template emplace(*static_cast(from.instance)); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to) = *static_cast(from.instance); } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif + break; + case operation::MOVE: + as(to).instance = from.instance; + as(to).vtable = from.vtable; + [[fallthrough]]; + case operation::DTOR: + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + return std::is_const_v> ? nullptr : from.instance; + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else if constexpr(in_situ) { + #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L + auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); + #else + auto *instance = const_cast(reinterpret_cast(&from.storage)); + #endif - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - [[fallthrough]]; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + new (&as(to).storage) Type{std::as_const(*instance)}; + as(to).vtable = from.vtable; } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = from.instance; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + break; + case operation::MOVE: + new (&as(to).storage) Type{std::move(*instance)}; + as(to).vtable = from.vtable; + break; + case operation::DTOR: + instance->~Type(); + break; + case operation::COMP: + return compare(instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return instance; + case operation::REF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else { + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to).instance = new Type{*static_cast(from.instance)}; + as(to).vtable = from.vtable; } + break; + case operation::MOVE: + as(to).instance = std::exchange(as(&from).instance, nullptr); + as(to).vtable = from.vtable; + break; + case operation::DTOR: + if constexpr(std::is_array_v) { + delete[] static_cast(from.instance); + } else { + delete static_cast(from.instance); + } + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; } } return nullptr; } + template + void initialize([[maybe_unused]] Args &&... args) { + if constexpr(!std::is_void_v) { + if constexpr(std::is_lvalue_reference_v) { + static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); + instance = (std::addressof(args), ...); + } else if constexpr(in_situ) { + if constexpr(std::is_aggregate_v) { + new (&storage) Type{std::forward(args)...}; + } else { + new (&storage) Type(std::forward(args)...); + } + } else { + if constexpr(std::is_aggregate_v) { + instance = new Type{std::forward(args)...}; + } else { + instance = new Type(std::forward(args)...); + } + } + } + } + public: /*! @brief Default constructor. */ basic_any() ENTT_NOEXCEPT @@ -10857,20 +10824,11 @@ public: * @param args Parameters to use to construct the instance. */ template - explicit basic_any(std::in_place_type_t, [[maybe_unused]] Args &&... args) + explicit basic_any(std::in_place_type_t, Args &&... args) : instance{}, vtable{&basic_vtable} { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - new (&storage) Type(std::forward(args)...); - } else { - instance = new Type(std::forward(args)...); - } - } + initialize(std::forward(args)...); } /** @@ -10898,7 +10856,7 @@ public: * @param other The instance to copy from. */ basic_any(const basic_any &other) - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::COPY, other, this); } @@ -10908,10 +10866,9 @@ public: * @param other The instance to move from. */ basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::MOVE, other, this); - vtable = std::exchange(other.vtable, &basic_vtable); } /*! @brief Frees the internal storage, whatever it means. */ @@ -10920,12 +10877,49 @@ public: } /** - * @brief Assignment operator. - * @param other The instance to assign from. + * @brief Copy assignment operator. + * @param other The instance to copy from. * @return This any object. */ - basic_any & operator=(basic_any other) { - swap(*this, other); + basic_any & operator=(const basic_any &other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::COPY, other, this); + return *this; + } + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This any object. + */ + basic_any & operator=(basic_any &&other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::MOVE, other, this); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { + emplace(value.get()); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + std::enable_if_t, basic_any>, basic_any &> + operator=(Type &&value) { + emplace>(std::forward(value)); return *this; } @@ -10934,7 +10928,7 @@ public: * @return The type of the contained object, if any. */ [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info; + type_info info{}; vtable(operation::TYPE, *this, &info); return info; } @@ -10960,12 +10954,13 @@ public: */ template void emplace(Args &&... args) { - *this = basic_any{std::in_place_type, std::forward(args)...}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); + initialize(std::forward(args)...); } /*! @brief Destroys contained object */ void reset() { - *this = basic_any{}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); } /** @@ -10985,19 +10980,6 @@ public: return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); } - /** - * @brief Swaps two any objects. - * @param lhs A valid any object. - * @param rhs A valid any object. - */ - friend void swap(basic_any &lhs, basic_any &rhs) { - basic_any tmp{}; - lhs.vtable(operation::MOVE, lhs, &tmp); - rhs.vtable(operation::MOVE, rhs, &lhs); - lhs.vtable(operation::MOVE, tmp, &rhs); - std::swap(lhs.vtable, rhs.vtable); - } - /** * @brief Aliasing constructor. * @return An any that shares a reference to an unmanaged object. @@ -11055,7 +11037,7 @@ Type any_cast(const basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(*instance); } @@ -11065,7 +11047,7 @@ Type any_cast(basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &&data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(std::move(*instance)); } @@ -11490,7 +11472,7 @@ class basic_group, get_t> final { private: It it; - const std::tuple *...> pools; + std::tuple *...> pools; }; iterable_group(basic_sparse_set * const ref, const std::tuple *...> &cpools) @@ -12800,7 +12782,7 @@ private: * @param str Human-readable identifer. */ template -basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT +basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; @@ -13676,30 +13658,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -13818,117 +13776,151 @@ class basic_any { template static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - using base_type = std::remove_const_t>; + if constexpr(std::is_void_v) { + switch(op) { + case operation::COPY: + case operation::MOVE: + case operation::REF: + case operation::CREF: + as(to).vtable = from.vtable; + break; + default: + break; + } + } else if constexpr(std::is_lvalue_reference_v) { + using base_type = std::decay_t; - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).template emplace(*static_cast(from.instance)); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to) = *static_cast(from.instance); } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif + break; + case operation::MOVE: + as(to).instance = from.instance; + as(to).vtable = from.vtable; + [[fallthrough]]; + case operation::DTOR: + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + return std::is_const_v> ? nullptr : from.instance; + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else if constexpr(in_situ) { + #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L + auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); + #else + auto *instance = const_cast(reinterpret_cast(&from.storage)); + #endif - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - [[fallthrough]]; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + new (&as(to).storage) Type{std::as_const(*instance)}; + as(to).vtable = from.vtable; } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = from.instance; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + break; + case operation::MOVE: + new (&as(to).storage) Type{std::move(*instance)}; + as(to).vtable = from.vtable; + break; + case operation::DTOR: + instance->~Type(); + break; + case operation::COMP: + return compare(instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return instance; + case operation::REF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else { + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to).instance = new Type{*static_cast(from.instance)}; + as(to).vtable = from.vtable; } + break; + case operation::MOVE: + as(to).instance = std::exchange(as(&from).instance, nullptr); + as(to).vtable = from.vtable; + break; + case operation::DTOR: + if constexpr(std::is_array_v) { + delete[] static_cast(from.instance); + } else { + delete static_cast(from.instance); + } + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; } } return nullptr; } + template + void initialize([[maybe_unused]] Args &&... args) { + if constexpr(!std::is_void_v) { + if constexpr(std::is_lvalue_reference_v) { + static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); + instance = (std::addressof(args), ...); + } else if constexpr(in_situ) { + if constexpr(std::is_aggregate_v) { + new (&storage) Type{std::forward(args)...}; + } else { + new (&storage) Type(std::forward(args)...); + } + } else { + if constexpr(std::is_aggregate_v) { + instance = new Type{std::forward(args)...}; + } else { + instance = new Type(std::forward(args)...); + } + } + } + } + public: /*! @brief Default constructor. */ basic_any() ENTT_NOEXCEPT @@ -13942,20 +13934,11 @@ public: * @param args Parameters to use to construct the instance. */ template - explicit basic_any(std::in_place_type_t, [[maybe_unused]] Args &&... args) + explicit basic_any(std::in_place_type_t, Args &&... args) : instance{}, vtable{&basic_vtable} { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - new (&storage) Type(std::forward(args)...); - } else { - instance = new Type(std::forward(args)...); - } - } + initialize(std::forward(args)...); } /** @@ -13983,7 +13966,7 @@ public: * @param other The instance to copy from. */ basic_any(const basic_any &other) - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::COPY, other, this); } @@ -13993,10 +13976,9 @@ public: * @param other The instance to move from. */ basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::MOVE, other, this); - vtable = std::exchange(other.vtable, &basic_vtable); } /*! @brief Frees the internal storage, whatever it means. */ @@ -14005,12 +13987,49 @@ public: } /** - * @brief Assignment operator. - * @param other The instance to assign from. + * @brief Copy assignment operator. + * @param other The instance to copy from. * @return This any object. */ - basic_any & operator=(basic_any other) { - swap(*this, other); + basic_any & operator=(const basic_any &other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::COPY, other, this); + return *this; + } + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This any object. + */ + basic_any & operator=(basic_any &&other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::MOVE, other, this); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { + emplace(value.get()); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + std::enable_if_t, basic_any>, basic_any &> + operator=(Type &&value) { + emplace>(std::forward(value)); return *this; } @@ -14019,7 +14038,7 @@ public: * @return The type of the contained object, if any. */ [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info; + type_info info{}; vtable(operation::TYPE, *this, &info); return info; } @@ -14045,12 +14064,13 @@ public: */ template void emplace(Args &&... args) { - *this = basic_any{std::in_place_type, std::forward(args)...}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); + initialize(std::forward(args)...); } /*! @brief Destroys contained object */ void reset() { - *this = basic_any{}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); } /** @@ -14070,19 +14090,6 @@ public: return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); } - /** - * @brief Swaps two any objects. - * @param lhs A valid any object. - * @param rhs A valid any object. - */ - friend void swap(basic_any &lhs, basic_any &rhs) { - basic_any tmp{}; - lhs.vtable(operation::MOVE, lhs, &tmp); - rhs.vtable(operation::MOVE, rhs, &lhs); - lhs.vtable(operation::MOVE, tmp, &rhs); - std::swap(lhs.vtable, rhs.vtable); - } - /** * @brief Aliasing constructor. * @return An any that shares a reference to an unmanaged object. @@ -14140,7 +14147,7 @@ Type any_cast(const basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(*instance); } @@ -14150,7 +14157,7 @@ Type any_cast(basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &&data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(std::move(*instance)); } @@ -15009,30 +15016,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -15952,7 +15935,7 @@ class basic_view, Component...> final { class iterable_view_iterator final { friend class iterable_view; - iterable_view_iterator(It from, const basic_view &parent) ENTT_NOEXCEPT + iterable_view_iterator(It from, const basic_view *parent) ENTT_NOEXCEPT : it{from}, view{parent} {} @@ -15974,7 +15957,7 @@ class basic_view, Component...> final { } [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat(std::make_tuple(*it), view.get(*it)); + return std::tuple_cat(std::make_tuple(*it), view->get(*it)); } [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT { @@ -15987,7 +15970,7 @@ class basic_view, Component...> final { private: It it; - const basic_view view; + const basic_view *view; }; iterable_view(const basic_view &parent) @@ -15999,19 +15982,19 @@ class basic_view, Component...> final { using reverse_iterator = iterable_view_iterator::reverse_iterator>>; [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return { view.begin(), view }; + return { view.begin(), &view }; } [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return { view.end(), view }; + return { view.end(), &view }; } [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return { view.rbegin(), view }; + return { view.rbegin(), &view }; } [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return { view.rend(), view }; + return { view.rend(), &view }; } private: @@ -16027,7 +16010,7 @@ class basic_view, Component...> final { [[nodiscard]] unchecked_type unchecked(const basic_sparse_set *cpool) const { std::size_t pos{}; unchecked_type other{}; - (static_cast(std::get *>(pools) == cpool ? nullptr : (other[pos] = std::get *>(pools), other[pos++])), ...); + (static_cast(std::get *>(pools) == cpool ? void() : void(other[pos++] = std::get *>(pools))), ...); return other; } @@ -16478,7 +16461,8 @@ public: /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() ENTT_NOEXCEPT - : pools{} + : pools{}, + filter{} {} /** @@ -16486,7 +16470,8 @@ public: * @param ref The storage for the type to iterate. */ basic_view(storage_type &ref) ENTT_NOEXCEPT - : pools{&ref} + : pools{&ref}, + filter{} {} /** @@ -16753,7 +16738,7 @@ private: * @param storage The storage for the types to iterate. */ template -basic_view(Storage &... storage) ENTT_NOEXCEPT +basic_view(Storage &... storage) -> basic_view, entt::exclude_t<>, constness_as_t...>; @@ -18672,7 +18657,8 @@ bool operator!=(const basic_handle &lhs, const basic_handle &rhs) E * @tparam Entity A valid entity type (see entt_traits for more details). */ template -basic_handle(basic_registry &, Entity) -> basic_handle; +basic_handle(basic_registry &, Entity) +-> basic_handle; /** @@ -18680,7 +18666,8 @@ basic_handle(basic_registry &, Entity) -> basic_handle; * @tparam Entity A valid entity type (see entt_traits for more details). */ template -basic_handle(const basic_registry &, Entity) -> basic_handle; +basic_handle(const basic_registry &, Entity) +-> basic_handle; } @@ -19038,7 +19025,7 @@ template * @tparam Candidate Function or member to connect to the delegate. */ template -delegate(connect_arg_t) ENTT_NOEXCEPT +delegate(connect_arg_t) -> delegate>>; @@ -19048,7 +19035,7 @@ delegate(connect_arg_t) ENTT_NOEXCEPT * @tparam Type Type of class or type of payload. */ template -delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT +delegate(connect_arg_t, Type &&) -> delegate>>; @@ -19058,7 +19045,7 @@ delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT * @tparam Args Types of arguments of a function type. */ template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT +delegate(Ret(*)(const void *, Args...), const void * = nullptr) -> delegate; @@ -19111,19 +19098,18 @@ private: /** * @brief Deduction guide. - * - * It allows to deduce the constness of a registry directly from the instance - * provided to the constructor. - * * @tparam Entity A valid entity type (see entt_traits for more details). */ template -as_view(basic_registry &) ENTT_NOEXCEPT -> as_view; +as_view(basic_registry &) -> as_view; -/*! @copydoc as_view */ +/** + * @brief Deduction guide. + * @tparam Entity A valid entity type (see entt_traits for more details). + */ template -as_view(const basic_registry &) ENTT_NOEXCEPT -> as_view; +as_view(const basic_registry &) -> as_view; /** @@ -19166,19 +19152,18 @@ private: /** * @brief Deduction guide. - * - * It allows to deduce the constness of a registry directly from the instance - * provided to the constructor. - * * @tparam Entity A valid entity type (see entt_traits for more details). */ template -as_group(basic_registry &) ENTT_NOEXCEPT -> as_group; +as_group(basic_registry &) -> as_group; -/*! @copydoc as_group */ +/** + * @brief Deduction guide. + * @tparam Entity A valid entity type (see entt_traits for more details). + */ template -as_group(const basic_registry &) ENTT_NOEXCEPT -> as_group; +as_group(const basic_registry &) -> as_group; @@ -19747,19 +19732,18 @@ private: /** * @brief Deduction guide. - * - * It allows to deduce the constness of a registry directly from the instance - * provided to the constructor. - * * @tparam Entity A valid entity type (see entt_traits for more details). */ template -as_view(basic_registry &) ENTT_NOEXCEPT -> as_view; +as_view(basic_registry &) -> as_view; -/*! @copydoc as_view */ +/** + * @brief Deduction guide. + * @tparam Entity A valid entity type (see entt_traits for more details). + */ template -as_view(const basic_registry &) ENTT_NOEXCEPT -> as_view; +as_view(const basic_registry &) -> as_view; /** @@ -19802,19 +19786,18 @@ private: /** * @brief Deduction guide. - * - * It allows to deduce the constness of a registry directly from the instance - * provided to the constructor. - * * @tparam Entity A valid entity type (see entt_traits for more details). */ template -as_group(basic_registry &) ENTT_NOEXCEPT -> as_group; +as_group(basic_registry &) -> as_group; -/*! @copydoc as_group */ +/** + * @brief Deduction guide. + * @tparam Entity A valid entity type (see entt_traits for more details). + */ template -as_group(const basic_registry &) ENTT_NOEXCEPT -> as_group; +as_group(const basic_registry &) -> as_group; @@ -24530,7 +24513,7 @@ class basic_view, Component...> final { class iterable_view_iterator final { friend class iterable_view; - iterable_view_iterator(It from, const basic_view &parent) ENTT_NOEXCEPT + iterable_view_iterator(It from, const basic_view *parent) ENTT_NOEXCEPT : it{from}, view{parent} {} @@ -24552,7 +24535,7 @@ class basic_view, Component...> final { } [[nodiscard]] reference operator*() const ENTT_NOEXCEPT { - return std::tuple_cat(std::make_tuple(*it), view.get(*it)); + return std::tuple_cat(std::make_tuple(*it), view->get(*it)); } [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT { @@ -24565,7 +24548,7 @@ class basic_view, Component...> final { private: It it; - const basic_view view; + const basic_view *view; }; iterable_view(const basic_view &parent) @@ -24577,19 +24560,19 @@ class basic_view, Component...> final { using reverse_iterator = iterable_view_iterator::reverse_iterator>>; [[nodiscard]] iterator begin() const ENTT_NOEXCEPT { - return { view.begin(), view }; + return { view.begin(), &view }; } [[nodiscard]] iterator end() const ENTT_NOEXCEPT { - return { view.end(), view }; + return { view.end(), &view }; } [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT { - return { view.rbegin(), view }; + return { view.rbegin(), &view }; } [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT { - return { view.rend(), view }; + return { view.rend(), &view }; } private: @@ -24605,7 +24588,7 @@ class basic_view, Component...> final { [[nodiscard]] unchecked_type unchecked(const basic_sparse_set *cpool) const { std::size_t pos{}; unchecked_type other{}; - (static_cast(std::get *>(pools) == cpool ? nullptr : (other[pos] = std::get *>(pools), other[pos++])), ...); + (static_cast(std::get *>(pools) == cpool ? void() : void(other[pos++] = std::get *>(pools))), ...); return other; } @@ -25056,7 +25039,8 @@ public: /*! @brief Default constructor to use to create empty, invalid views. */ basic_view() ENTT_NOEXCEPT - : pools{} + : pools{}, + filter{} {} /** @@ -25064,7 +25048,8 @@ public: * @param ref The storage for the type to iterate. */ basic_view(storage_type &ref) ENTT_NOEXCEPT - : pools{&ref} + : pools{&ref}, + filter{} {} /** @@ -25331,7 +25316,7 @@ private: * @param storage The storage for the types to iterate. */ template -basic_view(Storage &... storage) ENTT_NOEXCEPT +basic_view(Storage &... storage) -> basic_view, entt::exclude_t<>, constness_as_t...>; @@ -26310,30 +26295,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -27305,7 +27266,7 @@ private: * @param str Human-readable identifer. */ template -basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT +basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; @@ -27621,7 +27582,6 @@ template #define ENTT_META_META_HPP -#include #include #include #include @@ -28478,30 +28438,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -28620,117 +28556,151 @@ class basic_any { template static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - using base_type = std::remove_const_t>; + if constexpr(std::is_void_v) { + switch(op) { + case operation::COPY: + case operation::MOVE: + case operation::REF: + case operation::CREF: + as(to).vtable = from.vtable; + break; + default: + break; + } + } else if constexpr(std::is_lvalue_reference_v) { + using base_type = std::decay_t; - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).template emplace(*static_cast(from.instance)); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to) = *static_cast(from.instance); } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif + break; + case operation::MOVE: + as(to).instance = from.instance; + as(to).vtable = from.vtable; + [[fallthrough]]; + case operation::DTOR: + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + return std::is_const_v> ? nullptr : from.instance; + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else if constexpr(in_situ) { + #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L + auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); + #else + auto *instance = const_cast(reinterpret_cast(&from.storage)); + #endif - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - [[fallthrough]]; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + new (&as(to).storage) Type{std::as_const(*instance)}; + as(to).vtable = from.vtable; } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = from.instance; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + break; + case operation::MOVE: + new (&as(to).storage) Type{std::move(*instance)}; + as(to).vtable = from.vtable; + break; + case operation::DTOR: + instance->~Type(); + break; + case operation::COMP: + return compare(instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return instance; + case operation::REF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else { + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to).instance = new Type{*static_cast(from.instance)}; + as(to).vtable = from.vtable; } + break; + case operation::MOVE: + as(to).instance = std::exchange(as(&from).instance, nullptr); + as(to).vtable = from.vtable; + break; + case operation::DTOR: + if constexpr(std::is_array_v) { + delete[] static_cast(from.instance); + } else { + delete static_cast(from.instance); + } + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; } } return nullptr; } + template + void initialize([[maybe_unused]] Args &&... args) { + if constexpr(!std::is_void_v) { + if constexpr(std::is_lvalue_reference_v) { + static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); + instance = (std::addressof(args), ...); + } else if constexpr(in_situ) { + if constexpr(std::is_aggregate_v) { + new (&storage) Type{std::forward(args)...}; + } else { + new (&storage) Type(std::forward(args)...); + } + } else { + if constexpr(std::is_aggregate_v) { + instance = new Type{std::forward(args)...}; + } else { + instance = new Type(std::forward(args)...); + } + } + } + } + public: /*! @brief Default constructor. */ basic_any() ENTT_NOEXCEPT @@ -28744,20 +28714,11 @@ public: * @param args Parameters to use to construct the instance. */ template - explicit basic_any(std::in_place_type_t, [[maybe_unused]] Args &&... args) + explicit basic_any(std::in_place_type_t, Args &&... args) : instance{}, vtable{&basic_vtable} { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - new (&storage) Type(std::forward(args)...); - } else { - instance = new Type(std::forward(args)...); - } - } + initialize(std::forward(args)...); } /** @@ -28785,7 +28746,7 @@ public: * @param other The instance to copy from. */ basic_any(const basic_any &other) - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::COPY, other, this); } @@ -28795,10 +28756,9 @@ public: * @param other The instance to move from. */ basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::MOVE, other, this); - vtable = std::exchange(other.vtable, &basic_vtable); } /*! @brief Frees the internal storage, whatever it means. */ @@ -28807,12 +28767,49 @@ public: } /** - * @brief Assignment operator. - * @param other The instance to assign from. + * @brief Copy assignment operator. + * @param other The instance to copy from. * @return This any object. */ - basic_any & operator=(basic_any other) { - swap(*this, other); + basic_any & operator=(const basic_any &other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::COPY, other, this); + return *this; + } + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This any object. + */ + basic_any & operator=(basic_any &&other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::MOVE, other, this); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { + emplace(value.get()); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + std::enable_if_t, basic_any>, basic_any &> + operator=(Type &&value) { + emplace>(std::forward(value)); return *this; } @@ -28821,7 +28818,7 @@ public: * @return The type of the contained object, if any. */ [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info; + type_info info{}; vtable(operation::TYPE, *this, &info); return info; } @@ -28847,12 +28844,13 @@ public: */ template void emplace(Args &&... args) { - *this = basic_any{std::in_place_type, std::forward(args)...}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); + initialize(std::forward(args)...); } /*! @brief Destroys contained object */ void reset() { - *this = basic_any{}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); } /** @@ -28872,19 +28870,6 @@ public: return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); } - /** - * @brief Swaps two any objects. - * @param lhs A valid any object. - * @param rhs A valid any object. - */ - friend void swap(basic_any &lhs, basic_any &rhs) { - basic_any tmp{}; - lhs.vtable(operation::MOVE, lhs, &tmp); - rhs.vtable(operation::MOVE, rhs, &lhs); - lhs.vtable(operation::MOVE, tmp, &rhs); - std::swap(lhs.vtable, rhs.vtable); - } - /** * @brief Aliasing constructor. * @return An any that shares a reference to an unmanaged object. @@ -28942,7 +28927,7 @@ Type any_cast(const basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(*instance); } @@ -28952,7 +28937,7 @@ Type any_cast(basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &&data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(std::move(*instance)); } @@ -29044,7 +29029,8 @@ struct overloaded: Func... { * @tparam Func Types of function objects. */ template -overloaded(Func...) -> overloaded; +overloaded(Func...) +-> overloaded; /** @@ -29211,7 +29197,6 @@ private: #define ENTT_META_NODE_HPP -#include #include #include #include @@ -29251,8 +29236,8 @@ struct meta_type_node; struct meta_prop_node { meta_prop_node * next; - const meta_any * const id; - meta_any * const value; + const meta_any &id; + meta_any &value; }; @@ -29449,7 +29434,7 @@ public: meta_template_descriptor(), std::rank_v, [](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence>{}); }, - &meta_node>>::resolve, + &meta_node>>>::resolve, &meta_node>>>::resolve, meta_default_constructor(&node), meta_default_constructor(&node) @@ -29466,7 +29451,8 @@ struct meta_info: meta_node>> {}; template meta_type_node * meta_arg_node(type_list, const std::size_t index) ENTT_NOEXCEPT { - return std::array{{internal::meta_info::resolve()...}}[index]; + meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info::resolve()...}; + return args[index + 1u]; } @@ -29732,8 +29718,6 @@ class meta_any { template static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) { if constexpr(!std::is_void_v) { - using base_type = std::remove_const_t>; - switch(op) { case operation::DTOR: if constexpr(!std::is_lvalue_reference_v) { @@ -29744,39 +29728,37 @@ class meta_any { break; case operation::REF: case operation::CREF: - *static_cast(to) = (op == operation::REF ? meta_any{std::ref(any_cast(const_cast(from)))} : meta_any{std::cref(any_cast(from))}); + *static_cast(to) = (op == operation::REF ? meta_any{std::ref(any_cast(const_cast(from)))} : meta_any{std::cref(any_cast &>(from))}); break; case operation::DEREF: case operation::CDEREF: - if constexpr(is_meta_pointer_like_v) { - // for some reason vs2017 doesn't compile when using alias declarations with pointer_traits to get the element type - using element_type = std::remove_const_t>>::element_type>; + if constexpr(is_meta_pointer_like_v>) { + using element_type = std::remove_const_t>::element_type>; if constexpr(std::is_function_v) { - *static_cast(to) = any_cast(from); + *static_cast(to) = any_cast>(from); } else if constexpr(!std::is_same_v) { - // for some reason vs2017 doesn't compile when using alias declarations with adl_meta_pointer_like - using adl_meta_pointer_like_type = adl_meta_pointer_like>>; + using adl_meta_pointer_like_type = adl_meta_pointer_like>; - if constexpr(std::is_lvalue_reference_v()))>) { - auto &&obj = adl_meta_pointer_like_type::dereference(any_cast(from)); + if constexpr(std::is_lvalue_reference_v &>()))>) { + auto &&obj = adl_meta_pointer_like_type::dereference(any_cast &>(from)); *static_cast(to) = (op == operation::DEREF ? meta_any{std::ref(obj)} : meta_any{std::cref(obj)}); } else { - *static_cast(to) = adl_meta_pointer_like_type::dereference(any_cast(from)); + *static_cast(to) = adl_meta_pointer_like_type::dereference(any_cast &>(from)); } } } break; case operation::SEQ: case operation::CSEQ: - if constexpr(is_complete_v>) { - *static_cast(to) = { std::in_place_type, (op == operation::SEQ ? const_cast(from).as_ref() : from.as_ref()) }; + if constexpr(is_complete_v>>) { + *static_cast(to) = { std::in_place_type>, (op == operation::SEQ ? const_cast(from).as_ref() : from.as_ref()) }; } break; case operation::ASSOC: case operation::CASSOC: - if constexpr(is_complete_v>) { - *static_cast(to) = { std::in_place_type, (op == operation::ASSOC ? const_cast(from).as_ref() : from.as_ref()) }; + if constexpr(is_complete_v>>) { + *static_cast(to) = { std::in_place_type>, (op == operation::ASSOC ? const_cast(from).as_ref() : from.as_ref()) }; } break; } @@ -29799,7 +29781,7 @@ public: */ template explicit meta_any(std::in_place_type_t, Args &&... args) - : storage(std::in_place_type, std::forward(args)...), + : storage{std::in_place_type, std::forward(args)...}, node{internal::meta_info::resolve()}, vtable{&basic_vtable} {} @@ -29819,9 +29801,9 @@ public: * @tparam Type Type of object to use to initialize the wrapper. * @param value An instance of an object to use to initialize the wrapper. */ - template>, meta_any>>> + template, meta_any>>> meta_any(Type &&value) - : meta_any{std::in_place_type>>, std::forward(value)} + : meta_any{std::in_place_type>, std::forward(value)} {} /** @@ -29835,25 +29817,62 @@ public: * @param other The instance to move from. */ meta_any(meta_any &&other) ENTT_NOEXCEPT - : meta_any{} - { - swap(*this, other); - } + : storage{std::move(other.storage)}, + node{std::exchange(other.node, nullptr)}, + vtable{std::exchange(other.vtable, &basic_vtable)} + {} /*! @brief Frees the internal storage, whatever it means. */ ~meta_any() { - if(vtable) { - vtable(operation::DTOR, storage, node); - } + vtable(operation::DTOR, storage, node); } /** - * @brief Assignment operator. - * @param other The instance to assign from. + * @brief Copy assignment operator. + * @param other The instance to copy from. * @return This meta any object. */ - meta_any & operator=(meta_any other) { - swap(other, *this); + meta_any & operator=(const meta_any &other) { + std::exchange(vtable, other.vtable)(operation::DTOR, storage, node); + storage = other.storage; + node = other.node; + return *this; + } + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This meta any object. + */ + meta_any & operator=(meta_any &&other) { + std::exchange(vtable, std::exchange(other.vtable, &basic_vtable))(operation::DTOR, storage, node); + storage = std::move(other.storage); + node = std::exchange(other.node, nullptr); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This meta any object. + */ + template + meta_any & operator=(std::reference_wrapper value) { + emplace(value.get()); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This meta any object. + */ + template + std::enable_if_t, meta_any>, meta_any &> + operator=(Type &&value) { + emplace>(std::forward(value)); return *this; } @@ -29971,9 +29990,9 @@ public: template [[nodiscard]] Type cast() { // forces const on non-reference types to make them work also with wrappers for const references - auto * const actual = try_cast, std::remove_reference_t, const Type>>(); - ENTT_ASSERT(actual); - return static_cast(*actual); + auto * const instance = try_cast>(); + ENTT_ASSERT(instance); + return static_cast(*instance); } /** @@ -30002,7 +30021,8 @@ public: */ template bool allow_cast() { - if(try_cast, std::remove_reference_t, const Type>>() != nullptr) { + // forces const on non-reference types to make them work also with wrappers for const references + if(try_cast>() != nullptr) { return true; } else if(node) { if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id()](const auto *curr) { return curr->type()->info == info; }, node); conv) { @@ -30022,12 +30042,16 @@ public: */ template void emplace(Args &&... args) { - *this = meta_any{std::in_place_type, std::forward(args)...}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); + storage.emplace(std::forward(args)...); + node = internal::meta_info::resolve(); } /*! @brief Destroys contained object */ void reset() { - *this = meta_any{}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); + storage.reset(); + node = nullptr; } /** @@ -30099,18 +30123,6 @@ public: return (!node && !other.node) || (node && other.node && node->info == other.node->info && storage == other.storage); } - /** - * @brief Swaps two meta any objects. - * @param lhs A valid meta any object. - * @param rhs A valid meta any object. - */ - friend void swap(meta_any &lhs, meta_any &rhs) { - using std::swap; - swap(lhs.storage, rhs.storage); - swap(lhs.vtable, rhs.vtable); - swap(lhs.node, rhs.node); - } - /** * @brief Aliasing constructor. * @return A meta any that shares a reference to an unmanaged object. @@ -30181,11 +30193,11 @@ struct meta_handle { * @tparam Type Type of object to use to initialize the handle. * @param value An instance of an object to use to initialize the handle. */ - template>, meta_handle>>> + template, meta_handle>>> meta_handle(Type &value) ENTT_NOEXCEPT : meta_handle{} { - if constexpr(std::is_same_v>, meta_any>) { + if constexpr(std::is_same_v, meta_any>) { any = value.as_ref(); } else { any.emplace(value); @@ -30236,7 +30248,7 @@ struct meta_prop { * @return A meta any containing the key stored with the property. */ [[nodiscard]] meta_any key() const { - return node->id->as_ref(); + return node->id.as_ref(); } /** @@ -30244,7 +30256,7 @@ struct meta_prop { * @return A meta any containing the value stored with the property. */ [[nodiscard]] meta_any value() const { - return *node->value; + return node->value; } /** @@ -30318,8 +30330,8 @@ struct meta_ctor { */ template [[nodiscard]] meta_any invoke([[maybe_unused]] Args &&... args) const { - std::array arguments{std::forward(args)...}; - return invoke(arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return invoke(arguments, sizeof...(Args)); } /** @@ -30336,7 +30348,7 @@ struct meta_ctor { * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -30432,7 +30444,7 @@ struct meta_data { * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -30536,8 +30548,8 @@ struct meta_func { */ template meta_any invoke(meta_handle instance, Args &&... args) const { - std::array arguments{std::forward(args)...}; - return invoke(std::move(instance), arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return invoke(std::move(instance), arguments, sizeof...(Args)); } /*! @copydoc meta_ctor::prop */ @@ -30551,7 +30563,7 @@ struct meta_func { * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -30941,8 +30953,8 @@ public: */ template [[nodiscard]] meta_any construct(Args &&... args) const { - std::array arguments{std::forward(args)...}; - return construct(arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return construct(arguments, sizeof...(Args)); } /** @@ -31002,8 +31014,8 @@ public: */ template meta_any invoke(const id_type id, meta_handle instance, Args &&... args) const { - std::array arguments{std::forward(args)...}; - return invoke(id, std::move(instance), arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return invoke(id, std::move(instance), arguments, sizeof...(Args)); } /** @@ -31059,7 +31071,7 @@ public: * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -31796,7 +31808,6 @@ struct as_void_t {}; #define ENTT_META_UTILITY_HPP -#include #include #include #include @@ -32191,8 +32202,8 @@ private: static internal::meta_prop_node node{ nullptr, - property, - property + 1u + property[0u], + property[1u] }; entt::meta_any instance{std::forward(key)}; @@ -32394,7 +32405,7 @@ struct meta_factory { template auto ctor() ENTT_NOEXCEPT { using descriptor = meta_function_helper_t; - static_assert(std::is_same_v>, Type>, "The function doesn't return an object of the required type"); + static_assert(std::is_same_v, Type>, "The function doesn't return an object of the required type"); auto * const type = internal::meta_info::resolve(); static internal::meta_ctor_node node{ @@ -32659,7 +32670,6 @@ template #define ENTT_META_META_HPP -#include #include #include #include @@ -32832,8 +32842,6 @@ class meta_any { template static void basic_vtable(const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] void *to) { if constexpr(!std::is_void_v) { - using base_type = std::remove_const_t>; - switch(op) { case operation::DTOR: if constexpr(!std::is_lvalue_reference_v) { @@ -32844,39 +32852,37 @@ class meta_any { break; case operation::REF: case operation::CREF: - *static_cast(to) = (op == operation::REF ? meta_any{std::ref(any_cast(const_cast(from)))} : meta_any{std::cref(any_cast(from))}); + *static_cast(to) = (op == operation::REF ? meta_any{std::ref(any_cast(const_cast(from)))} : meta_any{std::cref(any_cast &>(from))}); break; case operation::DEREF: case operation::CDEREF: - if constexpr(is_meta_pointer_like_v) { - // for some reason vs2017 doesn't compile when using alias declarations with pointer_traits to get the element type - using element_type = std::remove_const_t>>::element_type>; + if constexpr(is_meta_pointer_like_v>) { + using element_type = std::remove_const_t>::element_type>; if constexpr(std::is_function_v) { - *static_cast(to) = any_cast(from); + *static_cast(to) = any_cast>(from); } else if constexpr(!std::is_same_v) { - // for some reason vs2017 doesn't compile when using alias declarations with adl_meta_pointer_like - using adl_meta_pointer_like_type = adl_meta_pointer_like>>; + using adl_meta_pointer_like_type = adl_meta_pointer_like>; - if constexpr(std::is_lvalue_reference_v()))>) { - auto &&obj = adl_meta_pointer_like_type::dereference(any_cast(from)); + if constexpr(std::is_lvalue_reference_v &>()))>) { + auto &&obj = adl_meta_pointer_like_type::dereference(any_cast &>(from)); *static_cast(to) = (op == operation::DEREF ? meta_any{std::ref(obj)} : meta_any{std::cref(obj)}); } else { - *static_cast(to) = adl_meta_pointer_like_type::dereference(any_cast(from)); + *static_cast(to) = adl_meta_pointer_like_type::dereference(any_cast &>(from)); } } } break; case operation::SEQ: case operation::CSEQ: - if constexpr(is_complete_v>) { - *static_cast(to) = { std::in_place_type, (op == operation::SEQ ? const_cast(from).as_ref() : from.as_ref()) }; + if constexpr(is_complete_v>>) { + *static_cast(to) = { std::in_place_type>, (op == operation::SEQ ? const_cast(from).as_ref() : from.as_ref()) }; } break; case operation::ASSOC: case operation::CASSOC: - if constexpr(is_complete_v>) { - *static_cast(to) = { std::in_place_type, (op == operation::ASSOC ? const_cast(from).as_ref() : from.as_ref()) }; + if constexpr(is_complete_v>>) { + *static_cast(to) = { std::in_place_type>, (op == operation::ASSOC ? const_cast(from).as_ref() : from.as_ref()) }; } break; } @@ -32899,7 +32905,7 @@ public: */ template explicit meta_any(std::in_place_type_t, Args &&... args) - : storage(std::in_place_type, std::forward(args)...), + : storage{std::in_place_type, std::forward(args)...}, node{internal::meta_info::resolve()}, vtable{&basic_vtable} {} @@ -32919,9 +32925,9 @@ public: * @tparam Type Type of object to use to initialize the wrapper. * @param value An instance of an object to use to initialize the wrapper. */ - template>, meta_any>>> + template, meta_any>>> meta_any(Type &&value) - : meta_any{std::in_place_type>>, std::forward(value)} + : meta_any{std::in_place_type>, std::forward(value)} {} /** @@ -32935,25 +32941,62 @@ public: * @param other The instance to move from. */ meta_any(meta_any &&other) ENTT_NOEXCEPT - : meta_any{} - { - swap(*this, other); - } + : storage{std::move(other.storage)}, + node{std::exchange(other.node, nullptr)}, + vtable{std::exchange(other.vtable, &basic_vtable)} + {} /*! @brief Frees the internal storage, whatever it means. */ ~meta_any() { - if(vtable) { - vtable(operation::DTOR, storage, node); - } + vtable(operation::DTOR, storage, node); } /** - * @brief Assignment operator. - * @param other The instance to assign from. + * @brief Copy assignment operator. + * @param other The instance to copy from. * @return This meta any object. */ - meta_any & operator=(meta_any other) { - swap(other, *this); + meta_any & operator=(const meta_any &other) { + std::exchange(vtable, other.vtable)(operation::DTOR, storage, node); + storage = other.storage; + node = other.node; + return *this; + } + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This meta any object. + */ + meta_any & operator=(meta_any &&other) { + std::exchange(vtable, std::exchange(other.vtable, &basic_vtable))(operation::DTOR, storage, node); + storage = std::move(other.storage); + node = std::exchange(other.node, nullptr); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This meta any object. + */ + template + meta_any & operator=(std::reference_wrapper value) { + emplace(value.get()); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This meta any object. + */ + template + std::enable_if_t, meta_any>, meta_any &> + operator=(Type &&value) { + emplace>(std::forward(value)); return *this; } @@ -33071,9 +33114,9 @@ public: template [[nodiscard]] Type cast() { // forces const on non-reference types to make them work also with wrappers for const references - auto * const actual = try_cast, std::remove_reference_t, const Type>>(); - ENTT_ASSERT(actual); - return static_cast(*actual); + auto * const instance = try_cast>(); + ENTT_ASSERT(instance); + return static_cast(*instance); } /** @@ -33102,7 +33145,8 @@ public: */ template bool allow_cast() { - if(try_cast, std::remove_reference_t, const Type>>() != nullptr) { + // forces const on non-reference types to make them work also with wrappers for const references + if(try_cast>() != nullptr) { return true; } else if(node) { if(const auto * const conv = internal::meta_visit<&internal::meta_type_node::conv>([info = type_id()](const auto *curr) { return curr->type()->info == info; }, node); conv) { @@ -33122,12 +33166,16 @@ public: */ template void emplace(Args &&... args) { - *this = meta_any{std::in_place_type, std::forward(args)...}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); + storage.emplace(std::forward(args)...); + node = internal::meta_info::resolve(); } /*! @brief Destroys contained object */ void reset() { - *this = meta_any{}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, storage, node); + storage.reset(); + node = nullptr; } /** @@ -33199,18 +33247,6 @@ public: return (!node && !other.node) || (node && other.node && node->info == other.node->info && storage == other.storage); } - /** - * @brief Swaps two meta any objects. - * @param lhs A valid meta any object. - * @param rhs A valid meta any object. - */ - friend void swap(meta_any &lhs, meta_any &rhs) { - using std::swap; - swap(lhs.storage, rhs.storage); - swap(lhs.vtable, rhs.vtable); - swap(lhs.node, rhs.node); - } - /** * @brief Aliasing constructor. * @return A meta any that shares a reference to an unmanaged object. @@ -33281,11 +33317,11 @@ struct meta_handle { * @tparam Type Type of object to use to initialize the handle. * @param value An instance of an object to use to initialize the handle. */ - template>, meta_handle>>> + template, meta_handle>>> meta_handle(Type &value) ENTT_NOEXCEPT : meta_handle{} { - if constexpr(std::is_same_v>, meta_any>) { + if constexpr(std::is_same_v, meta_any>) { any = value.as_ref(); } else { any.emplace(value); @@ -33336,7 +33372,7 @@ struct meta_prop { * @return A meta any containing the key stored with the property. */ [[nodiscard]] meta_any key() const { - return node->id->as_ref(); + return node->id.as_ref(); } /** @@ -33344,7 +33380,7 @@ struct meta_prop { * @return A meta any containing the value stored with the property. */ [[nodiscard]] meta_any value() const { - return *node->value; + return node->value; } /** @@ -33418,8 +33454,8 @@ struct meta_ctor { */ template [[nodiscard]] meta_any invoke([[maybe_unused]] Args &&... args) const { - std::array arguments{std::forward(args)...}; - return invoke(arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return invoke(arguments, sizeof...(Args)); } /** @@ -33436,7 +33472,7 @@ struct meta_ctor { * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -33532,7 +33568,7 @@ struct meta_data { * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -33636,8 +33672,8 @@ struct meta_func { */ template meta_any invoke(meta_handle instance, Args &&... args) const { - std::array arguments{std::forward(args)...}; - return invoke(std::move(instance), arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return invoke(std::move(instance), arguments, sizeof...(Args)); } /*! @copydoc meta_ctor::prop */ @@ -33651,7 +33687,7 @@ struct meta_func { * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -34041,8 +34077,8 @@ public: */ template [[nodiscard]] meta_any construct(Args &&... args) const { - std::array arguments{std::forward(args)...}; - return construct(arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return construct(arguments, sizeof...(Args)); } /** @@ -34102,8 +34138,8 @@ public: */ template meta_any invoke(const id_type id, meta_handle instance, Args &&... args) const { - std::array arguments{std::forward(args)...}; - return invoke(id, std::move(instance), arguments.data(), sizeof...(Args)); + meta_any arguments[sizeof...(Args) + 1u]{std::forward(args)...}; + return invoke(id, std::move(instance), arguments, sizeof...(Args)); } /** @@ -34159,7 +34195,7 @@ public: * @return The property associated with the given key, if any. */ [[nodiscard]] meta_prop prop(meta_any key) const { - return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return *curr->id == key; }, node); + return internal::meta_visit<&node_type::prop>([&key](const auto *curr) { return curr->id == key; }, node); } /** @@ -34865,7 +34901,6 @@ inline bool meta_associative_container::erase(meta_any key) { #define ENTT_META_NODE_HPP -#include #include #include #include @@ -34905,8 +34940,8 @@ struct meta_type_node; struct meta_prop_node { meta_prop_node * next; - const meta_any * const id; - meta_any * const value; + const meta_any &id; + meta_any &value; }; @@ -35103,7 +35138,7 @@ public: meta_template_descriptor(), std::rank_v, [](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence>{}); }, - &meta_node>>::resolve, + &meta_node>>>::resolve, &meta_node>>>::resolve, meta_default_constructor(&node), meta_default_constructor(&node) @@ -35120,7 +35155,8 @@ struct meta_info: meta_node>> {}; template meta_type_node * meta_arg_node(type_list, const std::size_t index) ENTT_NOEXCEPT { - return std::array{{internal::meta_info::resolve()...}}[index]; + meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info::resolve()...}; + return args[index + 1u]; } @@ -35162,6 +35198,17 @@ struct is_meta_pointer_like {}; +/** + * @brief Partial specialization used to reject pointers to arrays. + * @tparam Type Type of elements of the array. + * @tparam N Number of elements of the array. + */ +template +struct is_meta_pointer_like + : std::false_type +{}; + + /** * @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta * system. @@ -35531,7 +35578,6 @@ inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like::value #define ENTT_META_UTILITY_HPP -#include #include #include #include @@ -36358,7 +36404,7 @@ private: * @param str Human-readable identifer. */ template -basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT +basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; @@ -37234,30 +37280,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -37376,117 +37398,151 @@ class basic_any { template static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - using base_type = std::remove_const_t>; + if constexpr(std::is_void_v) { + switch(op) { + case operation::COPY: + case operation::MOVE: + case operation::REF: + case operation::CREF: + as(to).vtable = from.vtable; + break; + default: + break; + } + } else if constexpr(std::is_lvalue_reference_v) { + using base_type = std::decay_t; - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).template emplace(*static_cast(from.instance)); - } - break; - case operation::MOVE: - as(to).instance = from.instance; - [[fallthrough]]; - case operation::DTOR: - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - return std::is_const_v> ? nullptr : from.instance; - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to) = *static_cast(from.instance); } - } else if constexpr(in_situ) { - #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L - auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); - #else - auto *instance = const_cast(reinterpret_cast(&from.storage)); - #endif + break; + case operation::MOVE: + as(to).instance = from.instance; + as(to).vtable = from.vtable; + [[fallthrough]]; + case operation::DTOR: + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + return std::is_const_v> ? nullptr : from.instance; + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else if constexpr(in_situ) { + #if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L + auto *instance = const_cast(std::launder(reinterpret_cast(&from.storage))); + #else + auto *instance = const_cast(reinterpret_cast(&from.storage)); + #endif - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - new (&as(to).storage) Type{std::as_const(*instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - new (&as(to).storage) Type{std::move(*instance)}; - [[fallthrough]]; - case operation::DTOR: - instance->~Type(); - break; - case operation::COMP: - return compare(instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return instance; - case operation::REF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + new (&as(to).storage) Type{std::as_const(*instance)}; + as(to).vtable = from.vtable; } - } else { - switch(op) { - case operation::COPY: - if constexpr(std::is_copy_constructible_v) { - as(to).instance = new Type{*static_cast(from.instance)}; - as(to).vtable = from.vtable; - } - break; - case operation::MOVE: - as(to).instance = from.instance; - break; - case operation::DTOR: - if constexpr(std::is_array_v) { - delete[] static_cast(from.instance); - } else { - delete static_cast(from.instance); - } - break; - case operation::COMP: - return compare(from.instance, to) ? to : nullptr; - case operation::ADDR: - case operation::CADDR: - return from.instance; - case operation::REF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::CREF: - as(to).instance = from.instance; - as(to).vtable = basic_vtable; - break; - case operation::TYPE: - as(to) = type_id(); - break; + break; + case operation::MOVE: + new (&as(to).storage) Type{std::move(*instance)}; + as(to).vtable = from.vtable; + break; + case operation::DTOR: + instance->~Type(); + break; + case operation::COMP: + return compare(instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return instance; + case operation::REF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; + } + } else { + switch(op) { + case operation::COPY: + if constexpr(std::is_copy_constructible_v) { + as(to).instance = new Type{*static_cast(from.instance)}; + as(to).vtable = from.vtable; } + break; + case operation::MOVE: + as(to).instance = std::exchange(as(&from).instance, nullptr); + as(to).vtable = from.vtable; + break; + case operation::DTOR: + if constexpr(std::is_array_v) { + delete[] static_cast(from.instance); + } else { + delete static_cast(from.instance); + } + break; + case operation::COMP: + return compare(from.instance, to) ? to : nullptr; + case operation::ADDR: + case operation::CADDR: + return from.instance; + case operation::REF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::CREF: + as(to).instance = from.instance; + as(to).vtable = basic_vtable; + break; + case operation::TYPE: + as(to) = type_id(); + break; } } return nullptr; } + template + void initialize([[maybe_unused]] Args &&... args) { + if constexpr(!std::is_void_v) { + if constexpr(std::is_lvalue_reference_v) { + static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); + instance = (std::addressof(args), ...); + } else if constexpr(in_situ) { + if constexpr(std::is_aggregate_v) { + new (&storage) Type{std::forward(args)...}; + } else { + new (&storage) Type(std::forward(args)...); + } + } else { + if constexpr(std::is_aggregate_v) { + instance = new Type{std::forward(args)...}; + } else { + instance = new Type(std::forward(args)...); + } + } + } + } + public: /*! @brief Default constructor. */ basic_any() ENTT_NOEXCEPT @@ -37500,20 +37556,11 @@ public: * @param args Parameters to use to construct the instance. */ template - explicit basic_any(std::in_place_type_t, [[maybe_unused]] Args &&... args) + explicit basic_any(std::in_place_type_t, Args &&... args) : instance{}, vtable{&basic_vtable} { - if constexpr(!std::is_void_v) { - if constexpr(std::is_lvalue_reference_v) { - static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v && ...), "Invalid arguments"); - instance = (std::addressof(args), ...); - } else if constexpr(in_situ) { - new (&storage) Type(std::forward(args)...); - } else { - instance = new Type(std::forward(args)...); - } - } + initialize(std::forward(args)...); } /** @@ -37541,7 +37588,7 @@ public: * @param other The instance to copy from. */ basic_any(const basic_any &other) - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::COPY, other, this); } @@ -37551,10 +37598,9 @@ public: * @param other The instance to move from. */ basic_any(basic_any &&other) ENTT_NOEXCEPT - : basic_any{} + : basic_any{std::in_place_type} { other.vtable(operation::MOVE, other, this); - vtable = std::exchange(other.vtable, &basic_vtable); } /*! @brief Frees the internal storage, whatever it means. */ @@ -37563,12 +37609,49 @@ public: } /** - * @brief Assignment operator. - * @param other The instance to assign from. + * @brief Copy assignment operator. + * @param other The instance to copy from. * @return This any object. */ - basic_any & operator=(basic_any other) { - swap(*this, other); + basic_any & operator=(const basic_any &other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::COPY, other, this); + return *this; + } + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This any object. + */ + basic_any & operator=(basic_any &&other) { + vtable(operation::DTOR, *this, nullptr); + other.vtable(operation::MOVE, other, this); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + basic_any & operator=(std::reference_wrapper value) ENTT_NOEXCEPT { + emplace(value.get()); + return *this; + } + + /** + * @brief Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This any object. + */ + template + std::enable_if_t, basic_any>, basic_any &> + operator=(Type &&value) { + emplace>(std::forward(value)); return *this; } @@ -37577,7 +37660,7 @@ public: * @return The type of the contained object, if any. */ [[nodiscard]] type_info type() const ENTT_NOEXCEPT { - type_info info; + type_info info{}; vtable(operation::TYPE, *this, &info); return info; } @@ -37603,12 +37686,13 @@ public: */ template void emplace(Args &&... args) { - *this = basic_any{std::in_place_type, std::forward(args)...}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); + initialize(std::forward(args)...); } /*! @brief Destroys contained object */ void reset() { - *this = basic_any{}; + std::exchange(vtable, &basic_vtable)(operation::DTOR, *this, nullptr); } /** @@ -37628,19 +37712,6 @@ public: return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data()); } - /** - * @brief Swaps two any objects. - * @param lhs A valid any object. - * @param rhs A valid any object. - */ - friend void swap(basic_any &lhs, basic_any &rhs) { - basic_any tmp{}; - lhs.vtable(operation::MOVE, lhs, &tmp); - rhs.vtable(operation::MOVE, rhs, &lhs); - lhs.vtable(operation::MOVE, tmp, &rhs); - std::swap(lhs.vtable, rhs.vtable); - } - /** * @brief Aliasing constructor. * @return An any that shares a reference to an unmanaged object. @@ -37698,7 +37769,7 @@ Type any_cast(const basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(*instance); } @@ -37708,7 +37779,7 @@ Type any_cast(basic_any &data) ENTT_NOEXCEPT { template Type any_cast(basic_any &&data) ENTT_NOEXCEPT { // forces const on non-reference types to make them work also with wrappers for const references - auto * const instance = any_cast, std::remove_reference_t, const Type>>(&data); + auto * const instance = any_cast>(&data); ENTT_ASSERT(instance); return static_cast(std::move(*instance)); } @@ -38567,30 +38638,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -41529,30 +41576,6 @@ template inline constexpr auto is_complete_v = is_complete::value; -/** - * @brief Provides the member constant `value` to true if a given type is - * hashable, false otherwise. - * @tparam Type Potentially hashable type. - */ -template -struct is_std_hashable: std::false_type {}; - - -/*! @copydoc is_std_hashable */ -template -struct is_std_hashable>()(std::declval())), std::size_t>>> - : std::true_type -{}; - - -/** - * @brief Helper variable template. - * @tparam Type Potentially hashable type. - */ -template -inline constexpr auto is_std_hashable_v = is_std_hashable::value; - - /** * @brief Provides the member constant `value` to true if a given type is empty * and the empty type optimization is enabled, false otherwise. @@ -42025,7 +42048,7 @@ template * @tparam Candidate Function or member to connect to the delegate. */ template -delegate(connect_arg_t) ENTT_NOEXCEPT +delegate(connect_arg_t) -> delegate>>; @@ -42035,7 +42058,7 @@ delegate(connect_arg_t) ENTT_NOEXCEPT * @tparam Type Type of class or type of payload. */ template -delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT +delegate(connect_arg_t, Type &&) -> delegate>>; @@ -42045,7 +42068,7 @@ delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT * @tparam Args Types of arguments of a function type. */ template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT +delegate(Ret(*)(const void *, Args...), const void * = nullptr) -> delegate; @@ -42357,7 +42380,7 @@ private: * @param str Human-readable identifer. */ template -basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT +basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; @@ -43019,7 +43042,7 @@ template * @tparam Candidate Function or member to connect to the delegate. */ template -delegate(connect_arg_t) ENTT_NOEXCEPT +delegate(connect_arg_t) -> delegate>>; @@ -43029,7 +43052,7 @@ delegate(connect_arg_t) ENTT_NOEXCEPT * @tparam Type Type of class or type of payload. */ template -delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT +delegate(connect_arg_t, Type &&) -> delegate>>; @@ -43039,7 +43062,7 @@ delegate(connect_arg_t, Type &&) ENTT_NOEXCEPT * @tparam Args Types of arguments of a function type. */ template -delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT +delegate(Ret(*)(const void *, Args...), const void * = nullptr) -> delegate; @@ -43585,7 +43608,8 @@ private: * @tparam Args Types of arguments of a function type. */ template -sink(sigh &) ENTT_NOEXCEPT -> sink; +sink(sigh &) +-> sink; } @@ -44706,7 +44730,8 @@ private: * @tparam Args Types of arguments of a function type. */ template -sink(sigh &) ENTT_NOEXCEPT -> sink; +sink(sigh &) +-> sink; }