diff options
| author | untodesu <kirill@untode.su> | 2025-06-28 01:59:49 +0500 |
|---|---|---|
| committer | untodesu <kirill@untode.su> | 2025-06-28 01:59:49 +0500 |
| commit | 61e5bcef2629e2d68b805a956a96fff264d4f74d (patch) | |
| tree | bca3a94bac79d34e3c0db57c77604f5a823ecbda /deps/include/entt/entity | |
| parent | 88c01588aa0830e219eaa62588839e4d1e2883ce (diff) | |
| download | voxelius-61e5bcef2629e2d68b805a956a96fff264d4f74d.tar.bz2 voxelius-61e5bcef2629e2d68b805a956a96fff264d4f74d.zip | |
Restructure dependencies and update to C++20
- Nuked static_assert from almost everywhere in the project
- Nuked binary dependency support. Might add one later though
- Separated dependency headers into a separate include subdirectory
- Grafted a thirdpartylegalnotices.txt generator from RITEG
- Pushed development snapshot version to 2126 (26th week of 2025)
Diffstat (limited to 'deps/include/entt/entity')
| -rw-r--r-- | deps/include/entt/entity/component.hpp | 56 | ||||
| -rw-r--r-- | deps/include/entt/entity/entity.hpp | 388 | ||||
| -rw-r--r-- | deps/include/entt/entity/fwd.hpp | 267 | ||||
| -rw-r--r-- | deps/include/entt/entity/group.hpp | 1057 | ||||
| -rw-r--r-- | deps/include/entt/entity/handle.hpp | 431 | ||||
| -rw-r--r-- | deps/include/entt/entity/helper.hpp | 255 | ||||
| -rw-r--r-- | deps/include/entt/entity/mixin.hpp | 318 | ||||
| -rw-r--r-- | deps/include/entt/entity/observer.hpp | 438 | ||||
| -rw-r--r-- | deps/include/entt/entity/organizer.hpp | 424 | ||||
| -rw-r--r-- | deps/include/entt/entity/ranges.hpp | 26 | ||||
| -rw-r--r-- | deps/include/entt/entity/registry.hpp | 1222 | ||||
| -rw-r--r-- | deps/include/entt/entity/runtime_view.hpp | 318 | ||||
| -rw-r--r-- | deps/include/entt/entity/snapshot.hpp | 509 | ||||
| -rw-r--r-- | deps/include/entt/entity/sparse_set.hpp | 1068 | ||||
| -rw-r--r-- | deps/include/entt/entity/storage.hpp | 1205 | ||||
| -rw-r--r-- | deps/include/entt/entity/storage_mixin.hpp | 236 | ||||
| -rw-r--r-- | deps/include/entt/entity/view.hpp | 1076 |
17 files changed, 0 insertions, 9294 deletions
diff --git a/deps/include/entt/entity/component.hpp b/deps/include/entt/entity/component.hpp deleted file mode 100644 index 7b17827..0000000 --- a/deps/include/entt/entity/component.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef ENTT_ENTITY_COMPONENT_HPP
-#define ENTT_ENTITY_COMPONENT_HPP
-
-#include <cstddef>
-#include <type_traits>
-#include "../config/config.h"
-#include "fwd.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename Type, typename = void>
-struct in_place_delete: std::bool_constant<!(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>)> {};
-
-template<>
-struct in_place_delete<void>: std::false_type {};
-
-template<typename Type>
-struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
- : std::true_type {};
-
-template<typename Type, typename = void>
-struct page_size: std::integral_constant<std::size_t, !std::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {};
-
-template<>
-struct page_size<void>: std::integral_constant<std::size_t, 0u> {};
-
-template<typename Type>
-struct page_size<Type, std::void_t<decltype(Type::page_size)>>
- : std::integral_constant<std::size_t, Type::page_size> {};
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Common way to access various properties of components.
- * @tparam Type Type of component.
- */
-template<typename Type, typename = void>
-struct component_traits {
- static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
-
- /*! @brief Component type. */
- using type = Type;
-
- /*! @brief Pointer stability, default is `false`. */
- static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;
- /*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */
- static constexpr std::size_t page_size = internal::page_size<Type>::value;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/entity.hpp b/deps/include/entt/entity/entity.hpp deleted file mode 100644 index f9a2454..0000000 --- a/deps/include/entt/entity/entity.hpp +++ /dev/null @@ -1,388 +0,0 @@ -#ifndef ENTT_ENTITY_ENTITY_HPP
-#define ENTT_ENTITY_ENTITY_HPP
-
-#include <cstddef>
-#include <cstdint>
-#include <type_traits>
-#include "../config/config.h"
-#include "../core/bit.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename, typename = void>
-struct entt_traits;
-
-template<typename Type>
-struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
- : entt_traits<std::underlying_type_t<Type>> {
- using value_type = Type;
-};
-
-template<typename Type>
-struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
- : entt_traits<typename Type::entity_type> {
- using value_type = Type;
-};
-
-template<>
-struct entt_traits<std::uint32_t> {
- using value_type = std::uint32_t;
-
- using entity_type = std::uint32_t;
- using version_type = std::uint16_t;
-
- static constexpr entity_type entity_mask = 0xFFFFF;
- static constexpr entity_type version_mask = 0xFFF;
-};
-
-template<>
-struct entt_traits<std::uint64_t> {
- using value_type = std::uint64_t;
-
- using entity_type = std::uint64_t;
- using version_type = std::uint32_t;
-
- static constexpr entity_type entity_mask = 0xFFFFFFFF;
- static constexpr entity_type version_mask = 0xFFFFFFFF;
-};
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Common basic entity traits implementation.
- * @tparam Traits Actual entity traits to use.
- */
-template<typename Traits>
-class basic_entt_traits {
- static constexpr auto length = popcount(Traits::entity_mask);
-
- static_assert(Traits::entity_mask && ((Traits::entity_mask & (Traits::entity_mask + 1)) == 0), "Invalid entity mask");
- static_assert((Traits::version_mask & (Traits::version_mask + 1)) == 0, "Invalid version mask");
-
-public:
- /*! @brief Value type. */
- using value_type = typename Traits::value_type;
- /*! @brief Underlying entity type. */
- using entity_type = typename Traits::entity_type;
- /*! @brief Underlying version type. */
- using version_type = typename Traits::version_type;
-
- /*! @brief Entity mask size. */
- static constexpr entity_type entity_mask = Traits::entity_mask;
- /*! @brief Version mask size */
- static constexpr entity_type version_mask = Traits::version_mask;
-
- /**
- * @brief Converts an entity to its underlying type.
- * @param value The value to convert.
- * @return The integral representation of the given value.
- */
- [[nodiscard]] static constexpr entity_type to_integral(const value_type value) noexcept {
- return static_cast<entity_type>(value);
- }
-
- /**
- * @brief Returns the entity part once converted to the underlying type.
- * @param value The value to convert.
- * @return The integral representation of the entity part.
- */
- [[nodiscard]] static constexpr entity_type to_entity(const value_type value) noexcept {
- return (to_integral(value) & entity_mask);
- }
-
- /**
- * @brief Returns the version part once converted to the underlying type.
- * @param value The value to convert.
- * @return The integral representation of the version part.
- */
- [[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept {
- if constexpr(Traits::version_mask == 0u) {
- return version_type{};
- } else {
- return (static_cast<version_type>(to_integral(value) >> length) & version_mask);
- }
- }
-
- /**
- * @brief Returns the successor of a given identifier.
- * @param value The identifier of which to return the successor.
- * @return The successor of the given identifier.
- */
- [[nodiscard]] static constexpr value_type next(const value_type value) noexcept {
- const auto vers = to_version(value) + 1;
- return construct(to_integral(value), static_cast<version_type>(vers + (vers == version_mask)));
- }
-
- /**
- * @brief Constructs an identifier from its parts.
- *
- * If the version part is not provided, a tombstone is returned.<br/>
- * If the entity part is not provided, a null identifier is returned.
- *
- * @param entity The entity part of the identifier.
- * @param version The version part of the identifier.
- * @return A properly constructed identifier.
- */
- [[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept {
- if constexpr(Traits::version_mask == 0u) {
- return value_type{entity & entity_mask};
- } else {
- return value_type{(entity & entity_mask) | (static_cast<entity_type>(version & version_mask) << length)};
- }
- }
-
- /**
- * @brief Combines two identifiers in a single one.
- *
- * The returned identifier is a copy of the first element except for its
- * version, which is taken from the second element.
- *
- * @param lhs The identifier from which to take the entity part.
- * @param rhs The identifier from which to take the version part.
- * @return A properly constructed identifier.
- */
- [[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept {
- if constexpr(Traits::version_mask == 0u) {
- return value_type{lhs & entity_mask};
- } else {
- return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))};
- }
- }
-};
-
-/**
- * @brief Entity traits.
- * @tparam Type Type of identifier.
- */
-template<typename Type>
-struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
- /*! @brief Base type. */
- using base_type = basic_entt_traits<internal::entt_traits<Type>>;
- /*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
- static constexpr std::size_t page_size = ENTT_SPARSE_PAGE;
-};
-
-/**
- * @brief Converts an entity to its underlying type.
- * @tparam Entity The value type.
- * @param value The value to convert.
- * @return The integral representation of the given value.
- */
-template<typename Entity>
-[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
- return entt_traits<Entity>::to_integral(value);
-}
-
-/**
- * @brief Returns the entity part once converted to the underlying type.
- * @tparam Entity The value type.
- * @param value The value to convert.
- * @return The integral representation of the entity part.
- */
-template<typename Entity>
-[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
- return entt_traits<Entity>::to_entity(value);
-}
-
-/**
- * @brief Returns the version part once converted to the underlying type.
- * @tparam Entity The value type.
- * @param value The value to convert.
- * @return The integral representation of the version part.
- */
-template<typename Entity>
-[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
- return entt_traits<Entity>::to_version(value);
-}
-
-/*! @brief Null object for all identifiers. */
-struct null_t {
- /**
- * @brief Converts the null object to identifiers of any type.
- * @tparam Entity Type of identifier.
- * @return The null representation for the given type.
- */
- template<typename Entity>
- [[nodiscard]] constexpr operator Entity() const noexcept {
- using traits_type = entt_traits<Entity>;
- constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
- return value;
- }
-
- /**
- * @brief Compares two null objects.
- * @param other A null object.
- * @return True in all cases.
- */
- [[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const noexcept {
- return true;
- }
-
- /**
- * @brief Compares two null objects.
- * @param other A null object.
- * @return False in all cases.
- */
- [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const noexcept {
- return false;
- }
-
- /**
- * @brief Compares a null object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param entity Identifier with which to compare.
- * @return False if the two elements differ, true otherwise.
- */
- template<typename Entity>
- [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
- using traits_type = entt_traits<Entity>;
- return traits_type::to_entity(entity) == traits_type::to_entity(*this);
- }
-
- /**
- * @brief Compares a null object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param entity Identifier with which to compare.
- * @return True if the two elements differ, false otherwise.
- */
- template<typename Entity>
- [[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
- return !(entity == *this);
- }
-};
-
-/**
- * @brief Compares a null object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param lhs Identifier with which to compare.
- * @param rhs A null object yet to be converted.
- * @return False if the two elements differ, true otherwise.
- */
-template<typename Entity>
-[[nodiscard]] constexpr bool operator==(const Entity lhs, const null_t rhs) noexcept {
- return rhs.operator==(lhs);
-}
-
-/**
- * @brief Compares a null object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param lhs Identifier with which to compare.
- * @param rhs A null object yet to be converted.
- * @return True if the two elements differ, false otherwise.
- */
-template<typename Entity>
-[[nodiscard]] constexpr bool operator!=(const Entity lhs, const null_t rhs) noexcept {
- return !(rhs == lhs);
-}
-
-/*! @brief Tombstone object for all identifiers. */
-struct tombstone_t {
- /**
- * @brief Converts the tombstone object to identifiers of any type.
- * @tparam Entity Type of identifier.
- * @return The tombstone representation for the given type.
- */
- template<typename Entity>
- [[nodiscard]] constexpr operator Entity() const noexcept {
- using traits_type = entt_traits<Entity>;
- constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
- return value;
- }
-
- /**
- * @brief Compares two tombstone objects.
- * @param other A tombstone object.
- * @return True in all cases.
- */
- [[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const noexcept {
- return true;
- }
-
- /**
- * @brief Compares two tombstone objects.
- * @param other A tombstone object.
- * @return False in all cases.
- */
- [[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const noexcept {
- return false;
- }
-
- /**
- * @brief Compares a tombstone object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param entity Identifier with which to compare.
- * @return False if the two elements differ, true otherwise.
- */
- template<typename Entity>
- [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
- using traits_type = entt_traits<Entity>;
-
- if constexpr(traits_type::version_mask == 0u) {
- return false;
- } else {
- return (traits_type::to_version(entity) == traits_type::to_version(*this));
- }
- }
-
- /**
- * @brief Compares a tombstone object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param entity Identifier with which to compare.
- * @return True if the two elements differ, false otherwise.
- */
- template<typename Entity>
- [[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
- return !(entity == *this);
- }
-};
-
-/**
- * @brief Compares a tombstone object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param lhs Identifier with which to compare.
- * @param rhs A tombstone object yet to be converted.
- * @return False if the two elements differ, true otherwise.
- */
-template<typename Entity>
-[[nodiscard]] constexpr bool operator==(const Entity lhs, const tombstone_t rhs) noexcept {
- return rhs.operator==(lhs);
-}
-
-/**
- * @brief Compares a tombstone object and an identifier of any type.
- * @tparam Entity Type of identifier.
- * @param lhs Identifier with which to compare.
- * @param rhs A tombstone object yet to be converted.
- * @return True if the two elements differ, false otherwise.
- */
-template<typename Entity>
-[[nodiscard]] constexpr bool operator!=(const Entity lhs, const tombstone_t rhs) noexcept {
- return !(rhs == lhs);
-}
-
-/**
- * @brief Compile-time constant for null entities.
- *
- * There exist implicit conversions from this variable to identifiers of any
- * allowed type. Similarly, there exist comparison operators between the null
- * entity and any other identifier.
- */
-inline constexpr null_t null{};
-
-/**
- * @brief Compile-time constant for tombstone entities.
- *
- * There exist implicit conversions from this variable to identifiers of any
- * allowed type. Similarly, there exist comparison operators between the
- * tombstone entity and any other identifier.
- */
-inline constexpr tombstone_t tombstone{};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/fwd.hpp b/deps/include/entt/entity/fwd.hpp deleted file mode 100644 index 4ccdab9..0000000 --- a/deps/include/entt/entity/fwd.hpp +++ /dev/null @@ -1,267 +0,0 @@ -#ifndef ENTT_ENTITY_FWD_HPP
-#define ENTT_ENTITY_FWD_HPP
-
-#include <cstdint>
-#include <memory>
-#include <type_traits>
-#include "../config/config.h"
-#include "../core/fwd.hpp"
-#include "../core/type_traits.hpp"
-
-namespace entt {
-
-/*! @brief Default entity identifier. */
-enum class entity : id_type {};
-
-/*! @brief Storage deletion policy. */
-enum class deletion_policy : std::uint8_t {
- /*! @brief Swap-and-pop deletion policy. */
- swap_and_pop = 0u,
- /*! @brief In-place deletion policy. */
- in_place = 1u,
- /*! @brief Swap-only deletion policy. */
- swap_only = 2u
-};
-
-template<typename Entity = entity, typename = std::allocator<Entity>>
-class basic_sparse_set;
-
-template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
-class basic_storage;
-
-template<typename, typename>
-class basic_sigh_mixin;
-
-template<typename Entity = entity, typename = std::allocator<Entity>>
-class basic_registry;
-
-template<typename, typename, typename = void>
-class basic_view;
-
-template<typename Type, typename = std::allocator<Type *>>
-class basic_runtime_view;
-
-template<typename, typename, typename>
-class basic_group;
-
-template<typename, typename = std::allocator<void>>
-class basic_observer;
-
-template<typename>
-class basic_organizer;
-
-template<typename, typename...>
-class basic_handle;
-
-template<typename>
-class basic_snapshot;
-
-template<typename>
-class basic_snapshot_loader;
-
-template<typename>
-class basic_continuous_loader;
-
-/*! @brief Alias declaration for the most common use case. */
-using sparse_set = basic_sparse_set<>;
-
-/**
- * @brief Alias declaration for the most common use case.
- * @tparam Type Element type.
- */
-template<typename Type>
-using storage = basic_storage<Type>;
-
-/**
- * @brief Alias declaration for the most common use case.
- * @tparam Type Underlying storage type.
- */
-template<typename Type>
-using sigh_mixin = basic_sigh_mixin<Type, basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>>;
-
-/*! @brief Alias declaration for the most common use case. */
-using registry = basic_registry<>;
-
-/*! @brief Alias declaration for the most common use case. */
-using observer = basic_observer<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using organizer = basic_organizer<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using handle = basic_handle<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using const_handle = basic_handle<const registry>;
-
-/**
- * @brief Alias declaration for the most common use case.
- * @tparam Args Other template parameters.
- */
-template<typename... Args>
-using handle_view = basic_handle<registry, Args...>;
-
-/**
- * @brief Alias declaration for the most common use case.
- * @tparam Args Other template parameters.
- */
-template<typename... Args>
-using const_handle_view = basic_handle<const registry, Args...>;
-
-/*! @brief Alias declaration for the most common use case. */
-using snapshot = basic_snapshot<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using snapshot_loader = basic_snapshot_loader<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using continuous_loader = basic_continuous_loader<registry>;
-
-/*! @brief Alias declaration for the most common use case. */
-using runtime_view = basic_runtime_view<sparse_set>;
-
-/*! @brief Alias declaration for the most common use case. */
-using const_runtime_view = basic_runtime_view<const sparse_set>;
-
-/**
- * @brief Alias for exclusion lists.
- * @tparam Type List of types.
- */
-template<typename... Type>
-struct exclude_t final: type_list<Type...> {
- /*! @brief Default constructor. */
- explicit constexpr exclude_t() = default;
-};
-
-/**
- * @brief Variable template for exclusion lists.
- * @tparam Type List of types.
- */
-template<typename... Type>
-inline constexpr exclude_t<Type...> exclude{};
-
-/**
- * @brief Alias for lists of observed elements.
- * @tparam Type List of types.
- */
-template<typename... Type>
-struct get_t final: type_list<Type...> {
- /*! @brief Default constructor. */
- explicit constexpr get_t() = default;
-};
-
-/**
- * @brief Variable template for lists of observed elements.
- * @tparam Type List of types.
- */
-template<typename... Type>
-inline constexpr get_t<Type...> get{};
-
-/**
- * @brief Alias for lists of owned elements.
- * @tparam Type List of types.
- */
-template<typename... Type>
-struct owned_t final: type_list<Type...> {
- /*! @brief Default constructor. */
- explicit constexpr owned_t() = default;
-};
-
-/**
- * @brief Variable template for lists of owned elements.
- * @tparam Type List of types.
- */
-template<typename... Type>
-inline constexpr owned_t<Type...> owned{};
-
-/**
- * @brief Applies a given _function_ to a get list and generate a new list.
- * @tparam Type Types provided by the get list.
- * @tparam Op Unary operation as template class with a type member named `type`.
- */
-template<typename... Type, template<typename...> class Op>
-struct type_list_transform<get_t<Type...>, Op> {
- /*! @brief Resulting get list after applying the transform function. */
- using type = get_t<typename Op<Type>::type...>;
-};
-
-/**
- * @brief Applies a given _function_ to an exclude list and generate a new list.
- * @tparam Type Types provided by the exclude list.
- * @tparam Op Unary operation as template class with a type member named `type`.
- */
-template<typename... Type, template<typename...> class Op>
-struct type_list_transform<exclude_t<Type...>, Op> {
- /*! @brief Resulting exclude list after applying the transform function. */
- using type = exclude_t<typename Op<Type>::type...>;
-};
-
-/**
- * @brief Applies a given _function_ to an owned list and generate a new list.
- * @tparam Type Types provided by the owned list.
- * @tparam Op Unary operation as template class with a type member named `type`.
- */
-template<typename... Type, template<typename...> class Op>
-struct type_list_transform<owned_t<Type...>, Op> {
- /*! @brief Resulting owned list after applying the transform function. */
- using type = owned_t<typename Op<Type>::type...>;
-};
-
-/**
- * @brief Provides a common way to define storage types.
- * @tparam Type Storage value type.
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
-struct storage_type {
- /*! @brief Type-to-storage conversion result. */
- using type = ENTT_STORAGE(sigh_mixin, basic_storage<Type, Entity, Allocator>);
-};
-
-/**
- * @brief Helper type.
- * @tparam Args Arguments to forward.
- */
-template<typename... Args>
-using storage_type_t = typename storage_type<Args...>::type;
-
-/**
- * Type-to-storage conversion utility that preserves constness.
- * @tparam Type Storage value type, eventually const.
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
-struct storage_for {
- /*! @brief Type-to-storage conversion result. */
- using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
-};
-
-/**
- * @brief Helper type.
- * @tparam Args Arguments to forward.
- */
-template<typename... Args>
-using storage_for_t = typename storage_for<Args...>::type;
-
-/**
- * @brief Alias declaration for the most common use case.
- * @tparam Get Types of storage iterated by the view.
- * @tparam Exclude Types of storage used to filter the view.
- */
-template<typename Get, typename Exclude = exclude_t<>>
-using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
-
-/**
- * @brief Alias declaration for the most common use case.
- * @tparam Owned Types of storage _owned_ by the group.
- * @tparam Get Types of storage _observed_ by the group.
- * @tparam Exclude Types of storage used to filter the group.
- */
-template<typename Owned, typename Get, typename Exclude>
-using group = basic_group<type_list_transform_t<Owned, storage_for>, type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/group.hpp b/deps/include/entt/entity/group.hpp deleted file mode 100644 index 9e6a210..0000000 --- a/deps/include/entt/entity/group.hpp +++ /dev/null @@ -1,1057 +0,0 @@ -#ifndef ENTT_ENTITY_GROUP_HPP
-#define ENTT_ENTITY_GROUP_HPP
-
-#include <array>
-#include <cstddef>
-#include <iterator>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include "../config/config.h"
-#include "../core/algorithm.hpp"
-#include "../core/fwd.hpp"
-#include "../core/iterator.hpp"
-#include "../core/type_info.hpp"
-#include "../core/type_traits.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename, typename, typename>
-class extended_group_iterator;
-
-template<typename It, typename... Owned, typename... Get>
-class extended_group_iterator<It, owned_t<Owned...>, get_t<Get...>> {
- template<typename Type>
- [[nodiscard]] auto index_to_element([[maybe_unused]] Type &cpool) const {
- if constexpr(std::is_void_v<typename Type::value_type>) {
- return std::make_tuple();
- } else {
- return std::forward_as_tuple(cpool.rbegin()[it.index()]);
- }
- }
-
-public:
- using iterator_type = It;
- using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Owned>().get_as_tuple({})..., std::declval<Get>().get_as_tuple({})...));
- using pointer = input_iterator_pointer<value_type>;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category = std::input_iterator_tag;
- using iterator_concept = std::forward_iterator_tag;
-
- constexpr extended_group_iterator()
- : it{},
- pools{} {}
-
- extended_group_iterator(iterator_type from, std::tuple<Owned *..., Get *...> cpools)
- : it{from},
- pools{std::move(cpools)} {}
-
- extended_group_iterator &operator++() noexcept {
- return ++it, *this;
- }
-
- extended_group_iterator operator++(int) noexcept {
- extended_group_iterator orig = *this;
- return ++(*this), orig;
- }
-
- [[nodiscard]] reference operator*() const noexcept {
- return std::tuple_cat(std::make_tuple(*it), index_to_element(*std::get<Owned *>(pools))..., std::get<Get *>(pools)->get_as_tuple(*it)...);
- }
-
- [[nodiscard]] pointer operator->() const noexcept {
- return operator*();
- }
-
- [[nodiscard]] constexpr iterator_type base() const noexcept {
- return it;
- }
-
- template<typename... Lhs, typename... Rhs>
- friend constexpr bool operator==(const extended_group_iterator<Lhs...> &, const extended_group_iterator<Rhs...> &) noexcept;
-
-private:
- It it;
- std::tuple<Owned *..., Get *...> pools;
-};
-
-template<typename... Lhs, typename... Rhs>
-[[nodiscard]] constexpr bool operator==(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
- return lhs.it == rhs.it;
-}
-
-template<typename... Lhs, typename... Rhs>
-[[nodiscard]] constexpr bool operator!=(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-struct group_descriptor {
- using size_type = std::size_t;
- virtual ~group_descriptor() noexcept = default;
- [[nodiscard]] virtual bool owned(const id_type) const noexcept {
- return false;
- }
-};
-
-template<typename Type, std::size_t Owned, std::size_t Get, std::size_t Exclude>
-class group_handler final: public group_descriptor {
- using entity_type = typename Type::entity_type;
-
- void swap_elements(const std::size_t pos, const entity_type entt) {
- for(size_type next{}; next < Owned; ++next) {
- pools[next]->swap_elements((*pools[next])[pos], entt);
- }
- }
-
- void push_on_construct(const entity_type entt) {
- if(std::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
- && std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
- swap_elements(len++, entt);
- }
- }
-
- void push_on_destroy(const entity_type entt) {
- if(std::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
- && std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
- swap_elements(len++, entt);
- }
- }
-
- void remove_if(const entity_type entt) {
- if(pools[0u]->contains(entt) && (pools[0u]->index(entt) < len)) {
- swap_elements(--len, entt);
- }
- }
-
- void common_setup() {
- // we cannot iterate backwards because we want to leave behind valid entities in case of owned types
- for(auto first = pools[0u]->rbegin(), last = first + pools[0u]->size(); first != last; ++first) {
- push_on_construct(*first);
- }
- }
-
-public:
- using common_type = Type;
- using size_type = typename Type::size_type;
-
- template<typename... OGType, typename... EType>
- group_handler(std::tuple<OGType &...> ogpool, std::tuple<EType &...> epool)
- : pools{std::apply([](auto &&...cpool) { return std::array<common_type *, (Owned + Get)>{&cpool...}; }, ogpool)},
- filter{std::apply([](auto &&...cpool) { return std::array<common_type *, Exclude>{&cpool...}; }, epool)} {
- std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool);
- std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
- common_setup();
- }
-
- [[nodiscard]] bool owned(const id_type hash) const noexcept override {
- for(size_type pos{}; pos < Owned; ++pos) {
- if(pools[pos]->type().hash() == hash) {
- return true;
- }
- }
-
- return false;
- }
-
- [[nodiscard]] size_type length() const noexcept {
- return len;
- }
-
- template<std::size_t Index>
- [[nodiscard]] common_type *storage() const noexcept {
- if constexpr(Index < (Owned + Get)) {
- return pools[Index];
- } else {
- return filter[Index - (Owned + Get)];
- }
- }
-
-private:
- std::array<common_type *, (Owned + Get)> pools;
- std::array<common_type *, Exclude> filter;
- std::size_t len{};
-};
-
-template<typename Type, std::size_t Get, std::size_t Exclude>
-class group_handler<Type, 0u, Get, Exclude> final: public group_descriptor {
- using entity_type = typename Type::entity_type;
-
- void push_on_construct(const entity_type entt) {
- if(!elem.contains(entt)
- && std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
- && std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
- elem.push(entt);
- }
- }
-
- void push_on_destroy(const entity_type entt) {
- if(!elem.contains(entt)
- && std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
- && std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
- elem.push(entt);
- }
- }
-
- void remove_if(const entity_type entt) {
- elem.remove(entt);
- }
-
- void common_setup() {
- for(const auto entity: *pools[0u]) {
- push_on_construct(entity);
- }
- }
-
-public:
- using common_type = Type;
-
- template<typename Allocator, typename... GType, typename... EType>
- group_handler(const Allocator &allocator, std::tuple<GType &...> gpool, std::tuple<EType &...> epool)
- : pools{std::apply([](auto &&...cpool) { return std::array<common_type *, Get>{&cpool...}; }, gpool)},
- filter{std::apply([](auto &&...cpool) { return std::array<common_type *, Exclude>{&cpool...}; }, epool)},
- elem{allocator} {
- std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool);
- std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
- common_setup();
- }
-
- [[nodiscard]] common_type &handle() noexcept {
- return elem;
- }
-
- [[nodiscard]] const common_type &handle() const noexcept {
- return elem;
- }
-
- template<std::size_t Index>
- [[nodiscard]] common_type *storage() const noexcept {
- if constexpr(Index < Get) {
- return pools[Index];
- } else {
- return filter[Index - Get];
- }
- }
-
-private:
- std::array<common_type *, Get> pools;
- std::array<common_type *, Exclude> filter;
- common_type elem;
-};
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Group.
- *
- * Primary template isn't defined on purpose. All the specializations give a
- * compile-time error, but for a few reasonable cases.
- */
-template<typename, typename, typename>
-class basic_group;
-
-/**
- * @brief Non-owning group.
- *
- * A non-owning group returns all entities and only the entities that are at
- * least in the given storage. Moreover, it's guaranteed that the entity list is
- * tightly packed in memory for fast iterations.
- *
- * @b Important
- *
- * Iterators aren't invalidated if:
- *
- * * New elements are added to the storage.
- * * The entity currently pointed is modified (for example, elements are added
- * or removed from it).
- * * The entity currently pointed is destroyed.
- *
- * In all other cases, modifying the pools iterated by the group in any way
- * invalidates all the iterators.
- *
- * @tparam Get Types of storage _observed_ by the group.
- * @tparam Exclude Types of storage used to filter the group.
- */
-template<typename... Get, typename... Exclude>
-class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
- using base_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
- using underlying_type = typename base_type::entity_type;
-
- template<typename Type>
- static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
-
- template<std::size_t... Index>
- [[nodiscard]] auto pools_for(std::index_sequence<Index...>) const noexcept {
- using return_type = std::tuple<Get *...>;
- return descriptor ? return_type{static_cast<Get *>(descriptor->template storage<Index>())...} : return_type{};
- }
-
-public:
- /*! @brief Underlying entity identifier. */
- using entity_type = underlying_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Common type among all storage types. */
- using common_type = base_type;
- /*! @brief Random access iterator type. */
- using iterator = typename common_type::iterator;
- /*! @brief Reverse iterator type. */
- using reverse_iterator = typename common_type::reverse_iterator;
- /*! @brief Iterable group type. */
- using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<>, get_t<Get...>>>;
- /*! @brief Group handler type. */
- using handler = internal::group_handler<common_type, 0u, sizeof...(Get), sizeof...(Exclude)>;
-
- /**
- * @brief Group opaque identifier.
- * @return Group opaque identifier.
- */
- static id_type group_id() noexcept {
- return type_hash<basic_group<owned_t<>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>>::value();
- }
-
- /*! @brief Default constructor to use to create empty, invalid groups. */
- basic_group() noexcept
- : descriptor{} {}
-
- /**
- * @brief Constructs a group from a set of storage classes.
- * @param ref A reference to a group handler.
- */
- basic_group(handler &ref) noexcept
- : descriptor{&ref} {}
-
- /**
- * @brief Returns the leading storage of a group.
- * @return The leading storage of the group.
- */
- [[nodiscard]] const common_type &handle() const noexcept {
- return descriptor->handle();
- }
-
- /**
- * @brief Returns the storage for a given element type, if any.
- * @tparam Type Type of element of which to return the storage.
- * @return The storage for the given element type.
- */
- template<typename Type>
- [[nodiscard]] auto *storage() const noexcept {
- return storage<index_of<Type>>();
- }
-
- /**
- * @brief Returns the storage for a given index, if any.
- * @tparam Index Index of the storage to return.
- * @return The storage for the given index.
- */
- template<std::size_t Index>
- [[nodiscard]] auto *storage() const noexcept {
- using type = type_list_element_t<Index, type_list<Get..., Exclude...>>;
- return *this ? static_cast<type *>(descriptor->template storage<Index>()) : nullptr;
- }
-
- /**
- * @brief Returns the number of entities that are part of the group.
- * @return Number of entities that are part of the group.
- */
- [[nodiscard]] size_type size() const noexcept {
- return *this ? handle().size() : size_type{};
- }
-
- /**
- * @brief Returns the number of elements that a group has currently
- * allocated space for.
- * @return Capacity of the group.
- */
- [[nodiscard]] size_type capacity() const noexcept {
- return *this ? handle().capacity() : size_type{};
- }
-
- /*! @brief Requests the removal of unused capacity. */
- void shrink_to_fit() {
- if(*this) {
- descriptor->handle().shrink_to_fit();
- }
- }
-
- /**
- * @brief Checks whether a group is empty.
- * @return True if the group is empty, false otherwise.
- */
- [[nodiscard]] bool empty() const noexcept {
- return !*this || handle().empty();
- }
-
- /**
- * @brief Returns an iterator to the first entity of the group.
- *
- * If the group is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first entity of the group.
- */
- [[nodiscard]] iterator begin() const noexcept {
- return *this ? handle().begin() : iterator{};
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the group.
- * @return An iterator to the entity following the last entity of the
- * group.
- */
- [[nodiscard]] iterator end() const noexcept {
- return *this ? handle().end() : iterator{};
- }
-
- /**
- * @brief Returns an iterator to the first entity of the reversed group.
- *
- * If the group is empty, the returned iterator will be equal to `rend()`.
- *
- * @return An iterator to the first entity of the reversed group.
- */
- [[nodiscard]] reverse_iterator rbegin() const noexcept {
- return *this ? handle().rbegin() : reverse_iterator{};
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the reversed
- * group.
- * @return An iterator to the entity following the last entity of the
- * reversed group.
- */
- [[nodiscard]] reverse_iterator rend() const noexcept {
- return *this ? handle().rend() : reverse_iterator{};
- }
-
- /**
- * @brief Returns the first entity of the group, if any.
- * @return The first entity of the group if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type front() const noexcept {
- const auto it = begin();
- return it != end() ? *it : null;
- }
-
- /**
- * @brief Returns the last entity of the group, if any.
- * @return The last entity of the group if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type back() const noexcept {
- const auto it = rbegin();
- return it != rend() ? *it : null;
- }
-
- /**
- * @brief Finds an entity.
- * @param entt A valid identifier.
- * @return An iterator to the given entity if it's found, past the end
- * iterator otherwise.
- */
- [[nodiscard]] iterator find(const entity_type entt) const noexcept {
- return *this ? handle().find(entt) : iterator{};
- }
-
- /**
- * @brief Returns the identifier that occupies the given position.
- * @param pos Position of the element to return.
- * @return The identifier that occupies the given position.
- */
- [[nodiscard]] entity_type operator[](const size_type pos) const {
- return begin()[pos];
- }
-
- /**
- * @brief Checks if a group is properly initialized.
- * @return True if the group is properly initialized, false otherwise.
- */
- [[nodiscard]] explicit operator bool() const noexcept {
- return descriptor != nullptr;
- }
-
- /**
- * @brief Checks if a group contains an entity.
- * @param entt A valid identifier.
- * @return True if the group contains the given entity, false otherwise.
- */
- [[nodiscard]] bool contains(const entity_type entt) const noexcept {
- return *this && handle().contains(entt);
- }
-
- /**
- * @brief Returns the elements assigned to the given entity.
- * @tparam Type Type of the element to get.
- * @tparam Other Other types of elements to get.
- * @param entt A valid identifier.
- * @return The elements assigned to the entity.
- */
- template<typename Type, typename... Other>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- return get<index_of<Type>, index_of<Other>...>(entt);
- }
-
- /**
- * @brief Returns the elements assigned to the given entity.
- * @tparam Index Indexes of the elements to get.
- * @param entt A valid identifier.
- * @return The elements assigned to the entity.
- */
- template<std::size_t... Index>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- const auto cpools = pools_for(std::index_sequence_for<Get...>{});
-
- if constexpr(sizeof...(Index) == 0) {
- return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
- } else if constexpr(sizeof...(Index) == 1) {
- return (std::get<Index>(cpools)->get(entt), ...);
- } else {
- return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
- }
- }
-
- /**
- * @brief Iterates entities and elements and applies the given function
- * object to them.
- *
- * The function object is invoked for each entity. It is provided with the
- * entity itself and a set of references to non-empty elements. The
- * _constness_ of the elements is as requested.<br/>
- * The signature of the function must be equivalent to one of the following
- * forms:
- *
- * @code{.cpp}
- * void(const entity_type, Type &...);
- * void(Type &...);
- * @endcode
- *
- * @note
- * Empty types aren't explicitly instantiated and therefore they are never
- * returned during iterations.
- *
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template<typename Func>
- void each(Func func) const {
- for(const auto entt: *this) {
- if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
- std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
- } else {
- std::apply(func, get(entt));
- }
- }
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a group.
- *
- * The iterable object returns tuples that contain the current entity and a
- * set of references to its non-empty elements. The _constness_ of the
- * elements is as requested.
- *
- * @note
- * Empty types aren't explicitly instantiated and therefore they are never
- * returned during iterations.
- *
- * @return An iterable object to use to _visit_ the group.
- */
- [[nodiscard]] iterable each() const noexcept {
- const auto cpools = pools_for(std::index_sequence_for<Get...>{});
- return iterable{{begin(), cpools}, {end(), cpools}};
- }
-
- /**
- * @brief Sort a group according to the given comparison function.
- *
- * The comparison function object must return `true` if the first element
- * is _less_ than the second one, `false` otherwise. The signature of the
- * comparison function should be equivalent to one of the following:
- *
- * @code{.cpp}
- * bool(std::tuple<Type &...>, std::tuple<Type &...>);
- * bool(const Type &..., const Type &...);
- * bool(const Entity, const Entity);
- * @endcode
- *
- * Where `Type` are such that they are iterated by the group.<br/>
- * Moreover, the comparison function object shall induce a
- * _strict weak ordering_ on the values.
- *
- * The sort function object must offer a member function template
- * `operator()` that accepts three arguments:
- *
- * * An iterator to the first element of the range to sort.
- * * An iterator past the last element of the range to sort.
- * * A comparison function to use to compare the elements.
- *
- * @tparam Type Optional type of element to compare.
- * @tparam Other Other optional types of elements to compare.
- * @tparam Compare Type of comparison function object.
- * @tparam Sort Type of sort function object.
- * @tparam Args Types of arguments to forward to the sort function object.
- * @param compare A valid comparison function object.
- * @param algo A valid sort function object.
- * @param args Arguments to forward to the sort function object, if any.
- */
- template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
- void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
- sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
- }
-
- /**
- * @brief Sort a group according to the given comparison function.
- *
- * @sa sort
- *
- * @tparam Index Optional indexes of elements to compare.
- * @tparam Compare Type of comparison function object.
- * @tparam Sort Type of sort function object.
- * @tparam Args Types of arguments to forward to the sort function object.
- * @param compare A valid comparison function object.
- * @param algo A valid sort function object.
- * @param args Arguments to forward to the sort function object, if any.
- */
- template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
- void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
- if(*this) {
- if constexpr(sizeof...(Index) == 0) {
- static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
- descriptor->handle().sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
- } else {
- auto comp = [&compare, cpools = pools_for(std::index_sequence_for<Get...>{})](const entity_type lhs, const entity_type rhs) {
- if constexpr(sizeof...(Index) == 1) {
- return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
- } else {
- return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
- }
- };
-
- descriptor->handle().sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
- }
- }
- }
-
- /**
- * @brief Sort entities according to their order in a range.
- *
- * The shared pool of entities and thus its order is affected by the changes
- * to each and every pool that it tracks.
- *
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- */
- template<typename It>
- void sort_as(It first, It last) const {
- if(*this) {
- descriptor->handle().sort_as(first, last);
- }
- }
-
-private:
- handler *descriptor;
-};
-
-/**
- * @brief Owning group.
- *
- * Owning groups returns all entities and only the entities that are at
- * least in the given storage. Moreover:
- *
- * * It's guaranteed that the entity list is tightly packed in memory for fast
- * iterations.
- * * It's guaranteed that all elements in the owned storage are tightly packed
- * in memory for even faster iterations and to allow direct access.
- * * They stay true to the order of the owned storage and all instances have the
- * same order in memory.
- *
- * The more types of storage are owned, the faster it is to iterate a group.
- *
- * @b Important
- *
- * Iterators aren't invalidated if:
- *
- * * New elements are added to the storage.
- * * The entity currently pointed is modified (for example, elements are added
- * or removed from it).
- * * The entity currently pointed is destroyed.
- *
- * In all other cases, modifying the pools iterated by the group in any way
- * invalidates all the iterators.
- *
- * @tparam Owned Types of storage _owned_ by the group.
- * @tparam Get Types of storage _observed_ by the group.
- * @tparam Exclude Types of storage used to filter the group.
- */
-template<typename... Owned, typename... Get, typename... Exclude>
-class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
- static_assert(((Owned::storage_policy != deletion_policy::in_place) && ...), "Groups do not support in-place delete");
-
- using base_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
- using underlying_type = typename base_type::entity_type;
-
- template<typename Type>
- static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Owned::element_type..., typename Get::element_type..., typename Exclude::element_type...>>;
-
- template<std::size_t... Index, std::size_t... Other>
- [[nodiscard]] auto pools_for(std::index_sequence<Index...>, std::index_sequence<Other...>) const noexcept {
- using return_type = std::tuple<Owned *..., Get *...>;
- return descriptor ? return_type{static_cast<Owned *>(descriptor->template storage<Index>())..., static_cast<Get *>(descriptor->template storage<sizeof...(Owned) + Other>())...} : return_type{};
- }
-
-public:
- /*! @brief Underlying entity identifier. */
- using entity_type = underlying_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Common type among all storage types. */
- using common_type = base_type;
- /*! @brief Random access iterator type. */
- using iterator = typename common_type::iterator;
- /*! @brief Reverse iterator type. */
- using reverse_iterator = typename common_type::reverse_iterator;
- /*! @brief Iterable group type. */
- using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<Owned...>, get_t<Get...>>>;
- /*! @brief Group handler type. */
- using handler = internal::group_handler<common_type, sizeof...(Owned), sizeof...(Get), sizeof...(Exclude)>;
-
- /**
- * @brief Group opaque identifier.
- * @return Group opaque identifier.
- */
- static id_type group_id() noexcept {
- return type_hash<basic_group<owned_t<std::remove_const_t<Owned>...>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>>::value();
- }
-
- /*! @brief Default constructor to use to create empty, invalid groups. */
- basic_group() noexcept
- : descriptor{} {}
-
- /**
- * @brief Constructs a group from a set of storage classes.
- * @param ref A reference to a group handler.
- */
- basic_group(handler &ref) noexcept
- : descriptor{&ref} {}
-
- /**
- * @brief Returns the leading storage of a group.
- * @return The leading storage of the group.
- */
- [[nodiscard]] const common_type &handle() const noexcept {
- return *storage<0>();
- }
-
- /**
- * @brief Returns the storage for a given element type, if any.
- * @tparam Type Type of element of which to return the storage.
- * @return The storage for the given element type.
- */
- template<typename Type>
- [[nodiscard]] auto *storage() const noexcept {
- return storage<index_of<Type>>();
- }
-
- /**
- * @brief Returns the storage for a given index, if any.
- * @tparam Index Index of the storage to return.
- * @return The storage for the given index.
- */
- template<std::size_t Index>
- [[nodiscard]] auto *storage() const noexcept {
- using type = type_list_element_t<Index, type_list<Owned..., Get..., Exclude...>>;
- return *this ? static_cast<type *>(descriptor->template storage<Index>()) : nullptr;
- }
-
- /**
- * @brief Returns the number of entities that that are part of the group.
- * @return Number of entities that that are part of the group.
- */
- [[nodiscard]] size_type size() const noexcept {
- return *this ? descriptor->length() : size_type{};
- }
-
- /**
- * @brief Checks whether a group is empty.
- * @return True if the group is empty, false otherwise.
- */
- [[nodiscard]] bool empty() const noexcept {
- return !*this || !descriptor->length();
- }
-
- /**
- * @brief Returns an iterator to the first entity of the group.
- *
- * If the group is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first entity of the group.
- */
- [[nodiscard]] iterator begin() const noexcept {
- return *this ? (handle().end() - descriptor->length()) : iterator{};
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the group.
- * @return An iterator to the entity following the last entity of the
- * group.
- */
- [[nodiscard]] iterator end() const noexcept {
- return *this ? handle().end() : iterator{};
- }
-
- /**
- * @brief Returns an iterator to the first entity of the reversed group.
- *
- * If the group is empty, the returned iterator will be equal to `rend()`.
- *
- * @return An iterator to the first entity of the reversed group.
- */
- [[nodiscard]] reverse_iterator rbegin() const noexcept {
- return *this ? handle().rbegin() : reverse_iterator{};
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the reversed
- * group.
- * @return An iterator to the entity following the last entity of the
- * reversed group.
- */
- [[nodiscard]] reverse_iterator rend() const noexcept {
- return *this ? (handle().rbegin() + descriptor->length()) : reverse_iterator{};
- }
-
- /**
- * @brief Returns the first entity of the group, if any.
- * @return The first entity of the group if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type front() const noexcept {
- const auto it = begin();
- return it != end() ? *it : null;
- }
-
- /**
- * @brief Returns the last entity of the group, if any.
- * @return The last entity of the group if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type back() const noexcept {
- const auto it = rbegin();
- return it != rend() ? *it : null;
- }
-
- /**
- * @brief Finds an entity.
- * @param entt A valid identifier.
- * @return An iterator to the given entity if it's found, past the end
- * iterator otherwise.
- */
- [[nodiscard]] iterator find(const entity_type entt) const noexcept {
- const auto it = *this ? handle().find(entt) : iterator{};
- return it >= begin() ? it : iterator{};
- }
-
- /**
- * @brief Returns the identifier that occupies the given position.
- * @param pos Position of the element to return.
- * @return The identifier that occupies the given position.
- */
- [[nodiscard]] entity_type operator[](const size_type pos) const {
- return begin()[pos];
- }
-
- /**
- * @brief Checks if a group is properly initialized.
- * @return True if the group is properly initialized, false otherwise.
- */
- [[nodiscard]] explicit operator bool() const noexcept {
- return descriptor != nullptr;
- }
-
- /**
- * @brief Checks if a group contains an entity.
- * @param entt A valid identifier.
- * @return True if the group contains the given entity, false otherwise.
- */
- [[nodiscard]] bool contains(const entity_type entt) const noexcept {
- return *this && handle().contains(entt) && (handle().index(entt) < (descriptor->length()));
- }
-
- /**
- * @brief Returns the elements assigned to the given entity.
- * @tparam Type Type of the element to get.
- * @tparam Other Other types of elements to get.
- * @param entt A valid identifier.
- * @return The elements assigned to the entity.
- */
- template<typename Type, typename... Other>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- return get<index_of<Type>, index_of<Other>...>(entt);
- }
-
- /**
- * @brief Returns the elements assigned to the given entity.
- * @tparam Index Indexes of the elements to get.
- * @param entt A valid identifier.
- * @return The elements assigned to the entity.
- */
- template<std::size_t... Index>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
-
- if constexpr(sizeof...(Index) == 0) {
- return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
- } else if constexpr(sizeof...(Index) == 1) {
- return (std::get<Index>(cpools)->get(entt), ...);
- } else {
- return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
- }
- }
-
- /**
- * @brief Iterates entities and elements and applies the given function
- * object to them.
- *
- * The function object is invoked for each entity. It is provided with the
- * entity itself and a set of references to non-empty elements. The
- * _constness_ of the elements is as requested.<br/>
- * The signature of the function must be equivalent to one of the following
- * forms:
- *
- * @code{.cpp}
- * void(const entity_type, Type &...);
- * void(Type &...);
- * @endcode
- *
- * @note
- * Empty types aren't explicitly instantiated and therefore they are never
- * returned during iterations.
- *
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template<typename Func>
- void each(Func func) const {
- for(auto args: each()) {
- if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
- std::apply(func, args);
- } else {
- std::apply([&func](auto, auto &&...less) { func(std::forward<decltype(less)>(less)...); }, args);
- }
- }
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a group.
- *
- * The iterable object returns tuples that contain the current entity and a
- * set of references to its non-empty elements. The _constness_ of the
- * elements is as requested.
- *
- * @note
- * Empty types aren't explicitly instantiated and therefore they are never
- * returned during iterations.
- *
- * @return An iterable object to use to _visit_ the group.
- */
- [[nodiscard]] iterable each() const noexcept {
- const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
- return iterable{{begin(), cpools}, {end(), cpools}};
- }
-
- /**
- * @brief Sort a group according to the given comparison function.
- *
- * The comparison function object must return `true` if the first element
- * is _less_ than the second one, `false` otherwise. The signature of the
- * comparison function should be equivalent to one of the following:
- *
- * @code{.cpp}
- * bool(std::tuple<Type &...>, std::tuple<Type &...>);
- * bool(const Type &, const Type &);
- * bool(const Entity, const Entity);
- * @endcode
- *
- * Where `Type` are either owned types or not but still such that they are
- * iterated by the group.<br/>
- * Moreover, the comparison function object shall induce a
- * _strict weak ordering_ on the values.
- *
- * The sort function object must offer a member function template
- * `operator()` that accepts three arguments:
- *
- * * An iterator to the first element of the range to sort.
- * * An iterator past the last element of the range to sort.
- * * A comparison function to use to compare the elements.
- *
- * @tparam Type Optional type of element to compare.
- * @tparam Other Other optional types of elements to compare.
- * @tparam Compare Type of comparison function object.
- * @tparam Sort Type of sort function object.
- * @tparam Args Types of arguments to forward to the sort function object.
- * @param compare A valid comparison function object.
- * @param algo A valid sort function object.
- * @param args Arguments to forward to the sort function object, if any.
- */
- template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
- void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
- sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
- }
-
- /**
- * @brief Sort a group according to the given comparison function.
- *
- * @sa sort
- *
- * @tparam Index Optional indexes of elements to compare.
- * @tparam Compare Type of comparison function object.
- * @tparam Sort Type of sort function object.
- * @tparam Args Types of arguments to forward to the sort function object.
- * @param compare A valid comparison function object.
- * @param algo A valid sort function object.
- * @param args Arguments to forward to the sort function object, if any.
- */
- template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
- void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
- const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
-
- if constexpr(sizeof...(Index) == 0) {
- static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
- storage<0>()->sort_n(descriptor->length(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
- } else {
- auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) {
- if constexpr(sizeof...(Index) == 1) {
- return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
- } else {
- return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
- }
- };
-
- storage<0>()->sort_n(descriptor->length(), std::move(comp), std::move(algo), std::forward<Args>(args)...);
- }
-
- auto cb = [this](auto *head, auto *...other) {
- for(auto next = descriptor->length(); next; --next) {
- const auto pos = next - 1;
- [[maybe_unused]] const auto entt = head->data()[pos];
- (other->swap_elements(other->data()[pos], entt), ...);
- }
- };
-
- std::apply(cb, cpools);
- }
-
-private:
- handler *descriptor;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/handle.hpp b/deps/include/entt/entity/handle.hpp deleted file mode 100644 index 15a7993..0000000 --- a/deps/include/entt/entity/handle.hpp +++ /dev/null @@ -1,431 +0,0 @@ -#ifndef ENTT_ENTITY_HANDLE_HPP
-#define ENTT_ENTITY_HANDLE_HPP
-
-#include <iterator>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include "../config/config.h"
-#include "../core/iterator.hpp"
-#include "../core/type_traits.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename It>
-class handle_storage_iterator final {
- template<typename Other>
- friend class handle_storage_iterator;
-
- using underlying_type = std::remove_reference_t<typename It::value_type::second_type>;
- using entity_type = typename underlying_type::entity_type;
-
-public:
- using value_type = typename std::iterator_traits<It>::value_type;
- using pointer = input_iterator_pointer<value_type>;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category = std::input_iterator_tag;
- using iterator_concept = std::forward_iterator_tag;
-
- constexpr handle_storage_iterator() noexcept
- : entt{null},
- it{},
- last{} {}
-
- constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept
- : entt{value},
- it{from},
- last{to} {
- while(it != last && !it->second.contains(entt)) {
- ++it;
- }
- }
-
- constexpr handle_storage_iterator &operator++() noexcept {
- while(++it != last && !it->second.contains(entt)) {}
- return *this;
- }
-
- constexpr handle_storage_iterator operator++(int) noexcept {
- handle_storage_iterator orig = *this;
- return ++(*this), orig;
- }
-
- [[nodiscard]] constexpr reference operator*() const noexcept {
- return *it;
- }
-
- [[nodiscard]] constexpr pointer operator->() const noexcept {
- return operator*();
- }
-
- template<typename ILhs, typename IRhs>
- friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept;
-
-private:
- entity_type entt;
- It it;
- It last;
-};
-
-template<typename ILhs, typename IRhs>
-[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
- return lhs.it == rhs.it;
-}
-
-template<typename ILhs, typename IRhs>
-[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Non-owning handle to an entity.
- *
- * Tiny wrapper around a registry and an entity.
- *
- * @tparam Registry Basic registry type.
- * @tparam Scope Types to which to restrict the scope of a handle.
- */
-template<typename Registry, typename... Scope>
-class basic_handle {
- using traits_type = entt_traits<typename Registry::entity_type>;
-
- [[nodiscard]] auto &owner_or_assert() const noexcept {
- ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
- return static_cast<Registry &>(*owner);
- }
-
-public:
- /*! @brief Type of registry accepted by the handle. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename traits_type::value_type;
- /*! @brief Underlying version type. */
- using version_type = typename traits_type::version_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Iterable handle type. */
- using iterable = iterable_adaptor<internal::handle_storage_iterator<typename decltype(std::declval<registry_type>().storage())::iterator>>;
-
- /*! @brief Constructs an invalid handle. */
- basic_handle() noexcept
- : owner{},
- entt{null} {}
-
- /**
- * @brief Constructs a handle from a given registry and entity.
- * @param ref An instance of the registry class.
- * @param value A valid identifier.
- */
- basic_handle(registry_type &ref, entity_type value) noexcept
- : owner{&ref},
- entt{value} {}
-
- /**
- * @brief Returns an iterable object to use to _visit_ a handle.
- *
- * The iterable object returns a pair that contains the name and a reference
- * to the current storage.<br/>
- * Returned storage are those that contain the entity associated with the
- * handle.
- *
- * @return An iterable object to use to _visit_ the handle.
- */
- [[nodiscard]] iterable storage() const noexcept {
- auto underlying = owner_or_assert().storage();
- return iterable{{entt, underlying.begin(), underlying.end()}, {entt, underlying.end(), underlying.end()}};
- }
-
- /*! @copydoc valid */
- [[nodiscard]] explicit operator bool() const noexcept {
- return owner && owner->valid(entt);
- }
-
- /**
- * @brief Checks if a handle refers to non-null registry pointer and entity.
- * @return True if the handle refers to non-null registry and entity, false
- * otherwise.
- */
- [[nodiscard]] bool valid() const {
- return static_cast<bool>(*this);
- }
-
- /**
- * @brief Returns a pointer to the underlying registry, if any.
- * @return A pointer to the underlying registry, if any.
- */
- [[nodiscard]] registry_type *registry() const noexcept {
- return owner;
- }
-
- /**
- * @brief Returns the entity associated with a handle.
- * @return The entity associated with the handle.
- */
- [[nodiscard]] entity_type entity() const noexcept {
- return entt;
- }
-
- /*! @copydoc entity */
- [[nodiscard]] operator entity_type() const noexcept {
- return entity();
- }
-
- /*! @brief Destroys the entity associated with a handle. */
- void destroy() {
- owner_or_assert().destroy(std::exchange(entt, null));
- }
-
- /**
- * @brief Destroys the entity associated with a handle.
- * @param version A desired version upon destruction.
- */
- void destroy(const version_type version) {
- owner_or_assert().destroy(std::exchange(entt, null), version);
- }
-
- /**
- * @brief Assigns the given element to a handle.
- * @tparam Type Type of element to create.
- * @tparam Args Types of arguments to use to construct the element.
- * @param args Parameters to use to initialize the element.
- * @return A reference to the newly created element.
- */
- template<typename Type, typename... Args>
- // NOLINTNEXTLINE(modernize-use-nodiscard)
- decltype(auto) emplace(Args &&...args) const {
- static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
- return owner_or_assert().template emplace<Type>(entt, std::forward<Args>(args)...);
- }
-
- /**
- * @brief Assigns or replaces the given element for a handle.
- * @tparam Type Type of element to assign or replace.
- * @tparam Args Types of arguments to use to construct the element.
- * @param args Parameters to use to initialize the element.
- * @return A reference to the newly created element.
- */
- template<typename Type, typename... Args>
- decltype(auto) emplace_or_replace(Args &&...args) const {
- static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
- return owner_or_assert().template emplace_or_replace<Type>(entt, std::forward<Args>(args)...);
- }
-
- /**
- * @brief Patches the given element for a handle.
- * @tparam Type Type of element to patch.
- * @tparam Func Types of the function objects to invoke.
- * @param func Valid function objects.
- * @return A reference to the patched element.
- */
- template<typename Type, typename... Func>
- decltype(auto) patch(Func &&...func) const {
- static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
- return owner_or_assert().template patch<Type>(entt, std::forward<Func>(func)...);
- }
-
- /**
- * @brief Replaces the given element for a handle.
- * @tparam Type Type of element to replace.
- * @tparam Args Types of arguments to use to construct the element.
- * @param args Parameters to use to initialize the element.
- * @return A reference to the element being replaced.
- */
- template<typename Type, typename... Args>
- decltype(auto) replace(Args &&...args) const {
- static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
- return owner_or_assert().template replace<Type>(entt, std::forward<Args>(args)...);
- }
-
- /**
- * @brief Removes the given elements from a handle.
- * @tparam Type Types of elements to remove.
- * @return The number of elements actually removed.
- */
- template<typename... Type>
- // NOLINTNEXTLINE(modernize-use-nodiscard)
- size_type remove() const {
- static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
- return owner_or_assert().template remove<Type...>(entt);
- }
-
- /**
- * @brief Erases the given elements from a handle.
- * @tparam Type Types of elements to erase.
- */
- template<typename... Type>
- void erase() const {
- static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
- owner_or_assert().template erase<Type...>(entt);
- }
-
- /**
- * @brief Checks if a handle has all the given elements.
- * @tparam Type Elements for which to perform the check.
- * @return True if the handle has all the elements, false otherwise.
- */
- template<typename... Type>
- [[nodiscard]] decltype(auto) all_of() const {
- return owner_or_assert().template all_of<Type...>(entt);
- }
-
- /**
- * @brief Checks if a handle has at least one of the given elements.
- * @tparam Type Elements for which to perform the check.
- * @return True if the handle has at least one of the given elements,
- * false otherwise.
- */
- template<typename... Type>
- [[nodiscard]] decltype(auto) any_of() const {
- return owner_or_assert().template any_of<Type...>(entt);
- }
-
- /**
- * @brief Returns references to the given elements for a handle.
- * @tparam Type Types of elements to get.
- * @return References to the elements owned by the handle.
- */
- template<typename... Type>
- [[nodiscard]] decltype(auto) get() const {
- static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
- return owner_or_assert().template get<Type...>(entt);
- }
-
- /**
- * @brief Returns a reference to the given element for a handle.
- * @tparam Type Type of element to get.
- * @tparam Args Types of arguments to use to construct the element.
- * @param args Parameters to use to initialize the element.
- * @return Reference to the element owned by the handle.
- */
- template<typename Type, typename... Args>
- [[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
- static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
- return owner_or_assert().template get_or_emplace<Type>(entt, std::forward<Args>(args)...);
- }
-
- /**
- * @brief Returns pointers to the given elements for a handle.
- * @tparam Type Types of elements to get.
- * @return Pointers to the elements owned by the handle.
- */
- template<typename... Type>
- [[nodiscard]] auto try_get() const {
- static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Type> && ...), "Invalid type");
- return owner_or_assert().template try_get<Type...>(entt);
- }
-
- /**
- * @brief Checks if a handle has elements assigned.
- * @return True if the handle has no elements assigned, false otherwise.
- */
- [[nodiscard]] bool orphan() const {
- return owner_or_assert().orphan(entt);
- }
-
- /**
- * @brief Returns a const handle from a non-const one.
- * @tparam Other A valid entity type.
- * @tparam Args Scope of the handle to construct.
- * @return A const handle referring to the same registry and the same
- * entity.
- */
- template<typename Other, typename... Args>
- operator basic_handle<Other, Args...>() const noexcept {
- static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
- static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles");
- return owner ? basic_handle<Other, Args...>{*owner, entt} : basic_handle<Other, Args...>{};
- }
-
-private:
- registry_type *owner;
- entity_type entt;
-};
-
-/**
- * @brief Compares two handles.
- * @tparam Args Scope of the first handle.
- * @tparam Other Scope of the second handle.
- * @param lhs A valid handle.
- * @param rhs A valid handle.
- * @return True if both handles refer to the same registry and the same
- * entity, false otherwise.
- */
-template<typename... Args, typename... Other>
-[[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
- return lhs.registry() == rhs.registry() && lhs.entity() == rhs.entity();
-}
-
-/**
- * @brief Compares two handles.
- * @tparam Args Scope of the first handle.
- * @tparam Other Scope of the second handle.
- * @param lhs A valid handle.
- * @param rhs A valid handle.
- * @return False if both handles refer to the same registry and the same
- * entity, true otherwise.
- */
-template<typename... Args, typename... Other>
-[[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-/**
- * @brief Compares a handle with the null object.
- * @tparam Args Scope of the handle.
- * @param lhs A valid handle.
- * @param rhs A null object yet to be converted.
- * @return False if the two elements differ, true otherwise.
- */
-template<typename... Args>
-[[nodiscard]] constexpr bool operator==(const basic_handle<Args...> &lhs, const null_t rhs) noexcept {
- return (lhs.entity() == rhs);
-}
-
-/**
- * @brief Compares a handle with the null object.
- * @tparam Args Scope of the handle.
- * @param lhs A null object yet to be converted.
- * @param rhs A valid handle.
- * @return False if the two elements differ, true otherwise.
- */
-template<typename... Args>
-[[nodiscard]] constexpr bool operator==(const null_t lhs, const basic_handle<Args...> &rhs) noexcept {
- return (rhs == lhs);
-}
-
-/**
- * @brief Compares a handle with the null object.
- * @tparam Args Scope of the handle.
- * @param lhs A valid handle.
- * @param rhs A null object yet to be converted.
- * @return True if the two elements differ, false otherwise.
- */
-template<typename... Args>
-[[nodiscard]] constexpr bool operator!=(const basic_handle<Args...> &lhs, const null_t rhs) noexcept {
- return (lhs.entity() != rhs);
-}
-
-/**
- * @brief Compares a handle with the null object.
- * @tparam Args Scope of the handle.
- * @param lhs A null object yet to be converted.
- * @param rhs A valid handle.
- * @return True if the two elements differ, false otherwise.
- */
-template<typename... Args>
-[[nodiscard]] constexpr bool operator!=(const null_t lhs, const basic_handle<Args...> &rhs) noexcept {
- return (rhs != lhs);
-}
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/helper.hpp b/deps/include/entt/entity/helper.hpp deleted file mode 100644 index 33e1978..0000000 --- a/deps/include/entt/entity/helper.hpp +++ /dev/null @@ -1,255 +0,0 @@ -#ifndef ENTT_ENTITY_HELPER_HPP
-#define ENTT_ENTITY_HELPER_HPP
-
-#include <memory>
-#include <type_traits>
-#include <utility>
-#include "../core/fwd.hpp"
-#include "../core/type_traits.hpp"
-#include "component.hpp"
-#include "fwd.hpp"
-#include "group.hpp"
-#include "storage.hpp"
-#include "view.hpp"
-
-namespace entt {
-
-/**
- * @brief Converts a registry to a view.
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-class as_view {
- template<typename... Get, typename... Exclude>
- [[nodiscard]] auto dispatch(get_t<Get...>, exclude_t<Exclude...>) const {
- return reg.template view<constness_as_t<typename Get::element_type, Get>...>(exclude_t<constness_as_t<typename Exclude::element_type, Exclude>...>{});
- }
-
-public:
- /*! @brief Type of registry to convert. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
-
- /**
- * @brief Constructs a converter for a given registry.
- * @param source A valid reference to a registry.
- */
- as_view(registry_type &source) noexcept
- : reg{source} {}
-
- /**
- * @brief Conversion function from a registry to a view.
- * @tparam Get Type of storage used to construct the view.
- * @tparam Exclude Types of storage used to filter the view.
- * @return A newly created view.
- */
- template<typename Get, typename Exclude>
- operator basic_view<Get, Exclude>() const {
- return dispatch(Get{}, Exclude{});
- }
-
-private:
- registry_type ®
-};
-
-/**
- * @brief Converts a registry to a group.
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-class as_group {
- template<typename... Owned, typename... Get, typename... Exclude>
- [[nodiscard]] auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
- if constexpr(std::is_const_v<registry_type>) {
- return reg.template group_if_exists<typename Owned::element_type...>(get_t<typename Get::element_type...>{}, exclude_t<typename Exclude::element_type...>{});
- } else {
- return reg.template group<constness_as_t<typename Owned::element_type, Owned>...>(get_t<constness_as_t<typename Get::element_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::element_type, Exclude>...>{});
- }
- }
-
-public:
- /*! @brief Type of registry to convert. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
-
- /**
- * @brief Constructs a converter for a given registry.
- * @param source A valid reference to a registry.
- */
- as_group(registry_type &source) noexcept
- : reg{source} {}
-
- /**
- * @brief Conversion function from a registry to a group.
- * @tparam Owned Types of _owned_ by the group.
- * @tparam Get Types of storage _observed_ by the group.
- * @tparam Exclude Types of storage used to filter the group.
- * @return A newly created group.
- */
- template<typename Owned, typename Get, typename Exclude>
- operator basic_group<Owned, Get, Exclude>() const {
- return dispatch(Owned{}, Get{}, Exclude{});
- }
-
-private:
- registry_type ®
-};
-
-/**
- * @brief Helper to create a listener that directly invokes a member function.
- * @tparam Member Member function to invoke on an element of the given type.
- * @tparam Registry Basic registry type.
- * @param reg A registry that contains the given entity and its elements.
- * @param entt Entity from which to get the element.
- */
-template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, decltype(Member)>>>
-void invoke(Registry ®, const typename Registry::entity_type entt) {
- static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
- (reg.template get<member_class_t<decltype(Member)>>(entt).*Member)(reg, entt);
-}
-
-/**
- * @brief Returns the entity associated with a given element.
- *
- * @warning
- * Currently, this function only works correctly with the default storage as it
- * makes assumptions about how the elements are laid out.
- *
- * @tparam Args Storage type template parameters.
- * @param storage A storage that contains the given element.
- * @param instance A valid element instance.
- * @return The entity associated with the given element.
- */
-template<typename... Args>
-typename basic_storage<Args...>::entity_type to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) {
- using traits_type = component_traits<typename basic_storage<Args...>::value_type>;
- static_assert(traits_type::page_size != 0u, "Unexpected page size");
- const typename basic_storage<Args...>::base_type &base = storage;
- const auto *addr = std::addressof(instance);
-
- for(auto it = base.rbegin(), last = base.rend(); it < last; it += traits_type::page_size) {
- if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(traits_type::page_size)) {
- return *(it + dist);
- }
- }
-
- return null;
-}
-
-/*! @brief Primary template isn't defined on purpose. */
-template<typename...>
-struct sigh_helper;
-
-/**
- * @brief Signal connection helper for registries.
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-struct sigh_helper<Registry> {
- /*! @brief Registry type. */
- using registry_type = Registry;
-
- /**
- * @brief Constructs a helper for a given registry.
- * @param ref A valid reference to a registry.
- */
- sigh_helper(registry_type &ref)
- : bucket{&ref} {}
-
- /**
- * @brief Binds a properly initialized helper to a given signal type.
- * @tparam Type Type of signal to bind the helper to.
- * @param id Optional name for the underlying storage to use.
- * @return A helper for a given registry and signal type.
- */
- template<typename Type>
- auto with(const id_type id = type_hash<Type>::value()) noexcept {
- return sigh_helper<registry_type, Type>{*bucket, id};
- }
-
- /**
- * @brief Returns a reference to the underlying registry.
- * @return A reference to the underlying registry.
- */
- [[nodiscard]] registry_type ®istry() noexcept {
- return *bucket;
- }
-
-private:
- registry_type *bucket;
-};
-
-/**
- * @brief Signal connection helper for registries.
- * @tparam Registry Basic registry type.
- * @tparam Type Type of signal to connect listeners to.
- */
-template<typename Registry, typename Type>
-struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
- /*! @brief Registry type. */
- using registry_type = Registry;
-
- /**
- * @brief Constructs a helper for a given registry.
- * @param ref A valid reference to a registry.
- * @param id Optional name for the underlying storage to use.
- */
- sigh_helper(registry_type &ref, const id_type id = type_hash<Type>::value())
- : sigh_helper<Registry>{ref},
- name{id} {}
-
- /**
- * @brief Forwards the call to `on_construct` on the underlying storage.
- * @tparam Candidate Function or member to connect.
- * @tparam Args Type of class or type of payload, if any.
- * @param args A valid object that fits the purpose, if any.
- * @return This helper.
- */
- template<auto Candidate, typename... Args>
- auto on_construct(Args &&...args) {
- this->registry().template on_construct<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
- return *this;
- }
-
- /**
- * @brief Forwards the call to `on_update` on the underlying storage.
- * @tparam Candidate Function or member to connect.
- * @tparam Args Type of class or type of payload, if any.
- * @param args A valid object that fits the purpose, if any.
- * @return This helper.
- */
- template<auto Candidate, typename... Args>
- auto on_update(Args &&...args) {
- this->registry().template on_update<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
- return *this;
- }
-
- /**
- * @brief Forwards the call to `on_destroy` on the underlying storage.
- * @tparam Candidate Function or member to connect.
- * @tparam Args Type of class or type of payload, if any.
- * @param args A valid object that fits the purpose, if any.
- * @return This helper.
- */
- template<auto Candidate, typename... Args>
- auto on_destroy(Args &&...args) {
- this->registry().template on_destroy<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
- return *this;
- }
-
-private:
- id_type name;
-};
-
-/**
- * @brief Deduction guide.
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-sigh_helper(Registry &) -> sigh_helper<Registry>;
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/mixin.hpp b/deps/include/entt/entity/mixin.hpp deleted file mode 100644 index d82bc92..0000000 --- a/deps/include/entt/entity/mixin.hpp +++ /dev/null @@ -1,318 +0,0 @@ -#ifndef ENTT_ENTITY_MIXIN_HPP
-#define ENTT_ENTITY_MIXIN_HPP
-
-#include <type_traits>
-#include <utility>
-#include "../config/config.h"
-#include "../core/any.hpp"
-#include "../signal/sigh.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/**
- * @brief Mixin type used to add signal support to storage types.
- *
- * The function type of a listener is equivalent to:
- *
- * @code{.cpp}
- * void(basic_registry<entity_type> &, entity_type);
- * @endcode
- *
- * This applies to all signals made available.
- *
- * @tparam Type Underlying storage type.
- * @tparam Registry Basic registry type.
- */
-template<typename Type, typename Registry>
-class basic_sigh_mixin final: public Type {
- using underlying_type = Type;
- using owner_type = Registry;
-
- using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>;
- using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
- using underlying_iterator = typename underlying_type::base_type::basic_iterator;
-
- static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
-
- [[nodiscard]] auto &owner_or_assert() const noexcept {
- ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
- return static_cast<owner_type &>(*owner);
- }
-
-private:
- void pop(underlying_iterator first, underlying_iterator last) final {
- if(auto ® = owner_or_assert(); destruction.empty()) {
- underlying_type::pop(first, last);
- } else {
- for(; first != last; ++first) {
- const auto entt = *first;
- destruction.publish(reg, entt);
- const auto it = underlying_type::find(entt);
- underlying_type::pop(it, it + 1u);
- }
- }
- }
-
- void pop_all() final {
- if(auto ® = owner_or_assert(); !destruction.empty()) {
- if constexpr(std::is_same_v<typename underlying_type::element_type, typename underlying_type::entity_type>) {
- for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) {
- destruction.publish(reg, underlying_type::base_type::operator[](pos));
- }
- } else {
- for(auto entt: static_cast<typename underlying_type::base_type &>(*this)) {
- if constexpr(underlying_type::storage_policy == deletion_policy::in_place) {
- if(entt != tombstone) {
- destruction.publish(reg, entt);
- }
- } else {
- destruction.publish(reg, entt);
- }
- }
- }
- }
-
- underlying_type::pop_all();
- }
-
- underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final {
- const auto it = underlying_type::try_emplace(entt, force_back, value);
-
- if(auto ® = owner_or_assert(); it != underlying_type::base_type::end()) {
- construction.publish(reg, *it);
- }
-
- return it;
- }
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = typename underlying_type::allocator_type;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename underlying_type::entity_type;
- /*! @brief Expected registry type. */
- using registry_type = owner_type;
-
- /*! @brief Default constructor. */
- basic_sigh_mixin()
- : basic_sigh_mixin{allocator_type{}} {}
-
- /**
- * @brief Constructs an empty storage with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_sigh_mixin(const allocator_type &allocator)
- : underlying_type{allocator},
- owner{},
- construction{allocator},
- destruction{allocator},
- update{allocator} {}
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_sigh_mixin(const basic_sigh_mixin &) = delete;
-
- /**
- * @brief Move constructor.
- * @param other The instance to move from.
- */
- basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
- : underlying_type{std::move(other)},
- owner{other.owner},
- construction{std::move(other.construction)},
- destruction{std::move(other.destruction)},
- update{std::move(other.update)} {}
-
- /**
- * @brief Allocator-extended move constructor.
- * @param other The instance to move from.
- * @param allocator The allocator to use.
- */
- basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator)
- : underlying_type{std::move(other), allocator},
- owner{other.owner},
- construction{std::move(other.construction), allocator},
- destruction{std::move(other.destruction), allocator},
- update{std::move(other.update), allocator} {}
-
- /*! @brief Default destructor. */
- ~basic_sigh_mixin() noexcept override = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This mixin.
- */
- basic_sigh_mixin &operator=(const basic_sigh_mixin &) = delete;
-
- /**
- * @brief Move assignment operator.
- * @param other The instance to move from.
- * @return This mixin.
- */
- basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept {
- owner = other.owner;
- construction = std::move(other.construction);
- destruction = std::move(other.destruction);
- update = std::move(other.update);
- underlying_type::operator=(std::move(other));
- return *this;
- }
-
- /**
- * @brief Exchanges the contents with those of a given storage.
- * @param other Storage to exchange the content with.
- */
- void swap(basic_sigh_mixin &other) {
- using std::swap;
- swap(owner, other.owner);
- swap(construction, other.construction);
- swap(destruction, other.destruction);
- swap(update, other.update);
- underlying_type::swap(other);
- }
-
- /**
- * @brief Returns a sink object.
- *
- * The sink returned by this function can be used to receive notifications
- * whenever a new instance is created and assigned to an entity.<br/>
- * Listeners are invoked after the object has been assigned to the entity.
- *
- * @sa sink
- *
- * @return A temporary sink object.
- */
- [[nodiscard]] auto on_construct() noexcept {
- return sink{construction};
- }
-
- /**
- * @brief Returns a sink object.
- *
- * The sink returned by this function can be used to receive notifications
- * whenever an instance is explicitly updated.<br/>
- * Listeners are invoked after the object has been updated.
- *
- * @sa sink
- *
- * @return A temporary sink object.
- */
- [[nodiscard]] auto on_update() noexcept {
- return sink{update};
- }
-
- /**
- * @brief Returns a sink object.
- *
- * The sink returned by this function can be used to receive notifications
- * whenever an instance is removed from an entity and thus destroyed.<br/>
- * Listeners are invoked before the object has been removed from the entity.
- *
- * @sa sink
- *
- * @return A temporary sink object.
- */
- [[nodiscard]] auto on_destroy() noexcept {
- return sink{destruction};
- }
-
- /**
- * @brief Emplace elements into a storage.
- *
- * The behavior of this operation depends on the underlying storage type
- * (for example, components vs entities).<br/>
- * Refer to the specific documentation for more details.
- *
- * @return A return value as returned by the underlying storage.
- */
- auto emplace() {
- const auto entt = underlying_type::emplace();
- construction.publish(owner_or_assert(), entt);
- return entt;
- }
-
- /**
- * @brief Emplace elements into a storage.
- *
- * The behavior of this operation depends on the underlying storage type
- * (for example, components vs entities).<br/>
- * Refer to the specific documentation for more details.
- *
- * @tparam Args Types of arguments to forward to the underlying storage.
- * @param hint A valid identifier.
- * @param args Parameters to forward to the underlying storage.
- * @return A return value as returned by the underlying storage.
- */
- template<typename... Args>
- decltype(auto) emplace(const entity_type hint, Args &&...args) {
- if constexpr(std::is_same_v<typename underlying_type::element_type, typename underlying_type::entity_type>) {
- const auto entt = underlying_type::emplace(hint, std::forward<Args>(args)...);
- construction.publish(owner_or_assert(), entt);
- return entt;
- } else {
- underlying_type::emplace(hint, std::forward<Args>(args)...);
- construction.publish(owner_or_assert(), hint);
- return this->get(hint);
- }
- }
-
- /**
- * @brief Patches the given instance for an entity.
- * @tparam Func Types of the function objects to invoke.
- * @param entt A valid identifier.
- * @param func Valid function objects.
- * @return A reference to the patched instance.
- */
- template<typename... Func>
- decltype(auto) patch(const entity_type entt, Func &&...func) {
- underlying_type::patch(entt, std::forward<Func>(func)...);
- update.publish(owner_or_assert(), entt);
- return this->get(entt);
- }
-
- /**
- * @brief Emplace elements into a storage.
- *
- * The behavior of this operation depends on the underlying storage type
- * (for example, components vs entities).<br/>
- * Refer to the specific documentation for more details.
- *
- * @tparam It Iterator type (as required by the underlying storage type).
- * @tparam Args Types of arguments to forward to the underlying storage.
- * @param first An iterator to the first element of the range.
- * @param last An iterator past the last element of the range.
- * @param args Parameters to use to forward to the underlying storage.
- */
- template<typename It, typename... Args>
- void insert(It first, It last, Args &&...args) {
- auto from = underlying_type::size();
- underlying_type::insert(first, last, std::forward<Args>(args)...);
-
- if(auto ® = owner_or_assert(); !construction.empty()) {
- for(const auto to = underlying_type::size(); from != to; ++from) {
- construction.publish(reg, underlying_type::operator[](from));
- }
- }
- }
-
- /**
- * @brief Forwards variables to derived classes, if any.
- * @param value A variable wrapped in an opaque container.
- */
- void bind(any value) noexcept final {
- auto *reg = any_cast<basic_registry_type>(&value);
- owner = reg ? reg : owner;
- underlying_type::bind(std::move(value));
- }
-
-private:
- basic_registry_type *owner;
- sigh_type construction;
- sigh_type destruction;
- sigh_type update;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/observer.hpp b/deps/include/entt/entity/observer.hpp deleted file mode 100644 index 5698723..0000000 --- a/deps/include/entt/entity/observer.hpp +++ /dev/null @@ -1,438 +0,0 @@ -#ifndef ENTT_ENTITY_OBSERVER_HPP
-#define ENTT_ENTITY_OBSERVER_HPP
-
-#include <cstddef>
-#include <cstdint>
-#include <limits>
-#include <type_traits>
-#include <utility>
-#include "../core/type_traits.hpp"
-#include "fwd.hpp"
-#include "storage.hpp"
-
-namespace entt {
-
-/*! @brief Grouping matcher. */
-template<typename...>
-struct matcher {};
-
-/**
- * @brief Collector.
- *
- * Primary template isn't defined on purpose. All the specializations give a
- * compile-time error, but for a few reasonable cases.
- */
-template<typename...>
-struct basic_collector;
-
-/**
- * @brief Collector.
- *
- * A collector contains a set of rules (literally, matchers) to use to track
- * entities.<br/>
- * Its main purpose is to generate a descriptor that allows an observer to know
- * how to connect to a registry.
- */
-template<>
-struct basic_collector<> {
- /**
- * @brief Adds a grouping matcher to the collector.
- * @tparam AllOf Types of elements tracked by the matcher.
- * @tparam NoneOf Types of elements used to filter out entities.
- * @return The updated collector.
- */
- template<typename... AllOf, typename... NoneOf>
- static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
- return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{};
- }
-
- /**
- * @brief Adds an observing matcher to the collector.
- * @tparam AnyOf Type of element for which changes should be detected.
- * @return The updated collector.
- */
- template<typename AnyOf>
- static constexpr auto update() noexcept {
- return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{};
- }
-};
-
-/**
- * @brief Collector.
- * @copydetails basic_collector<>
- * @tparam Reject Untracked types used to filter out entities.
- * @tparam Require Untracked types required by the matcher.
- * @tparam Rule Specific details of the current matcher.
- * @tparam Other Other matchers.
- */
-template<typename... Reject, typename... Require, typename... Rule, typename... Other>
-struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule...>, Other...> {
- /*! @brief Current matcher. */
- using current_type = matcher<type_list<Reject...>, type_list<Require...>, Rule...>;
-
- /**
- * @brief Adds a grouping matcher to the collector.
- * @tparam AllOf Types of elements tracked by the matcher.
- * @tparam NoneOf Types of elements used to filter out entities.
- * @return The updated collector.
- */
- template<typename... AllOf, typename... NoneOf>
- static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
- return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{};
- }
-
- /**
- * @brief Adds an observing matcher to the collector.
- * @tparam AnyOf Type of element for which changes should be detected.
- * @return The updated collector.
- */
- template<typename AnyOf>
- static constexpr auto update() noexcept {
- return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{};
- }
-
- /**
- * @brief Updates the filter of the last added matcher.
- * @tparam AllOf Types of elements required by the matcher.
- * @tparam NoneOf Types of elements used to filter out entities.
- * @return The updated collector.
- */
- template<typename... AllOf, typename... NoneOf>
- static constexpr auto where(exclude_t<NoneOf...> = exclude_t{}) noexcept {
- using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>;
- return basic_collector<extended_type, Other...>{};
- }
-};
-
-/*! @brief Variable template used to ease the definition of collectors. */
-inline constexpr basic_collector<> collector{};
-
-/**
- * @brief Observer.
- *
- * An observer returns all the entities and only the entities that fit the
- * requirements of at least one matcher. Moreover, it's guaranteed that the
- * entity list is tightly packed in memory for fast iterations.<br/>
- * In general, observers don't stay true to the order of any set of elements.
- *
- * Observers work mainly with two types of matchers, provided through a
- * collector:
- *
- * * Observing matcher: an observer will return at least all the living entities
- * for which one or more of the given elements have been updated and not yet
- * destroyed.
- * * Grouping matcher: an observer will return at least all the living entities
- * that would have entered the given group if it existed and that would have
- * not yet left it.
- *
- * If an entity respects the requirements of multiple matchers, it will be
- * returned once and only once by the observer in any case.
- *
- * Matchers support also filtering by means of a _where_ clause that accepts
- * both a list of types and an exclusion list.<br/>
- * Whenever a matcher finds that an entity matches its requirements, the
- * condition of the filter is verified before to register the entity itself.
- * Moreover, a registered entity isn't returned by the observer if the condition
- * set by the filter is broken in the meantime.
- *
- * @b Important
- *
- * Iterators aren't invalidated if:
- *
- * * New instances of the given elements are created and assigned to entities.
- * * The entity currently pointed is modified (as an example, if one of the
- * given elements is removed from the entity to which the iterator points).
- * * The entity currently pointed is destroyed.
- *
- * In all the other cases, modifying the pools of the given elements in any way
- * invalidates all the iterators.
- *
- * @warning
- * Lifetime of an observer doesn't necessarily have to overcome that of the
- * registry to which it is connected. However, the observer must be disconnected
- * from the registry before being destroyed to avoid crashes due to dangling
- * pointers.
- *
- * @tparam Registry Basic registry type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Registry, typename Allocator>
-class basic_observer {
- using mask_type = std::uint64_t;
- using storage_type = basic_storage<mask_type, typename Registry::entity_type, typename std::allocator_traits<Allocator>::template rebind_alloc<mask_type>>;
-
- template<std::size_t Index>
- static void discard_if(storage_type &storage, Registry &, const typename Registry::entity_type entt) {
- if(storage.contains(entt) && !(storage.get(entt) &= (~(1 << Index)))) {
- storage.erase(entt);
- }
- }
-
- template<typename>
- struct matcher_handler;
-
- template<typename... Reject, typename... Require, typename AnyOf>
- struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
- template<std::size_t Index>
- static void maybe_valid_if(storage_type &storage, Registry &parent, const typename Registry::entity_type entt) {
- if(parent.template all_of<Require...>(entt) && !parent.template any_of<Reject...>(entt)) {
- if(!storage.contains(entt)) {
- storage.emplace(entt);
- }
-
- storage.get(entt) |= (1 << Index);
- }
- }
-
- template<std::size_t Index>
- static void connect(storage_type &storage, Registry &parent) {
- (parent.template on_destroy<Require>().template connect<&discard_if<Index>>(storage), ...);
- (parent.template on_construct<Reject>().template connect<&discard_if<Index>>(storage), ...);
- parent.template on_update<AnyOf>().template connect<&maybe_valid_if<Index>>(storage);
- parent.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(storage);
- }
-
- static void disconnect(storage_type &storage, Registry &parent) {
- (parent.template on_destroy<Require>().disconnect(&storage), ...);
- (parent.template on_construct<Reject>().disconnect(&storage), ...);
- parent.template on_update<AnyOf>().disconnect(&storage);
- parent.template on_destroy<AnyOf>().disconnect(&storage);
- }
- };
-
- template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
- struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
- template<std::size_t Index, typename... Ignore>
- static void maybe_valid_if(storage_type &storage, Registry &parent, const typename Registry::entity_type entt) {
- bool guard{};
-
- if constexpr(sizeof...(Ignore) == 0) {
- guard = parent.template all_of<AllOf..., Require...>(entt) && !parent.template any_of<NoneOf..., Reject...>(entt);
- } else {
- guard = parent.template all_of<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !parent.template any_of<NoneOf>(entt)) && ...) && !parent.template any_of<Reject...>(entt);
- }
-
- if(guard) {
- if(!storage.contains(entt)) {
- storage.emplace(entt);
- }
-
- storage.get(entt) |= (1 << Index);
- }
- }
-
- template<std::size_t Index>
- static void connect(storage_type &storage, Registry &parent) {
- (parent.template on_destroy<Require>().template connect<&discard_if<Index>>(storage), ...);
- (parent.template on_construct<Reject>().template connect<&discard_if<Index>>(storage), ...);
- (parent.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(storage), ...);
- (parent.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index, NoneOf>>(storage), ...);
- (parent.template on_destroy<AllOf>().template connect<&discard_if<Index>>(storage), ...);
- (parent.template on_construct<NoneOf>().template connect<&discard_if<Index>>(storage), ...);
- }
-
- static void disconnect(storage_type &storage, Registry &parent) {
- (parent.template on_destroy<Require>().disconnect(&storage), ...);
- (parent.template on_construct<Reject>().disconnect(&storage), ...);
- (parent.template on_construct<AllOf>().disconnect(&storage), ...);
- (parent.template on_destroy<NoneOf>().disconnect(&storage), ...);
- (parent.template on_destroy<AllOf>().disconnect(&storage), ...);
- (parent.template on_construct<NoneOf>().disconnect(&storage), ...);
- }
- };
-
- template<typename... Matcher>
- static void disconnect(Registry &parent, storage_type &storage) {
- (matcher_handler<Matcher>::disconnect(storage, parent), ...);
- }
-
- template<typename... Matcher, std::size_t... Index>
- static void connect(Registry &parent, storage_type &storage, std::index_sequence<Index...>) {
- static_assert(sizeof...(Matcher) < std::numeric_limits<mask_type>::digits, "Too many matchers");
- (matcher_handler<Matcher>::template connect<Index>(storage, parent), ...);
- }
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = Allocator;
- /*! Basic registry type. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Random access iterator type. */
- using iterator = typename registry_type::common_type::iterator;
-
- /*! @brief Default constructor. */
- basic_observer()
- : basic_observer{allocator_type{}} {}
-
- /**
- * @brief Constructs an empty storage with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_observer(const allocator_type &allocator)
- : release{},
- parent{},
- storage{allocator} {}
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_observer(const basic_observer &) = delete;
-
- /*! @brief Default move constructor, deleted on purpose. */
- basic_observer(basic_observer &&) = delete;
-
- /**
- * @brief Creates an observer and connects it to a given registry.
- * @tparam Matcher Types of matchers to use to initialize the observer.
- * @param reg A valid reference to a registry.
- * @param allocator The allocator to use.
- */
- template<typename... Matcher>
- basic_observer(registry_type ®, basic_collector<Matcher...>, const allocator_type &allocator = allocator_type{})
- : release{&basic_observer::disconnect<Matcher...>},
- parent{®},
- storage{allocator} {
- connect<Matcher...>(reg, storage, std::index_sequence_for<Matcher...>{});
- }
-
- /*! @brief Default destructor. */
- ~basic_observer() noexcept = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This observer.
- */
- basic_observer &operator=(const basic_observer &) = delete;
-
- /**
- * @brief Default move assignment operator, deleted on purpose.
- * @return This observer.
- */
- basic_observer &operator=(basic_observer &&) = delete;
-
- /**
- * @brief Connects an observer to a given registry.
- * @tparam Matcher Types of matchers to use to initialize the observer.
- * @param reg A valid reference to a registry.
- */
- template<typename... Matcher>
- void connect(registry_type ®, basic_collector<Matcher...>) {
- disconnect();
- storage.clear();
-
- parent = ®
- release = &basic_observer::disconnect<Matcher...>;
- connect<Matcher...>(reg, storage, std::index_sequence_for<Matcher...>{});
- }
-
- /*! @brief Disconnects an observer from the registry it keeps track of. */
- void disconnect() {
- if(release) {
- release(*parent, storage);
- release = nullptr;
- }
- }
-
- /**
- * @brief Returns the number of elements in an observer.
- * @return Number of elements.
- */
- [[nodiscard]] size_type size() const noexcept {
- return storage.size();
- }
-
- /**
- * @brief Checks whether an observer is empty.
- * @return True if the observer is empty, false otherwise.
- */
- [[nodiscard]] bool empty() const noexcept {
- return storage.empty();
- }
-
- /**
- * @brief Direct access to the list of entities of the observer.
- *
- * The returned pointer is such that range `[data(), data() + size())` is
- * always a valid range, even if the container is empty.
- *
- * @note
- * Entities are in the reverse order as returned by the `begin`/`end`
- * iterators.
- *
- * @return A pointer to the array of entities.
- */
- [[nodiscard]] const entity_type *data() const noexcept {
- return storage.data();
- }
-
- /**
- * @brief Returns an iterator to the first entity of the observer.
- *
- * If the observer is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first entity of the observer.
- */
- [[nodiscard]] iterator begin() const noexcept {
- return storage.storage_type::base_type::begin();
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the observer.
- * @return An iterator to the entity following the last entity of the
- * observer.
- */
- [[nodiscard]] iterator end() const noexcept {
- return storage.storage_type::base_type::end();
- }
-
- /*! @brief Clears the underlying container. */
- void clear() noexcept {
- storage.clear();
- }
-
- /**
- * @brief Iterates entities and applies the given function object to them.
- *
- * The function object is invoked for each entity.<br/>
- * The signature of the function must be equivalent to the following form:
- *
- * @code{.cpp}
- * void(const entity_type);
- * @endcode
- *
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template<typename Func>
- void each(Func func) const {
- for(const auto entity: *this) {
- func(entity);
- }
- }
-
- /**
- * @brief Iterates entities and applies the given function object to them,
- * then clears the observer.
- *
- * @sa each
- *
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template<typename Func>
- void each(Func func) {
- std::as_const(*this).each(std::move(func));
- clear();
- }
-
-private:
- void (*release)(registry_type &, storage_type &);
- registry_type *parent;
- storage_type storage;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/organizer.hpp b/deps/include/entt/entity/organizer.hpp deleted file mode 100644 index f48390e..0000000 --- a/deps/include/entt/entity/organizer.hpp +++ /dev/null @@ -1,424 +0,0 @@ -#ifndef ENTT_ENTITY_ORGANIZER_HPP
-#define ENTT_ENTITY_ORGANIZER_HPP
-
-#include <cstddef>
-#include <type_traits>
-#include <utility>
-#include <vector>
-#include "../core/type_info.hpp"
-#include "../core/type_traits.hpp"
-#include "../core/utility.hpp"
-#include "../graph/adjacency_matrix.hpp"
-#include "../graph/flow.hpp"
-#include "fwd.hpp"
-#include "helper.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename>
-struct is_view: std::false_type {};
-
-template<typename... Args>
-struct is_view<basic_view<Args...>>: std::true_type {};
-
-template<typename Type>
-inline constexpr bool is_view_v = is_view<Type>::value;
-
-template<typename Type, typename Override>
-struct unpack_type {
- using ro = std::conditional_t<
- type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
- type_list<std::remove_const_t<Type>>,
- type_list<>>;
-
- using rw = std::conditional_t<
- type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
- type_list<Type>,
- type_list<>>;
-};
-
-template<typename... Args, typename... Override>
-struct unpack_type<basic_registry<Args...>, type_list<Override...>> {
- using ro = type_list<>;
- using rw = type_list<>;
-};
-
-template<typename... Args, typename... Override>
-struct unpack_type<const basic_registry<Args...>, type_list<Override...>>
- : unpack_type<basic_registry<Args...>, type_list<Override...>> {};
-
-template<typename... Get, typename... Exclude, typename... Override>
-struct unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {
- using ro = type_list_cat_t<type_list<typename Exclude::element_type...>, typename unpack_type<constness_as_t<typename Get::element_type, Get>, type_list<Override...>>::ro...>;
- using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::element_type, Get>, type_list<Override...>>::rw...>;
-};
-
-template<typename... Get, typename... Exclude, typename... Override>
-struct unpack_type<const basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
- : unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
-
-template<typename, typename>
-struct resource_traits;
-
-template<typename... Args, typename... Req>
-struct resource_traits<type_list<Args...>, type_list<Req...>> {
- using args = type_list<std::remove_const_t<Args>...>;
- using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>;
- using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
-};
-
-template<typename... Req, typename Ret, typename... Args>
-resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
-
-template<typename... Req, typename Ret, typename Type, typename... Args>
-resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
-
-template<typename... Req, typename Ret, typename Class, typename... Args>
-resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
-
-template<typename... Req, typename Ret, typename Class, typename... Args>
-resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Utility class for creating a static task graph.
- *
- * This class offers minimal support (but sufficient in many cases) for creating
- * an execution graph from functions and their requirements on resources.<br/>
- * Note that the resulting tasks aren't executed in any case. This isn't the
- * goal of the tool. Instead, they are returned to the user in the form of a
- * graph that allows for safe execution.
- *
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-class basic_organizer final {
- using callback_type = void(const void *, Registry &);
- using prepare_type = void(Registry &);
- using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
-
- struct vertex_data final {
- std::size_t ro_count{};
- std::size_t rw_count{};
- const char *name{};
- const void *payload{};
- callback_type *callback{};
- dependency_type *dependency{};
- prepare_type *prepare{};
- const type_info *info{};
- };
-
- template<typename Type>
- [[nodiscard]] static decltype(auto) extract(Registry ®) {
- if constexpr(std::is_same_v<Type, Registry>) {
- return reg;
- } else if constexpr(internal::is_view_v<Type>) {
- return static_cast<Type>(as_view{reg});
- } else {
- return reg.ctx().template emplace<std::remove_reference_t<Type>>();
- }
- }
-
- template<typename... Args>
- [[nodiscard]] static auto to_args(Registry ®, type_list<Args...>) {
- return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
- }
-
- template<typename... Type>
- [[nodiscard]] static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
- if constexpr(sizeof...(Type) == 0u) {
- return {};
- } else {
- const type_info *info[]{&type_id<Type>()...};
- const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
-
- for(std::size_t pos{}; pos < length; ++pos) {
- buffer[pos] = info[pos];
- }
-
- return length;
- }
- }
-
- template<typename... RO, typename... RW>
- void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) {
- builder.bind(static_cast<id_type>(index));
- builder.set(type_hash<Registry>::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u));
- (builder.ro(type_hash<RO>::value()), ...);
- (builder.rw(type_hash<RW>::value()), ...);
- }
-
-public:
- /*! Basic registry type. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Raw task function type. */
- using function_type = callback_type;
-
- /*! @brief Vertex type of a task graph defined as an adjacency list. */
- struct vertex {
- /**
- * @brief Constructs a vertex of the task graph.
- * @param data The data associated with the vertex.
- * @param from List of in-edges of the vertex.
- * @param to List of out-edges of the vertex.
- */
- vertex(vertex_data data, std::vector<std::size_t> from, std::vector<std::size_t> to)
- : node{std::move(data)},
- in{std::move(from)},
- out{std::move(to)} {}
-
- /**
- * @brief Fills a buffer with the type info objects for the writable
- * resources of a vertex.
- * @param buffer A buffer pre-allocated by the user.
- * @param length The length of the user-supplied buffer.
- * @return The number of type info objects written to the buffer.
- */
- [[nodiscard]] size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
- return node.dependency(false, buffer, length);
- }
-
- /**
- * @brief Fills a buffer with the type info objects for the read-only
- * resources of a vertex.
- * @param buffer A buffer pre-allocated by the user.
- * @param length The length of the user-supplied buffer.
- * @return The number of type info objects written to the buffer.
- */
- [[nodiscard]] size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
- return node.dependency(true, buffer, length);
- }
-
- /**
- * @brief Returns the number of read-only resources of a vertex.
- * @return The number of read-only resources of the vertex.
- */
- [[nodiscard]] size_type ro_count() const noexcept {
- return node.ro_count;
- }
-
- /**
- * @brief Returns the number of writable resources of a vertex.
- * @return The number of writable resources of the vertex.
- */
- [[nodiscard]] size_type rw_count() const noexcept {
- return node.rw_count;
- }
-
- /**
- * @brief Checks if a vertex is also a top-level one.
- * @return True if the vertex is a top-level one, false otherwise.
- */
- [[nodiscard]] bool top_level() const noexcept {
- return in.empty();
- }
-
- /**
- * @brief Returns a type info object associated with a vertex.
- * @return A properly initialized type info object.
- */
- [[nodiscard]] const type_info &info() const noexcept {
- return *node.info;
- }
-
- /**
- * @brief Returns a user defined name associated with a vertex, if any.
- * @return The user defined name associated with the vertex, if any.
- */
- [[nodiscard]] const char *name() const noexcept {
- return node.name;
- }
-
- /**
- * @brief Returns the function associated with a vertex.
- * @return The function associated with the vertex.
- */
- [[nodiscard]] function_type *callback() const noexcept {
- return node.callback;
- }
-
- /**
- * @brief Returns the payload associated with a vertex, if any.
- * @return The payload associated with the vertex, if any.
- */
- [[nodiscard]] const void *data() const noexcept {
- return node.payload;
- }
-
- /**
- * @brief Returns the list of in-edges of a vertex.
- * @return The list of in-edges of a vertex.
- */
- [[nodiscard]] const std::vector<std::size_t> &in_edges() const noexcept {
- return in;
- }
-
- /**
- * @brief Returns the list of out-edges of a vertex.
- * @return The list of out-edges of a vertex.
- */
- [[nodiscard]] const std::vector<std::size_t> &out_edges() const noexcept {
- return out;
- }
-
- /**
- * @brief Returns the list of nodes reachable from a given vertex.
- * @return The list of nodes reachable from the vertex.
- */
- [[deprecated("use ::out_edges")]] [[nodiscard]] const std::vector<std::size_t> &children() const noexcept {
- return out_edges();
- }
-
- /**
- * @brief Prepares a registry and assures that all required resources
- * are properly instantiated before using them.
- * @param reg A valid registry.
- */
- void prepare(registry_type ®) const {
- node.prepare ? node.prepare(reg) : void();
- }
-
- private:
- vertex_data node;
- std::vector<std::size_t> in;
- std::vector<std::size_t> out;
- };
-
- /**
- * @brief Adds a free function to the task list.
- * @tparam Candidate Function to add to the task list.
- * @tparam Req Additional requirements and/or override resource access mode.
- * @param name Optional name to associate with the task.
- */
- template<auto Candidate, typename... Req>
- void emplace(const char *name = nullptr) {
- using resource_type = decltype(internal::free_function_to_resource_traits<Req...>(Candidate));
- constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
-
- callback_type *callback = +[](const void *, registry_type ®) {
- std::apply(Candidate, to_args(reg, typename resource_type::args{}));
- };
-
- vertex_data vdata{
- resource_type::ro::size,
- resource_type::rw::size,
- name,
- nullptr,
- callback,
- +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
- +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); },
- &type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
-
- track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
- vertices.push_back(std::move(vdata));
- }
-
- /**
- * @brief Adds a free function with payload or a member function with an
- * instance to the task list.
- * @tparam Candidate Function or member to add to the task list.
- * @tparam Req Additional requirements and/or override resource access mode.
- * @tparam Type Type of class or type of payload.
- * @param value_or_instance A valid object that fits the purpose.
- * @param name Optional name to associate with the task.
- */
- template<auto Candidate, typename... Req, typename Type>
- void emplace(Type &value_or_instance, const char *name = nullptr) {
- using resource_type = decltype(internal::constrained_function_to_resource_traits<Req...>(Candidate));
- constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
-
- callback_type *callback = +[](const void *payload, registry_type ®) {
- Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
- std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
- };
-
- vertex_data vdata{
- resource_type::ro::size,
- resource_type::rw::size,
- name,
- &value_or_instance,
- callback,
- +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
- +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); },
- &type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
-
- track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
- vertices.push_back(std::move(vdata));
- }
-
- /**
- * @brief Adds an user defined function with optional payload to the task
- * list.
- * @tparam Req Additional requirements and/or override resource access mode.
- * @param func Function to add to the task list.
- * @param payload User defined arbitrary data.
- * @param name Optional name to associate with the task.
- */
- template<typename... Req>
- void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
- using resource_type = internal::resource_traits<type_list<>, type_list<Req...>>;
- track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
-
- vertex_data vdata{
- resource_type::ro::size,
- resource_type::rw::size,
- name,
- payload,
- func,
- +[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
- nullptr,
- &type_id<void>()};
-
- vertices.push_back(std::move(vdata));
- }
-
- /**
- * @brief Generates a task graph for the current content.
- * @return The adjacency list of the task graph.
- */
- [[nodiscard]] std::vector<vertex> graph() {
- std::vector<vertex> adjacency_list{};
- adjacency_list.reserve(vertices.size());
- auto adjacency_matrix = builder.graph();
-
- for(auto curr: adjacency_matrix.vertices()) {
- std::vector<std::size_t> in{};
- std::vector<std::size_t> out{};
-
- for(auto &&edge: adjacency_matrix.in_edges(curr)) {
- in.push_back(edge.first);
- }
-
- for(auto &&edge: adjacency_matrix.out_edges(curr)) {
- out.push_back(edge.second);
- }
-
- adjacency_list.emplace_back(vertices[curr], std::move(in), std::move(out));
- }
-
- return adjacency_list;
- }
-
- /*! @brief Erases all elements from a container. */
- void clear() {
- builder.clear();
- vertices.clear();
- }
-
-private:
- std::vector<vertex_data> vertices;
- flow builder;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/ranges.hpp b/deps/include/entt/entity/ranges.hpp deleted file mode 100644 index 98f9fff..0000000 --- a/deps/include/entt/entity/ranges.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ENTT_ENTITY_RANGES_HPP
-#define ENTT_ENTITY_RANGES_HPP
-
-#if __has_include(<version>)
-# include <version>
-#
-# if defined(__cpp_lib_ranges)
-# include <ranges>
-# include "fwd.hpp"
-
-template<class... Args>
-inline constexpr bool std::ranges::enable_borrowed_range<entt::basic_view<Args...>>{true};
-
-template<class... Args>
-inline constexpr bool std::ranges::enable_borrowed_range<entt::basic_group<Args...>>{true};
-
-template<class... Args>
-inline constexpr bool std::ranges::enable_view<entt::basic_view<Args...>>{true};
-
-template<class... Args>
-inline constexpr bool std::ranges::enable_view<entt::basic_group<Args...>>{true};
-
-# endif
-#endif
-
-#endif
\ No newline at end of file diff --git a/deps/include/entt/entity/registry.hpp b/deps/include/entt/entity/registry.hpp deleted file mode 100644 index c7be616..0000000 --- a/deps/include/entt/entity/registry.hpp +++ /dev/null @@ -1,1222 +0,0 @@ -#ifndef ENTT_ENTITY_REGISTRY_HPP
-#define ENTT_ENTITY_REGISTRY_HPP
-
-#include <algorithm>
-#include <array>
-#include <cstddef>
-#include <functional>
-#include <iterator>
-#include <memory>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include <vector>
-#include "../config/config.h"
-#include "../container/dense_map.hpp"
-#include "../core/algorithm.hpp"
-#include "../core/any.hpp"
-#include "../core/fwd.hpp"
-#include "../core/iterator.hpp"
-#include "../core/memory.hpp"
-#include "../core/type_info.hpp"
-#include "../core/type_traits.hpp"
-#include "../core/utility.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-#include "group.hpp"
-#include "mixin.hpp"
-#include "sparse_set.hpp"
-#include "storage.hpp"
-#include "view.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename It>
-class registry_storage_iterator final {
- template<typename Other>
- friend class registry_storage_iterator;
-
- using mapped_type = std::remove_reference_t<decltype(std::declval<It>()->second)>;
-
-public:
- using value_type = std::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
- using pointer = input_iterator_pointer<value_type>;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category = std::input_iterator_tag;
- using iterator_concept = std::random_access_iterator_tag;
-
- constexpr registry_storage_iterator() noexcept
- : it{} {}
-
- constexpr registry_storage_iterator(It iter) noexcept
- : it{iter} {}
-
- template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
- constexpr registry_storage_iterator(const registry_storage_iterator<Other> &other) noexcept
- : registry_storage_iterator{other.it} {}
-
- constexpr registry_storage_iterator &operator++() noexcept {
- return ++it, *this;
- }
-
- constexpr registry_storage_iterator operator++(int) noexcept {
- registry_storage_iterator orig = *this;
- return ++(*this), orig;
- }
-
- constexpr registry_storage_iterator &operator--() noexcept {
- return --it, *this;
- }
-
- constexpr registry_storage_iterator operator--(int) noexcept {
- registry_storage_iterator orig = *this;
- return operator--(), orig;
- }
-
- constexpr registry_storage_iterator &operator+=(const difference_type value) noexcept {
- it += value;
- return *this;
- }
-
- constexpr registry_storage_iterator operator+(const difference_type value) const noexcept {
- registry_storage_iterator copy = *this;
- return (copy += value);
- }
-
- constexpr registry_storage_iterator &operator-=(const difference_type value) noexcept {
- return (*this += -value);
- }
-
- constexpr registry_storage_iterator operator-(const difference_type value) const noexcept {
- return (*this + -value);
- }
-
- [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
- return {it[value].first, *it[value].second};
- }
-
- [[nodiscard]] constexpr reference operator*() const noexcept {
- return operator[](0);
- }
-
- [[nodiscard]] constexpr pointer operator->() const noexcept {
- return operator*();
- }
-
- template<typename Lhs, typename Rhs>
- friend constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
-
- template<typename Lhs, typename Rhs>
- friend constexpr bool operator==(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
-
- template<typename Lhs, typename Rhs>
- friend constexpr bool operator<(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
-
-private:
- It it;
-};
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
- return lhs.it - rhs.it;
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
- return lhs.it == rhs.it;
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator!=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator<(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
- return lhs.it < rhs.it;
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator>(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
- return rhs < lhs;
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator<=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
- return !(lhs > rhs);
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator>=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
- return !(lhs < rhs);
-}
-
-template<typename Allocator>
-class registry_context {
- using alloc_traits = std::allocator_traits<Allocator>;
- using allocator_type = typename alloc_traits::template rebind_alloc<std::pair<const id_type, basic_any<0u>>>;
-
-public:
- explicit registry_context(const allocator_type &allocator)
- : ctx{allocator} {}
-
- template<typename Type, typename... Args>
- Type &emplace_as(const id_type id, Args &&...args) {
- return any_cast<Type &>(ctx.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
- }
-
- template<typename Type, typename... Args>
- Type &emplace(Args &&...args) {
- return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
- }
-
- template<typename Type>
- Type &insert_or_assign(const id_type id, Type &&value) {
- return any_cast<std::remove_cv_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
- }
-
- template<typename Type>
- Type &insert_or_assign(Type &&value) {
- return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
- }
-
- template<typename Type>
- bool erase(const id_type id = type_id<Type>().hash()) {
- const auto it = ctx.find(id);
- return it != ctx.end() && it->second.type() == type_id<Type>() ? (ctx.erase(it), true) : false;
- }
-
- template<typename Type>
- [[nodiscard]] const Type &get(const id_type id = type_id<Type>().hash()) const {
- return any_cast<const Type &>(ctx.at(id));
- }
-
- template<typename Type>
- [[nodiscard]] Type &get(const id_type id = type_id<Type>().hash()) {
- return any_cast<Type &>(ctx.at(id));
- }
-
- template<typename Type>
- [[nodiscard]] const Type *find(const id_type id = type_id<Type>().hash()) const {
- const auto it = ctx.find(id);
- return it != ctx.cend() ? any_cast<const Type>(&it->second) : nullptr;
- }
-
- template<typename Type>
- [[nodiscard]] Type *find(const id_type id = type_id<Type>().hash()) {
- const auto it = ctx.find(id);
- return it != ctx.end() ? any_cast<Type>(&it->second) : nullptr;
- }
-
- template<typename Type>
- [[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
- const auto it = ctx.find(id);
- return it != ctx.cend() && it->second.type() == type_id<Type>();
- }
-
-private:
- dense_map<id_type, basic_any<0u>, identity, std::equal_to<>, allocator_type> ctx;
-};
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Fast and reliable entity-component system.
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Entity, typename Allocator>
-class basic_registry {
- using base_type = basic_sparse_set<Entity, Allocator>;
- using alloc_traits = std::allocator_traits<Allocator>;
- static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
- // std::shared_ptr because of its type erased allocator which is useful here
- using pool_container_type = dense_map<id_type, std::shared_ptr<base_type>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<base_type>>>>;
- using group_container_type = dense_map<id_type, std::shared_ptr<internal::group_descriptor>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<internal::group_descriptor>>>>;
- using traits_type = entt_traits<Entity>;
-
- template<typename Type>
- [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
- static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
-
- if constexpr(std::is_same_v<Type, entity_type>) {
- ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
- return entities;
- } else {
- using storage_type = storage_for_type<Type>;
-
- if(auto it = pools.find(id); it == pools.cend()) {
- using alloc_type = typename storage_type::allocator_type;
- typename pool_container_type::mapped_type cpool{};
-
- if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
- // std::allocator<void> has no cross constructors (waiting for C++20)
- cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
- } else {
- cpool = std::allocate_shared<storage_type>(get_allocator(), get_allocator());
- }
-
- pools.emplace(id, cpool);
- cpool->bind(forward_as_any(*this));
-
- return static_cast<storage_type &>(*cpool);
- } else {
- ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
- return static_cast<storage_type &>(*it->second);
- }
- }
- }
-
- template<typename Type>
- [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
- static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
-
- if constexpr(std::is_same_v<Type, entity_type>) {
- ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
- return &entities;
- } else {
- if(const auto it = pools.find(id); it != pools.cend()) {
- ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
- return static_cast<const storage_for_type<Type> *>(it->second.get());
- }
-
- return static_cast<const storage_for_type<Type> *>(nullptr);
- }
- }
-
- void rebind() {
- entities.bind(forward_as_any(*this));
-
- for(auto &&curr: pools) {
- curr.second->bind(forward_as_any(*this));
- }
- }
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = Allocator;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename traits_type::value_type;
- /*! @brief Underlying version type. */
- using version_type = typename traits_type::version_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Common type among all storage types. */
- using common_type = base_type;
- /*! @brief Context type. */
- using context = internal::registry_context<allocator_type>;
- /*! @brief Iterable registry type. */
- using iterable = iterable_adaptor<internal::registry_storage_iterator<typename pool_container_type::iterator>>;
- /*! @brief Constant iterable registry type. */
- using const_iterable = iterable_adaptor<internal::registry_storage_iterator<typename pool_container_type::const_iterator>>;
-
- /**
- * @copybrief storage_for
- * @tparam Type Storage value type, eventually const.
- */
- template<typename Type>
- using storage_for_type = typename storage_for<Type, Entity, typename alloc_traits::template rebind_alloc<std::remove_const_t<Type>>>::type;
-
- /*! @brief Default constructor. */
- basic_registry()
- : basic_registry{allocator_type{}} {}
-
- /**
- * @brief Constructs an empty registry with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_registry(const allocator_type &allocator)
- : basic_registry{0u, allocator} {}
-
- /**
- * @brief Allocates enough memory upon construction to store `count` pools.
- * @param count The number of pools to allocate memory for.
- * @param allocator The allocator to use.
- */
- basic_registry(const size_type count, const allocator_type &allocator = allocator_type{})
- : vars{allocator},
- pools{allocator},
- groups{allocator},
- entities{allocator} {
- pools.reserve(count);
- rebind();
- }
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_registry(const basic_registry &) = delete;
-
- /**
- * @brief Move constructor.
- * @param other The instance to move from.
- */
- basic_registry(basic_registry &&other) noexcept
- : vars{std::move(other.vars)},
- pools{std::move(other.pools)},
- groups{std::move(other.groups)},
- entities{std::move(other.entities)} {
- rebind();
- }
-
- /*! @brief Default destructor. */
- ~basic_registry() noexcept = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This mixin.
- */
- basic_registry &operator=(const basic_registry &) = delete;
-
- /**
- * @brief Move assignment operator.
- * @param other The instance to move from.
- * @return This registry.
- */
- basic_registry &operator=(basic_registry &&other) noexcept {
- vars = std::move(other.vars);
- pools = std::move(other.pools);
- groups = std::move(other.groups);
- entities = std::move(other.entities);
-
- rebind();
-
- return *this;
- }
-
- /**
- * @brief Exchanges the contents with those of a given registry.
- * @param other Registry to exchange the content with.
- */
- void swap(basic_registry &other) {
- using std::swap;
-
- swap(vars, other.vars);
- swap(pools, other.pools);
- swap(groups, other.groups);
- swap(entities, other.entities);
-
- rebind();
- other.rebind();
- }
-
- /**
- * @brief Returns the associated allocator.
- * @return The associated allocator.
- */
- [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
- return entities.get_allocator();
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a registry.
- *
- * The iterable object returns a pair that contains the name and a reference
- * to the current storage.
- *
- * @return An iterable object to use to _visit_ the registry.
- */
- [[nodiscard]] iterable storage() noexcept {
- return iterable{pools.begin(), pools.end()};
- }
-
- /*! @copydoc storage */
- [[nodiscard]] const_iterable storage() const noexcept {
- return const_iterable{pools.cbegin(), pools.cend()};
- }
-
- /**
- * @brief Finds the storage associated with a given name, if any.
- * @param id Name used to map the storage within the registry.
- * @return A pointer to the storage if it exists, a null pointer otherwise.
- */
- [[nodiscard]] common_type *storage(const id_type id) {
- return const_cast<common_type *>(std::as_const(*this).storage(id));
- }
-
- /**
- * @brief Finds the storage associated with a given name, if any.
- * @param id Name used to map the storage within the registry.
- * @return A pointer to the storage if it exists, a null pointer otherwise.
- */
- [[nodiscard]] const common_type *storage(const id_type id) const {
- const auto it = pools.find(id);
- return it == pools.cend() ? nullptr : it->second.get();
- }
-
- /**
- * @brief Returns the storage for a given element type.
- * @tparam Type Type of element of which to return the storage.
- * @param id Optional name used to map the storage within the registry.
- * @return The storage for the given element type.
- */
- template<typename Type>
- storage_for_type<Type> &storage(const id_type id = type_hash<Type>::value()) {
- return assure<Type>(id);
- }
-
- /**
- * @brief Returns the storage for a given element type, if any.
- * @tparam Type Type of element of which to return the storage.
- * @param id Optional name used to map the storage within the registry.
- * @return The storage for the given element type.
- */
- template<typename Type>
- [[nodiscard]] const storage_for_type<Type> *storage(const id_type id = type_hash<Type>::value()) const {
- return assure<Type>(id);
- }
-
- /**
- * @brief Checks if an identifier refers to a valid entity.
- * @param entt An identifier, either valid or not.
- * @return True if the identifier is valid, false otherwise.
- */
- [[nodiscard]] bool valid(const entity_type entt) const {
- return static_cast<size_type>(entities.find(entt).index()) < entities.free_list();
- }
-
- /**
- * @brief Returns the actual version for an identifier.
- * @param entt A valid identifier.
- * @return The version for the given identifier if valid, the tombstone
- * version otherwise.
- */
- [[nodiscard]] version_type current(const entity_type entt) const {
- return entities.current(entt);
- }
-
- /**
- * @brief Creates a new entity or recycles a destroyed one.
- * @return A valid identifier.
- */
- [[nodiscard]] entity_type create() {
- return entities.emplace();
- }
-
- /**
- * @copybrief create
- *
- * If the requested entity isn't in use, the suggested identifier is used.
- * Otherwise, a new identifier is generated.
- *
- * @param hint Required identifier.
- * @return A valid identifier.
- */
- [[nodiscard]] entity_type create(const entity_type hint) {
- return entities.emplace(hint);
- }
-
- /**
- * @brief Assigns each element in a range an identifier.
- *
- * @sa create
- *
- * @tparam It Type of forward iterator.
- * @param first An iterator to the first element of the range to generate.
- * @param last An iterator past the last element of the range to generate.
- */
- template<typename It>
- void create(It first, It last) {
- entities.insert(std::move(first), std::move(last));
- }
-
- /**
- * @brief Destroys an entity and releases its identifier.
- *
- * @warning
- * Adding or removing elements to an entity that is being destroyed can
- * result in undefined behavior.
- *
- * @param entt A valid identifier.
- * @return The version of the recycled entity.
- */
- version_type destroy(const entity_type entt) {
- for(size_type pos = pools.size(); pos; --pos) {
- pools.begin()[pos - 1u].second->remove(entt);
- }
-
- entities.erase(entt);
- return entities.current(entt);
- }
-
- /**
- * @brief Destroys an entity and releases its identifier.
- *
- * The suggested version or the valid version closest to the suggested one
- * is used instead of the implicitly generated version.
- *
- * @sa destroy
- *
- * @param entt A valid identifier.
- * @param version A desired version upon destruction.
- * @return The version actually assigned to the entity.
- */
- version_type destroy(const entity_type entt, const version_type version) {
- destroy(entt);
- const auto elem = traits_type::construct(traits_type::to_entity(entt), version);
- return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem);
- }
-
- /**
- * @brief Destroys all entities in a range and releases their identifiers.
- *
- * @sa destroy
- *
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- */
- template<typename It>
- void destroy(It first, It last) {
- const auto to = entities.sort_as(first, last);
- const auto from = entities.cend() - entities.free_list();
-
- for(auto &&curr: pools) {
- curr.second->remove(from, to);
- }
-
- entities.erase(from, to);
- }
-
- /**
- * @brief Assigns the given element to an entity.
- *
- * The element must have a proper constructor or be of aggregate type.
- *
- * @warning
- * Attempting to assign an element to an entity that already owns it results
- * in undefined behavior.
- *
- * @tparam Type Type of element to create.
- * @tparam Args Types of arguments to use to construct the element.
- * @param entt A valid identifier.
- * @param args Parameters to use to initialize the element.
- * @return A reference to the newly created element.
- */
- template<typename Type, typename... Args>
- decltype(auto) emplace(const entity_type entt, Args &&...args) {
- ENTT_ASSERT(valid(entt), "Invalid entity");
- return assure<Type>().emplace(entt, std::forward<Args>(args)...);
- }
-
- /**
- * @brief Assigns each entity in a range the given element.
- *
- * @sa emplace
- *
- * @tparam Type Type of element to create.
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @param value An instance of the element to assign.
- */
- template<typename Type, typename It>
- void insert(It first, It last, const Type &value = {}) {
- ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
- assure<Type>().insert(std::move(first), std::move(last), value);
- }
-
- /**
- * @brief Assigns each entity in a range the given elements.
- *
- * @sa emplace
- *
- * @tparam Type Type of element to create.
- * @tparam EIt Type of input iterator.
- * @tparam CIt Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @param from An iterator to the first element of the range of elements.
- */
- template<typename Type, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, Type>>>
- void insert(EIt first, EIt last, CIt from) {
- ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
- assure<Type>().insert(first, last, from);
- }
-
- /**
- * @brief Assigns or replaces the given element for an entity.
- *
- * @sa emplace
- * @sa replace
- *
- * @tparam Type Type of element to assign or replace.
- * @tparam Args Types of arguments to use to construct the element.
- * @param entt A valid identifier.
- * @param args Parameters to use to initialize the element.
- * @return A reference to the newly created element.
- */
- template<typename Type, typename... Args>
- decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
- if(auto &cpool = assure<Type>(); cpool.contains(entt)) {
- return cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
- } else {
- ENTT_ASSERT(valid(entt), "Invalid entity");
- return cpool.emplace(entt, std::forward<Args>(args)...);
- }
- }
-
- /**
- * @brief Patches the given element for an entity.
- *
- * The signature of the function should be equivalent to the following:
- *
- * @code{.cpp}
- * void(Type &);
- * @endcode
- *
- * @warning
- * Attempting to patch an element of an entity that doesn't own it results
- * in undefined behavior.
- *
- * @tparam Type Type of element to patch.
- * @tparam Func Types of the function objects to invoke.
- * @param entt A valid identifier.
- * @param func Valid function objects.
- * @return A reference to the patched element.
- */
- template<typename Type, typename... Func>
- decltype(auto) patch(const entity_type entt, Func &&...func) {
- return assure<Type>().patch(entt, std::forward<Func>(func)...);
- }
-
- /**
- * @brief Replaces the given element for an entity.
- *
- * The element must have a proper constructor or be of aggregate type.
- *
- * @warning
- * Attempting to replace an element of an entity that doesn't own it results
- * in undefined behavior.
- *
- * @tparam Type Type of element to replace.
- * @tparam Args Types of arguments to use to construct the element.
- * @param entt A valid identifier.
- * @param args Parameters to use to initialize the element.
- * @return A reference to the element being replaced.
- */
- template<typename Type, typename... Args>
- decltype(auto) replace(const entity_type entt, Args &&...args) {
- return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
- }
-
- /**
- * @brief Removes the given elements from an entity.
- * @tparam Type Type of element to remove.
- * @tparam Other Other types of elements to remove.
- * @param entt A valid identifier.
- * @return The number of elements actually removed.
- */
- template<typename Type, typename... Other>
- size_type remove(const entity_type entt) {
- return (assure<Type>().remove(entt) + ... + assure<Other>().remove(entt));
- }
-
- /**
- * @brief Removes the given elements from all the entities in a range.
- *
- * @sa remove
- *
- * @tparam Type Type of element to remove.
- * @tparam Other Other types of elements to remove.
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @return The number of elements actually removed.
- */
- template<typename Type, typename... Other, typename It>
- size_type remove(It first, It last) {
- size_type count{};
-
- if constexpr(std::is_same_v<It, typename common_type::iterator>) {
- std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
-
- for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
- if constexpr(sizeof...(Other) != 0u) {
- if((*from)->data() == first.data()) {
- std::swap((*from), cpools.back());
- }
- }
-
- count += (*from)->remove(first, last);
- }
-
- } else {
- for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
- count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
- }
- }
-
- return count;
- }
-
- /**
- * @brief Erases the given elements from an entity.
- *
- * @warning
- * Attempting to erase an element from an entity that doesn't own it results
- * in undefined behavior.
- *
- * @tparam Type Types of elements to erase.
- * @tparam Other Other types of elements to erase.
- * @param entt A valid identifier.
- */
- template<typename Type, typename... Other>
- void erase(const entity_type entt) {
- (assure<Type>().erase(entt), (assure<Other>().erase(entt), ...));
- }
-
- /**
- * @brief Erases the given elements from all the entities in a range.
- *
- * @sa erase
- *
- * @tparam Type Types of elements to erase.
- * @tparam Other Other types of elements to erase.
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- */
- template<typename Type, typename... Other, typename It>
- void erase(It first, It last) {
- if constexpr(std::is_same_v<It, typename common_type::iterator>) {
- std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
-
- for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
- if constexpr(sizeof...(Other) != 0u) {
- if((*from)->data() == first.data()) {
- std::swap(*from, cpools.back());
- }
- }
-
- (*from)->erase(first, last);
- }
- } else {
- for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
- std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
- }
- }
- }
-
- /**
- * @brief Erases elements satisfying specific criteria from an entity.
- *
- * The function type is equivalent to:
- *
- * @code{.cpp}
- * void(const id_type, typename basic_registry<Entity>::common_type &);
- * @endcode
- *
- * Only storage where the entity exists are passed to the function.
- *
- * @tparam Func Type of the function object to invoke.
- * @param entt A valid identifier.
- * @param func A valid function object.
- */
- template<typename Func>
- void erase_if(const entity_type entt, Func func) {
- for(auto [id, cpool]: storage()) {
- if(cpool.contains(entt) && func(id, std::as_const(cpool))) {
- cpool.erase(entt);
- }
- }
- }
-
- /**
- * @brief Removes all tombstones from a registry or only the pools for the
- * given elements.
- * @tparam Type Types of elements for which to clear all tombstones.
- */
- template<typename... Type>
- void compact() {
- if constexpr(sizeof...(Type) == 0u) {
- for(auto &&curr: pools) {
- curr.second->compact();
- }
- } else {
- (assure<Type>().compact(), ...);
- }
- }
-
- /**
- * @brief Check if an entity is part of all the given storage.
- * @tparam Type Type of storage to check for.
- * @param entt A valid identifier.
- * @return True if the entity is part of all the storage, false otherwise.
- */
- template<typename... Type>
- [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
- if constexpr(sizeof...(Type) == 1u) {
- auto *cpool = assure<std::remove_const_t<Type>...>();
- return cpool && cpool->contains(entt);
- } else {
- return (all_of<Type>(entt) && ...);
- }
- }
-
- /**
- * @brief Check if an entity is part of at least one given storage.
- * @tparam Type Type of storage to check for.
- * @param entt A valid identifier.
- * @return True if the entity is part of at least one storage, false
- * otherwise.
- */
- template<typename... Type>
- [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
- return (all_of<Type>(entt) || ...);
- }
-
- /**
- * @brief Returns references to the given elements for an entity.
- *
- * @warning
- * Attempting to get an element from an entity that doesn't own it results
- * in undefined behavior.
- *
- * @tparam Type Types of elements to get.
- * @param entt A valid identifier.
- * @return References to the elements owned by the entity.
- */
- template<typename... Type>
- [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
- if constexpr(sizeof...(Type) == 1u) {
- return (assure<std::remove_const_t<Type>>()->get(entt), ...);
- } else {
- return std::forward_as_tuple(get<Type>(entt)...);
- }
- }
-
- /*! @copydoc get */
- template<typename... Type>
- [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
- if constexpr(sizeof...(Type) == 1u) {
- return (static_cast<storage_for_type<Type> &>(assure<std::remove_const_t<Type>>()).get(entt), ...);
- } else {
- return std::forward_as_tuple(get<Type>(entt)...);
- }
- }
-
- /**
- * @brief Returns a reference to the given element for an entity.
- *
- * In case the entity doesn't own the element, the parameters provided are
- * used to construct it.
- *
- * @sa get
- * @sa emplace
- *
- * @tparam Type Type of element to get.
- * @tparam Args Types of arguments to use to construct the element.
- * @param entt A valid identifier.
- * @param args Parameters to use to initialize the element.
- * @return Reference to the element owned by the entity.
- */
- template<typename Type, typename... Args>
- [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
- if(auto &cpool = assure<Type>(); cpool.contains(entt)) {
- return cpool.get(entt);
- } else {
- ENTT_ASSERT(valid(entt), "Invalid entity");
- return cpool.emplace(entt, std::forward<Args>(args)...);
- }
- }
-
- /**
- * @brief Returns pointers to the given elements for an entity.
- *
- * @note
- * The registry retains ownership of the pointed-to elements.
- *
- * @tparam Type Types of elements to get.
- * @param entt A valid identifier.
- * @return Pointers to the elements owned by the entity.
- */
- template<typename... Type>
- [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
- if constexpr(sizeof...(Type) == 1u) {
- const auto *cpool = assure<std::remove_const_t<Type>...>();
- return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr;
- } else {
- return std::make_tuple(try_get<Type>(entt)...);
- }
- }
-
- /*! @copydoc try_get */
- template<typename... Type>
- [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
- if constexpr(sizeof...(Type) == 1u) {
- return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
- } else {
- return std::make_tuple(try_get<Type>(entt)...);
- }
- }
-
- /**
- * @brief Clears a whole registry or the pools for the given elements.
- * @tparam Type Types of elements to remove from their entities.
- */
- template<typename... Type>
- void clear() {
- if constexpr(sizeof...(Type) == 0u) {
- for(size_type pos = pools.size(); pos; --pos) {
- pools.begin()[pos - 1u].second->clear();
- }
-
- const auto elem = entities.each();
- entities.erase(elem.begin().base(), elem.end().base());
- } else {
- (assure<Type>().clear(), ...);
- }
- }
-
- /**
- * @brief Checks if an entity has elements assigned.
- * @param entt A valid identifier.
- * @return True if the entity has no elements assigned, false otherwise.
- */
- [[nodiscard]] bool orphan(const entity_type entt) const {
- return std::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
- }
-
- /**
- * @brief Returns a sink object for the given element.
- *
- * Use this function to receive notifications whenever a new instance of the
- * given element is created and assigned to an entity.<br/>
- * The function type for a listener is equivalent to:
- *
- * @code{.cpp}
- * void(basic_registry<Entity> &, Entity);
- * @endcode
- *
- * Listeners are invoked **after** assigning the element to the entity.
- *
- * @sa sink
- *
- * @tparam Type Type of element of which to get the sink.
- * @param id Optional name used to map the storage within the registry.
- * @return A temporary sink object.
- */
- template<typename Type>
- [[nodiscard]] auto on_construct(const id_type id = type_hash<Type>::value()) {
- return assure<Type>(id).on_construct();
- }
-
- /**
- * @brief Returns a sink object for the given element.
- *
- * Use this function to receive notifications whenever an instance of the
- * given element is explicitly updated.<br/>
- * The function type for a listener is equivalent to:
- *
- * @code{.cpp}
- * void(basic_registry<Entity> &, Entity);
- * @endcode
- *
- * Listeners are invoked **after** updating the element.
- *
- * @sa sink
- *
- * @tparam Type Type of element of which to get the sink.
- * @param id Optional name used to map the storage within the registry.
- * @return A temporary sink object.
- */
- template<typename Type>
- [[nodiscard]] auto on_update(const id_type id = type_hash<Type>::value()) {
- return assure<Type>(id).on_update();
- }
-
- /**
- * @brief Returns a sink object for the given element.
- *
- * Use this function to receive notifications whenever an instance of the
- * given element is removed from an entity and thus destroyed.<br/>
- * The function type for a listener is equivalent to:
- *
- * @code{.cpp}
- * void(basic_registry<Entity> &, Entity);
- * @endcode
- *
- * Listeners are invoked **before** removing the element from the entity.
- *
- * @sa sink
- *
- * @tparam Type Type of element of which to get the sink.
- * @param id Optional name used to map the storage within the registry.
- * @return A temporary sink object.
- */
- template<typename Type>
- [[nodiscard]] auto on_destroy(const id_type id = type_hash<Type>::value()) {
- return assure<Type>(id).on_destroy();
- }
-
- /**
- * @brief Returns a view for the given elements.
- * @tparam Type Type of element used to construct the view.
- * @tparam Other Other types of elements used to construct the view.
- * @tparam Exclude Types of elements used to filter the view.
- * @return A newly created view.
- */
- template<typename Type, typename... Other, typename... Exclude>
- [[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
- view(exclude_t<Exclude...> = exclude_t{}) const {
- const auto cpools = std::make_tuple(assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...);
- basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>> elem{};
- std::apply([&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }, cpools);
- return elem;
- }
-
- /*! @copydoc view */
- template<typename Type, typename... Other, typename... Exclude>
- [[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
- view(exclude_t<Exclude...> = exclude_t{}) {
- return {assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...};
- }
-
- /**
- * @brief Returns a group for the given elements.
- * @tparam Owned Types of storage _owned_ by the group.
- * @tparam Get Types of storage _observed_ by the group, if any.
- * @tparam Exclude Types of storage used to filter the group, if any.
- * @return A newly created group.
- */
- template<typename... Owned, typename... Get, typename... Exclude>
- basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
- group(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) {
- using group_type = basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>;
- using handler_type = typename group_type::handler;
-
- if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
- return {*std::static_pointer_cast<handler_type>(it->second)};
- }
-
- std::shared_ptr<handler_type> handler{};
-
- if constexpr(sizeof...(Owned) == 0u) {
- handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
- } else {
- handler = std::allocate_shared<handler_type>(get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
- ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
- }
-
- groups.emplace(group_type::group_id(), handler);
- return {*handler};
- }
-
- /*! @copydoc group */
- template<typename... Owned, typename... Get, typename... Exclude>
- [[nodiscard]] basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
- group_if_exists(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) const {
- using group_type = basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>;
- using handler_type = typename group_type::handler;
-
- if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
- return {*std::static_pointer_cast<handler_type>(it->second)};
- }
-
- return {};
- }
-
- /**
- * @brief Checks whether the given elements belong to any group.
- * @tparam Type Types of elements in which one is interested.
- * @return True if the pools of the given elements are _free_, false
- * otherwise.
- */
- template<typename... Type>
- [[nodiscard]] bool owned() const {
- return std::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
- }
-
- /**
- * @brief Sorts the elements of a given element.
- *
- * The comparison function object returns `true` if the first element is
- * _less_ than the second one, `false` otherwise. Its signature is also
- * equivalent to one of the following:
- *
- * @code{.cpp}
- * bool(const Entity, const Entity);
- * bool(const Type &, const Type &);
- * @endcode
- *
- * Moreover, it shall induce a _strict weak ordering_ on the values.<br/>
- * The sort function object offers an `operator()` that accepts:
- *
- * * An iterator to the first element of the range to sort.
- * * An iterator past the last element of the range to sort.
- * * A comparison function object to use to compare the elements.
- *
- * The comparison function object hasn't necessarily the type of the one
- * passed along with the other parameters to this member function.
- *
- * @warning
- * Pools of elements owned by a group cannot be sorted.
- *
- * @tparam Type Type of elements to sort.
- * @tparam Compare Type of comparison function object.
- * @tparam Sort Type of sort function object.
- * @tparam Args Types of arguments to forward to the sort function object.
- * @param compare A valid comparison function object.
- * @param algo A valid sort function object.
- * @param args Arguments to forward to the sort function object, if any.
- */
- template<typename Type, typename Compare, typename Sort = std_sort, typename... Args>
- void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
- ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
- auto &cpool = assure<Type>();
-
- if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
- auto comp = [&cpool, compare = std::move(compare)](const auto lhs, const auto rhs) { return compare(std::as_const(cpool.get(lhs)), std::as_const(cpool.get(rhs))); };
- cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
- } else {
- cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
- }
- }
-
- /**
- * @brief Sorts two pools of elements in the same way.
- *
- * Entities and elements in `To` which are part of both storage are sorted
- * internally with the order they have in `From`. The others follow in no
- * particular order.
- *
- * @warning
- * Pools of elements owned by a group cannot be sorted.
- *
- * @tparam To Type of elements to sort.
- * @tparam From Type of elements to use to sort.
- */
- template<typename To, typename From>
- void sort() {
- ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
- const base_type &cpool = assure<From>();
- assure<To>().sort_as(cpool.begin(), cpool.end());
- }
-
- /**
- * @brief Returns the context object, that is, a general purpose container.
- * @return The context object, that is, a general purpose container.
- */
- [[nodiscard]] context &ctx() noexcept {
- return vars;
- }
-
- /*! @copydoc ctx */
- [[nodiscard]] const context &ctx() const noexcept {
- return vars;
- }
-
-private:
- context vars;
- pool_container_type pools;
- group_container_type groups;
- storage_for_type<entity_type> entities;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/runtime_view.hpp b/deps/include/entt/entity/runtime_view.hpp deleted file mode 100644 index b300160..0000000 --- a/deps/include/entt/entity/runtime_view.hpp +++ /dev/null @@ -1,318 +0,0 @@ -#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
-#define ENTT_ENTITY_RUNTIME_VIEW_HPP
-
-#include <algorithm>
-#include <cstddef>
-#include <iterator>
-#include <utility>
-#include <vector>
-#include "entity.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename Set>
-class runtime_view_iterator final {
- using iterator_type = typename Set::iterator;
- using iterator_traits = std::iterator_traits<iterator_type>;
-
- [[nodiscard]] bool valid() const {
- return (!tombstone_check || *it != tombstone)
- && std::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
- && std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
- }
-
-public:
- using value_type = typename iterator_traits::value_type;
- using pointer = typename iterator_traits::pointer;
- using reference = typename iterator_traits::reference;
- using difference_type = typename iterator_traits::difference_type;
- using iterator_category = std::bidirectional_iterator_tag;
-
- constexpr runtime_view_iterator() noexcept
- : pools{},
- filter{},
- it{},
- tombstone_check{} {}
-
- // NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
- runtime_view_iterator(const std::vector<Set *> &cpools, const std::vector<Set *> &ignore, iterator_type curr) noexcept
- : pools{&cpools},
- filter{&ignore},
- it{curr},
- tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} {
- if(it != (*pools)[0]->end() && !valid()) {
- ++(*this);
- }
- }
-
- runtime_view_iterator &operator++() {
- ++it;
- for(const auto last = (*pools)[0]->end(); it != last && !valid(); ++it) {}
- return *this;
- }
-
- runtime_view_iterator operator++(int) {
- runtime_view_iterator orig = *this;
- return ++(*this), orig;
- }
-
- runtime_view_iterator &operator--() {
- --it;
- for(const auto first = (*pools)[0]->begin(); it != first && !valid(); --it) {}
- return *this;
- }
-
- runtime_view_iterator operator--(int) {
- runtime_view_iterator orig = *this;
- return operator--(), orig;
- }
-
- [[nodiscard]] pointer operator->() const noexcept {
- return it.operator->();
- }
-
- [[nodiscard]] reference operator*() const noexcept {
- return *operator->();
- }
-
- [[nodiscard]] constexpr bool operator==(const runtime_view_iterator &other) const noexcept {
- return it == other.it;
- }
-
- [[nodiscard]] constexpr bool operator!=(const runtime_view_iterator &other) const noexcept {
- return !(*this == other);
- }
-
-private:
- const std::vector<Set *> *pools;
- const std::vector<Set *> *filter;
- iterator_type it;
- bool tombstone_check;
-};
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Generic runtime view.
- *
- * Runtime views iterate over those entities that are at least in the given
- * storage. During initialization, a runtime view looks at the number of
- * entities available for each element and uses the smallest set in order to get
- * a performance boost when iterating.
- *
- * @b Important
- *
- * Iterators aren't invalidated if:
- *
- * * New elements are added to the storage.
- * * The entity currently pointed is modified (for example, elements are added
- * or removed from it).
- * * The entity currently pointed is destroyed.
- *
- * In all other cases, modifying the storage iterated by the view in any way
- * invalidates all the iterators.
- *
- * @tparam Type Common base type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Type, typename Allocator>
-class basic_runtime_view {
- using alloc_traits = std::allocator_traits<Allocator>;
- static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
- using container_type = std::vector<Type *, Allocator>;
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = Allocator;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename Type::entity_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Common type among all storage types. */
- using common_type = Type;
- /*! @brief Bidirectional iterator type. */
- using iterator = internal::runtime_view_iterator<common_type>;
-
- /*! @brief Default constructor to use to create empty, invalid views. */
- basic_runtime_view() noexcept
- : basic_runtime_view{allocator_type{}} {}
-
- /**
- * @brief Constructs an empty, invalid view with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_runtime_view(const allocator_type &allocator)
- : pools{allocator},
- filter{allocator} {}
-
- /*! @brief Default copy constructor. */
- basic_runtime_view(const basic_runtime_view &) = default;
-
- /**
- * @brief Allocator-extended copy constructor.
- * @param other The instance to copy from.
- * @param allocator The allocator to use.
- */
- basic_runtime_view(const basic_runtime_view &other, const allocator_type &allocator)
- : pools{other.pools, allocator},
- filter{other.filter, allocator} {}
-
- /*! @brief Default move constructor. */
- basic_runtime_view(basic_runtime_view &&) noexcept(std::is_nothrow_move_constructible_v<container_type>) = default;
-
- /**
- * @brief Allocator-extended move constructor.
- * @param other The instance to move from.
- * @param allocator The allocator to use.
- */
- basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator)
- : pools{std::move(other.pools), allocator},
- filter{std::move(other.filter), allocator} {}
-
- /*! @brief Default destructor. */
- ~basic_runtime_view() noexcept = default;
-
- /**
- * @brief Default copy assignment operator.
- * @return This runtime view.
- */
- basic_runtime_view &operator=(const basic_runtime_view &) = default;
-
- /**
- * @brief Default move assignment operator.
- * @return This runtime view.
- */
- basic_runtime_view &operator=(basic_runtime_view &&) noexcept(std::is_nothrow_move_assignable_v<container_type>) = default;
-
- /**
- * @brief Exchanges the contents with those of a given view.
- * @param other View to exchange the content with.
- */
- void swap(basic_runtime_view &other) {
- using std::swap;
- swap(pools, other.pools);
- swap(filter, other.filter);
- }
-
- /**
- * @brief Returns the associated allocator.
- * @return The associated allocator.
- */
- [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
- return pools.get_allocator();
- }
-
- /*! @brief Clears the view. */
- void clear() {
- pools.clear();
- filter.clear();
- }
-
- /**
- * @brief Appends an opaque storage object to a runtime view.
- * @param base An opaque reference to a storage object.
- * @return This runtime view.
- */
- basic_runtime_view &iterate(common_type &base) {
- if(pools.empty() || !(base.size() < pools[0u]->size())) {
- pools.push_back(&base);
- } else {
- pools.push_back(std::exchange(pools[0u], &base));
- }
-
- return *this;
- }
-
- /**
- * @brief Adds an opaque storage object as a filter of a runtime view.
- * @param base An opaque reference to a storage object.
- * @return This runtime view.
- */
- basic_runtime_view &exclude(common_type &base) {
- filter.push_back(&base);
- return *this;
- }
-
- /**
- * @brief Estimates the number of entities iterated by the view.
- * @return Estimated number of entities iterated by the view.
- */
- [[nodiscard]] size_type size_hint() const {
- return pools.empty() ? size_type{} : pools.front()->size();
- }
-
- /**
- * @brief Returns an iterator to the first entity that has the given
- * elements.
- *
- * If the view is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first entity that has the given elements.
- */
- [[nodiscard]] iterator begin() const {
- return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()};
- }
-
- /**
- * @brief Returns an iterator that is past the last entity that has the
- * given elements.
- * @return An iterator to the entity following the last entity that has the
- * given elements.
- */
- [[nodiscard]] iterator end() const {
- return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()};
- }
-
- /**
- * @brief Checks whether a view is initialized or not.
- * @return True if the view is initialized, false otherwise.
- */
- [[nodiscard]] explicit operator bool() const noexcept {
- return !(pools.empty() && filter.empty());
- }
-
- /**
- * @brief Checks if a view contains an entity.
- * @param entt A valid identifier.
- * @return True if the view contains the given entity, false otherwise.
- */
- [[nodiscard]] bool contains(const entity_type entt) const {
- return !pools.empty()
- && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
- && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
- }
-
- /**
- * @brief Iterates entities and applies the given function object to them.
- *
- * The function object is invoked for each entity. It is provided only with
- * the entity itself.<br/>
- * The signature of the function should be equivalent to the following:
- *
- * @code{.cpp}
- * void(const entity_type);
- * @endcode
- *
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template<typename Func>
- void each(Func func) const {
- for(const auto entity: *this) {
- func(entity);
- }
- }
-
-private:
- container_type pools;
- container_type filter;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/snapshot.hpp b/deps/include/entt/entity/snapshot.hpp deleted file mode 100644 index 46ebd28..0000000 --- a/deps/include/entt/entity/snapshot.hpp +++ /dev/null @@ -1,509 +0,0 @@ -#ifndef ENTT_ENTITY_SNAPSHOT_HPP
-#define ENTT_ENTITY_SNAPSHOT_HPP
-
-#include <cstddef>
-#include <iterator>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include <vector>
-#include "../config/config.h"
-#include "../container/dense_map.hpp"
-#include "../core/type_traits.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-#include "view.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename Registry>
-void orphans(Registry ®istry) {
- auto &storage = registry.template storage<typename Registry::entity_type>();
-
- for(auto entt: storage) {
- if(registry.orphan(entt)) {
- storage.erase(entt);
- }
- }
-}
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Utility class to create snapshots from a registry.
- *
- * A _snapshot_ can be either a dump of the entire registry or a narrower
- * selection of elements of interest.<br/>
- * This type can be used in both cases if provided with a correctly configured
- * output archive.
- *
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-class basic_snapshot {
- static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
- using traits_type = entt_traits<typename Registry::entity_type>;
-
-public:
- /*! Basic registry type. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
-
- /**
- * @brief Constructs an instance that is bound to a given registry.
- * @param source A valid reference to a registry.
- */
- basic_snapshot(const registry_type &source) noexcept
- : reg{&source} {}
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_snapshot(const basic_snapshot &) = delete;
-
- /*! @brief Default move constructor. */
- basic_snapshot(basic_snapshot &&) noexcept = default;
-
- /*! @brief Default destructor. */
- ~basic_snapshot() noexcept = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This snapshot.
- */
- basic_snapshot &operator=(const basic_snapshot &) = delete;
-
- /**
- * @brief Default move assignment operator.
- * @return This snapshot.
- */
- basic_snapshot &operator=(basic_snapshot &&) noexcept = default;
-
- /**
- * @brief Serializes all elements of a type with associated identifiers.
- * @tparam Type Type of elements to serialize.
- * @tparam Archive Type of output archive.
- * @param archive A valid reference to an output archive.
- * @param id Optional name used to map the storage within the registry.
- * @return An object of this type to continue creating the snapshot.
- */
- template<typename Type, typename Archive>
- const basic_snapshot &get(Archive &archive, const id_type id = type_hash<Type>::value()) const {
- if(const auto *storage = reg->template storage<Type>(id); storage) {
- const typename registry_type::common_type &base = *storage;
-
- archive(static_cast<typename traits_type::entity_type>(storage->size()));
-
- if constexpr(std::is_same_v<Type, entity_type>) {
- archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
-
- for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) {
- archive(*first);
- }
- } else if constexpr(registry_type::template storage_for_type<Type>::storage_policy == deletion_policy::in_place) {
- for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) {
- if(const auto entt = *it; entt == tombstone) {
- archive(static_cast<entity_type>(null));
- } else {
- archive(entt);
- std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
- }
- }
- } else {
- for(auto elem: storage->reach()) {
- std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
- }
- }
- } else {
- archive(typename traits_type::entity_type{});
- }
-
- return *this;
- }
-
- /**
- * @brief Serializes all elements of a type with associated identifiers for
- * the entities in a range.
- * @tparam Type Type of elements to serialize.
- * @tparam Archive Type of output archive.
- * @tparam It Type of input iterator.
- * @param archive A valid reference to an output archive.
- * @param first An iterator to the first element of the range to serialize.
- * @param last An iterator past the last element of the range to serialize.
- * @param id Optional name used to map the storage within the registry.
- * @return An object of this type to continue creating the snapshot.
- */
- template<typename Type, typename Archive, typename It>
- const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
- static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
-
- if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
- archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
-
- for(; first != last; ++first) {
- if(const auto entt = *first; storage->contains(entt)) {
- archive(entt);
- std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
- } else {
- archive(static_cast<entity_type>(null));
- }
- }
- } else {
- archive(typename traits_type::entity_type{});
- }
-
- return *this;
- }
-
-private:
- const registry_type *reg;
-};
-
-/**
- * @brief Utility class to restore a snapshot as a whole.
- *
- * A snapshot loader requires that the destination registry be empty and loads
- * all the data at once while keeping intact the identifiers that the entities
- * originally had.<br/>
- * An example of use is the implementation of a save/restore utility.
- *
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-class basic_snapshot_loader {
- static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
- using traits_type = entt_traits<typename Registry::entity_type>;
-
-public:
- /*! Basic registry type. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
-
- /**
- * @brief Constructs an instance that is bound to a given registry.
- * @param source A valid reference to a registry.
- */
- basic_snapshot_loader(registry_type &source) noexcept
- : reg{&source} {
- // restoring a snapshot as a whole requires a clean registry
- ENTT_ASSERT(reg->template storage<entity_type>().free_list() == 0u, "Registry must be empty");
- }
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_snapshot_loader(const basic_snapshot_loader &) = delete;
-
- /*! @brief Default move constructor. */
- basic_snapshot_loader(basic_snapshot_loader &&) noexcept = default;
-
- /*! @brief Default destructor. */
- ~basic_snapshot_loader() noexcept = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This loader.
- */
- basic_snapshot_loader &operator=(const basic_snapshot_loader &) = delete;
-
- /**
- * @brief Default move assignment operator.
- * @return This loader.
- */
- basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default;
-
- /**
- * @brief Restores all elements of a type with associated identifiers.
- * @tparam Type Type of elements to restore.
- * @tparam Archive Type of input archive.
- * @param archive A valid reference to an input archive.
- * @param id Optional name used to map the storage within the registry.
- * @return A valid loader to continue restoring data.
- */
- template<typename Type, typename Archive>
- basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
- auto &storage = reg->template storage<Type>(id);
- typename traits_type::entity_type length{};
-
- archive(length);
-
- if constexpr(std::is_same_v<Type, entity_type>) {
- typename traits_type::entity_type count{};
-
- storage.reserve(length);
- archive(count);
-
- for(entity_type entity = null; length; --length) {
- archive(entity);
- storage.emplace(entity);
- }
-
- storage.free_list(count);
- } else {
- auto &other = reg->template storage<entity_type>();
- entity_type entt{null};
-
- while(length--) {
- if(archive(entt); entt != null) {
- const auto entity = other.contains(entt) ? entt : other.emplace(entt);
- ENTT_ASSERT(entity == entt, "Entity not available for use");
-
- if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
- storage.emplace(entity);
- } else {
- Type elem{};
- archive(elem);
- storage.emplace(entity, std::move(elem));
- }
- }
- }
- }
-
- return *this;
- }
-
- /**
- * @brief Destroys those entities that have no elements.
- *
- * In case all the entities were serialized but only part of the elements
- * was saved, it could happen that some of the entities have no elements
- * once restored.<br/>
- * This function helps to identify and destroy those entities.
- *
- * @return A valid loader to continue restoring data.
- */
- basic_snapshot_loader &orphans() {
- internal::orphans(*reg);
- return *this;
- }
-
-private:
- registry_type *reg;
-};
-
-/**
- * @brief Utility class for _continuous loading_.
- *
- * A _continuous loader_ is designed to load data from a source registry to a
- * (possibly) non-empty destination. The loader can accommodate in a registry
- * more than one snapshot in a sort of _continuous loading_ that updates the
- * destination one step at a time.<br/>
- * Identifiers that entities originally had are not transferred to the target.
- * Instead, the loader maps remote identifiers to local ones while restoring a
- * snapshot.<br/>
- * An example of use is the implementation of a client-server application with
- * the requirement of transferring somehow parts of the representation side to
- * side.
- *
- * @tparam Registry Basic registry type.
- */
-template<typename Registry>
-class basic_continuous_loader {
- static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
- using traits_type = entt_traits<typename Registry::entity_type>;
-
- void restore(typename Registry::entity_type entt) {
- if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
- if(!reg->valid(remloc[entity].second)) {
- remloc[entity].second = reg->create();
- }
- } else {
- remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
- }
- }
-
- template<typename Container>
- auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
- // map like container
- Container other;
-
- for(auto &&pair: container) {
- using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
- using second_type = typename std::decay_t<decltype(pair)>::second_type;
-
- if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
- other.emplace(map(pair.first), map(pair.second));
- } else if constexpr(std::is_same_v<first_type, entity_type>) {
- other.emplace(map(pair.first), std::move(pair.second));
- } else {
- static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
- other.emplace(std::move(pair.first), map(pair.second));
- }
- }
-
- using std::swap;
- swap(container, other);
- }
-
- template<typename Container>
- auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
- // vector like container
- static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
-
- for(auto &&entt: container) {
- entt = map(entt);
- }
- }
-
- template<typename Component, typename Other, typename Member>
- void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
- if constexpr(!std::is_same_v<Component, Other>) {
- return;
- } else if constexpr(std::is_same_v<Member, entity_type>) {
- instance.*member = map(instance.*member);
- } else {
- // maybe a container? let's try...
- update(0, instance.*member);
- }
- }
-
-public:
- /*! Basic registry type. */
- using registry_type = Registry;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename registry_type::entity_type;
-
- /**
- * @brief Constructs an instance that is bound to a given registry.
- * @param source A valid reference to a registry.
- */
- basic_continuous_loader(registry_type &source) noexcept
- : remloc{source.get_allocator()},
- reg{&source} {}
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_continuous_loader(const basic_continuous_loader &) = delete;
-
- /*! @brief Default move constructor. */
- basic_continuous_loader(basic_continuous_loader &&) noexcept = default;
-
- /*! @brief Default destructor. */
- ~basic_continuous_loader() noexcept = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This loader.
- */
- basic_continuous_loader &operator=(const basic_continuous_loader &) = delete;
-
- /**
- * @brief Default move assignment operator.
- * @return This loader.
- */
- basic_continuous_loader &operator=(basic_continuous_loader &&) noexcept = default;
-
- /**
- * @brief Restores all elements of a type with associated identifiers.
- *
- * It creates local counterparts for remote elements as needed.<br/>
- * Members are either data members of type entity_type or containers of
- * entities. In both cases, a loader visits them and replaces entities with
- * their local counterpart.
- *
- * @tparam Type Type of elements to restore.
- * @tparam Archive Type of input archive.
- * @param archive A valid reference to an input archive.
- * @param id Optional name used to map the storage within the registry.
- * @return A valid loader to continue restoring data.
- */
- template<typename Type, typename Archive>
- basic_continuous_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
- auto &storage = reg->template storage<Type>(id);
- typename traits_type::entity_type length{};
- entity_type entt{null};
-
- archive(length);
-
- if constexpr(std::is_same_v<Type, entity_type>) {
- typename traits_type::entity_type in_use{};
-
- storage.reserve(length);
- archive(in_use);
-
- for(std::size_t pos{}; pos < in_use; ++pos) {
- archive(entt);
- restore(entt);
- }
-
- for(std::size_t pos = in_use; pos < length; ++pos) {
- archive(entt);
-
- if(const auto entity = to_entity(entt); remloc.contains(entity)) {
- if(reg->valid(remloc[entity].second)) {
- reg->destroy(remloc[entity].second);
- }
-
- remloc.erase(entity);
- }
- }
- } else {
- for(auto &&ref: remloc) {
- storage.remove(ref.second.second);
- }
-
- while(length--) {
- if(archive(entt); entt != null) {
- restore(entt);
-
- if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
- storage.emplace(map(entt));
- } else {
- Type elem{};
- archive(elem);
- storage.emplace(map(entt), std::move(elem));
- }
- }
- }
- }
-
- return *this;
- }
-
- /**
- * @brief Destroys those entities that have no elements.
- *
- * In case all the entities were serialized but only part of the elements
- * was saved, it could happen that some of the entities have no elements
- * once restored.<br/>
- * This function helps to identify and destroy those entities.
- *
- * @return A non-const reference to this loader.
- */
- basic_continuous_loader &orphans() {
- internal::orphans(*reg);
- return *this;
- }
-
- /**
- * @brief Tests if a loader knows about a given entity.
- * @param entt A valid identifier.
- * @return True if `entity` is managed by the loader, false otherwise.
- */
- [[nodiscard]] bool contains(entity_type entt) const noexcept {
- const auto it = remloc.find(to_entity(entt));
- return it != remloc.cend() && it->second.first == entt;
- }
-
- /**
- * @brief Returns the identifier to which an entity refers.
- * @param entt A valid identifier.
- * @return The local identifier if any, the null entity otherwise.
- */
- [[nodiscard]] entity_type map(entity_type entt) const noexcept {
- if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) {
- return it->second.second;
- }
-
- return null;
- }
-
-private:
- dense_map<typename traits_type::entity_type, std::pair<entity_type, entity_type>> remloc;
- registry_type *reg;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/sparse_set.hpp b/deps/include/entt/entity/sparse_set.hpp deleted file mode 100644 index bea16ae..0000000 --- a/deps/include/entt/entity/sparse_set.hpp +++ /dev/null @@ -1,1068 +0,0 @@ -#ifndef ENTT_ENTITY_SPARSE_SET_HPP
-#define ENTT_ENTITY_SPARSE_SET_HPP
-
-#include <cstddef>
-#include <iterator>
-#include <memory>
-#include <type_traits>
-#include <utility>
-#include <vector>
-#include "../config/config.h"
-#include "../core/algorithm.hpp"
-#include "../core/any.hpp"
-#include "../core/bit.hpp"
-#include "../core/type_info.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename Container>
-struct sparse_set_iterator final {
- using value_type = typename Container::value_type;
- using pointer = typename Container::const_pointer;
- using reference = typename Container::const_reference;
- using difference_type = typename Container::difference_type;
- using iterator_category = std::random_access_iterator_tag;
-
- constexpr sparse_set_iterator() noexcept
- : packed{},
- offset{} {}
-
- constexpr sparse_set_iterator(const Container &ref, const difference_type idx) noexcept
- : packed{&ref},
- offset{idx} {}
-
- constexpr sparse_set_iterator &operator++() noexcept {
- return --offset, *this;
- }
-
- constexpr sparse_set_iterator operator++(int) noexcept {
- sparse_set_iterator orig = *this;
- return ++(*this), orig;
- }
-
- constexpr sparse_set_iterator &operator--() noexcept {
- return ++offset, *this;
- }
-
- constexpr sparse_set_iterator operator--(int) noexcept {
- sparse_set_iterator orig = *this;
- return operator--(), orig;
- }
-
- constexpr sparse_set_iterator &operator+=(const difference_type value) noexcept {
- offset -= value;
- return *this;
- }
-
- constexpr sparse_set_iterator operator+(const difference_type value) const noexcept {
- sparse_set_iterator copy = *this;
- return (copy += value);
- }
-
- constexpr sparse_set_iterator &operator-=(const difference_type value) noexcept {
- return (*this += -value);
- }
-
- constexpr sparse_set_iterator operator-(const difference_type value) const noexcept {
- return (*this + -value);
- }
-
- [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
- return (*packed)[index() - value];
- }
-
- [[nodiscard]] constexpr pointer operator->() const noexcept {
- return std::addressof(operator[](0));
- }
-
- [[nodiscard]] constexpr reference operator*() const noexcept {
- return operator[](0);
- }
-
- [[nodiscard]] constexpr pointer data() const noexcept {
- return packed ? packed->data() : nullptr;
- }
-
- [[nodiscard]] constexpr difference_type index() const noexcept {
- return offset - 1;
- }
-
-private:
- const Container *packed;
- difference_type offset;
-};
-
-template<typename Container>
-[[nodiscard]] constexpr std::ptrdiff_t operator-(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
- return rhs.index() - lhs.index();
-}
-
-template<typename Container>
-[[nodiscard]] constexpr bool operator==(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
- return lhs.index() == rhs.index();
-}
-
-template<typename Container>
-[[nodiscard]] constexpr bool operator!=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-template<typename Container>
-[[nodiscard]] constexpr bool operator<(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
- return lhs.index() > rhs.index();
-}
-
-template<typename Container>
-[[nodiscard]] constexpr bool operator>(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
- return rhs < lhs;
-}
-
-template<typename Container>
-[[nodiscard]] constexpr bool operator<=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
- return !(lhs > rhs);
-}
-
-template<typename Container>
-[[nodiscard]] constexpr bool operator>=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
- return !(lhs < rhs);
-}
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Sparse set implementation.
- *
- * Sparse set or packed array or whatever is the name users give it.<br/>
- * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a
- * _packed_ one; one used for direct access through contiguous memory, the other
- * one used to get the data through an extra level of indirection.<br/>
- * This type of data structure is widely documented in the literature and on the
- * web. This is nothing more than a customized implementation suitable for the
- * purpose of the framework.
- *
- * @note
- * Internal data structures arrange elements to maximize performance. There are
- * no guarantees that entities are returned in the insertion order when iterate
- * a sparse set. Do not make assumption on the order in any case.
- *
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Entity, typename Allocator>
-class basic_sparse_set {
- using alloc_traits = std::allocator_traits<Allocator>;
- static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
- using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
- using packed_container_type = std::vector<Entity, Allocator>;
- using traits_type = entt_traits<Entity>;
-
- static constexpr auto max_size = static_cast<std::size_t>(traits_type::to_entity(null));
-
- [[nodiscard]] auto policy_to_head() const noexcept {
- return static_cast<size_type>(max_size * (mode != deletion_policy::swap_only));
- }
-
- [[nodiscard]] auto sparse_ptr(const Entity entt) const {
- const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
- const auto page = pos / traits_type::page_size;
- return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, traits_type::page_size)) : nullptr;
- }
-
- [[nodiscard]] auto &sparse_ref(const Entity entt) const {
- ENTT_ASSERT(sparse_ptr(entt), "Invalid element");
- const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
- return sparse[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
- }
-
- [[nodiscard]] auto to_iterator(const Entity entt) const {
- return --(end() - index(entt));
- }
-
- [[nodiscard]] auto &assure_at_least(const Entity entt) {
- const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
- const auto page = pos / traits_type::page_size;
-
- if(!(page < sparse.size())) {
- sparse.resize(page + 1u, nullptr);
- }
-
- if(!sparse[page]) {
- constexpr entity_type init = null;
- auto page_allocator{packed.get_allocator()};
- sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size);
- std::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init);
- }
-
- return sparse[page][fast_mod(pos, traits_type::page_size)];
- }
-
- void release_sparse_pages() {
- auto page_allocator{packed.get_allocator()};
-
- for(auto &&page: sparse) {
- if(page != nullptr) {
- std::destroy(page, page + traits_type::page_size);
- alloc_traits::deallocate(page_allocator, page, traits_type::page_size);
- page = nullptr;
- }
- }
- }
-
- void swap_at(const std::size_t lhs, const std::size_t rhs) {
- auto &from = packed[lhs];
- auto &to = packed[rhs];
-
- sparse_ref(from) = traits_type::combine(static_cast<typename traits_type::entity_type>(rhs), traits_type::to_integral(from));
- sparse_ref(to) = traits_type::combine(static_cast<typename traits_type::entity_type>(lhs), traits_type::to_integral(to));
-
- std::swap(from, to);
- }
-
-private:
- [[nodiscard]] virtual const void *get_at(const std::size_t) const {
- return nullptr;
- }
-
- virtual void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {
- ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < head) == (rhs < head)), "Cross swapping is not supported");
- }
-
-protected:
- /*! @brief Random access iterator type. */
- using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
-
- /**
- * @brief Erases an entity from a sparse set.
- * @param it An iterator to the element to pop.
- */
- void swap_only(const basic_iterator it) {
- ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch");
- const auto pos = index(*it);
- bump(traits_type::next(*it));
- swap_at(pos, head -= (pos < head));
- }
-
- /**
- * @brief Erases an entity from a sparse set.
- * @param it An iterator to the element to pop.
- */
- void swap_and_pop(const basic_iterator it) {
- ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatch");
- auto &self = sparse_ref(*it);
- const auto entt = traits_type::to_entity(self);
- sparse_ref(packed.back()) = traits_type::combine(entt, traits_type::to_integral(packed.back()));
- packed[static_cast<size_type>(entt)] = packed.back();
- // unnecessary but it helps to detect nasty bugs
- ENTT_ASSERT((packed.back() = null, true), "");
- // lazy self-assignment guard
- self = null;
- packed.pop_back();
- }
-
- /**
- * @brief Erases an entity from a sparse set.
- * @param it An iterator to the element to pop.
- */
- void in_place_pop(const basic_iterator it) {
- ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch");
- const auto pos = static_cast<size_type>(traits_type::to_entity(std::exchange(sparse_ref(*it), null)));
- packed[pos] = traits_type::combine(static_cast<typename traits_type::entity_type>(std::exchange(head, pos)), tombstone);
- }
-
-protected:
- /**
- * @brief Erases entities from a sparse set.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- */
- virtual void pop(basic_iterator first, basic_iterator last) {
- switch(mode) {
- case deletion_policy::swap_and_pop:
- for(; first != last; ++first) {
- swap_and_pop(first);
- }
- break;
- case deletion_policy::in_place:
- for(; first != last; ++first) {
- in_place_pop(first);
- }
- break;
- case deletion_policy::swap_only:
- for(; first != last; ++first) {
- swap_only(first);
- }
- break;
- }
- }
-
- /*! @brief Erases all entities of a sparse set. */
- virtual void pop_all() {
- switch(mode) {
- case deletion_policy::in_place:
- if(head != max_size) {
- for(auto first = begin(); !(first.index() < 0); ++first) {
- if(*first != tombstone) {
- sparse_ref(*first) = null;
- }
- }
- break;
- }
- [[fallthrough]];
- case deletion_policy::swap_only:
- case deletion_policy::swap_and_pop:
- for(auto first = begin(); !(first.index() < 0); ++first) {
- sparse_ref(*first) = null;
- }
- break;
- }
-
- head = policy_to_head();
- packed.clear();
- }
-
- /**
- * @brief Assigns an entity to a sparse set.
- * @param entt A valid identifier.
- * @param force_back Force back insertion.
- * @return Iterator pointing to the emplaced element.
- */
- virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) {
- ENTT_ASSERT(entt != null && entt != tombstone, "Invalid element");
- auto &elem = assure_at_least(entt);
- auto pos = size();
-
- switch(mode) {
- case deletion_policy::in_place:
- if(head != max_size && !force_back) {
- pos = head;
- ENTT_ASSERT(elem == null, "Slot not available");
- elem = traits_type::combine(static_cast<typename traits_type::entity_type>(head), traits_type::to_integral(entt));
- head = static_cast<size_type>(traits_type::to_entity(std::exchange(packed[pos], entt)));
- break;
- }
- [[fallthrough]];
- case deletion_policy::swap_and_pop:
- packed.push_back(entt);
- ENTT_ASSERT(elem == null, "Slot not available");
- elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
- break;
- case deletion_policy::swap_only:
- if(elem == null) {
- packed.push_back(entt);
- elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
- } else {
- ENTT_ASSERT(!(static_cast<size_type>(traits_type::to_entity(elem)) < head), "Slot not available");
- bump(entt);
- }
-
- pos = head++;
- swap_at(static_cast<size_type>(traits_type::to_entity(elem)), pos);
- break;
- }
-
- return --(end() - static_cast<typename iterator::difference_type>(pos));
- }
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = Allocator;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename traits_type::value_type;
- /*! @brief Underlying version type. */
- using version_type = typename traits_type::version_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Pointer type to contained entities. */
- using pointer = typename packed_container_type::const_pointer;
- /*! @brief Random access iterator type. */
- using iterator = basic_iterator;
- /*! @brief Constant random access iterator type. */
- using const_iterator = iterator;
- /*! @brief Reverse iterator type. */
- using reverse_iterator = std::reverse_iterator<iterator>;
- /*! @brief Constant reverse iterator type. */
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
- /*! @brief Default constructor. */
- basic_sparse_set()
- : basic_sparse_set{type_id<void>()} {}
-
- /**
- * @brief Constructs an empty container with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_sparse_set(const allocator_type &allocator)
- : basic_sparse_set{deletion_policy::swap_and_pop, allocator} {}
-
- /**
- * @brief Constructs an empty container with the given policy and allocator.
- * @param pol Type of deletion policy.
- * @param allocator The allocator to use (possibly default-constructed).
- */
- explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {})
- : basic_sparse_set{type_id<void>(), pol, allocator} {}
-
- /**
- * @brief Constructs an empty container with the given value type, policy
- * and allocator.
- * @param elem Returned value type, if any.
- * @param pol Type of deletion policy.
- * @param allocator The allocator to use (possibly default-constructed).
- */
- explicit basic_sparse_set(const type_info &elem, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {})
- : sparse{allocator},
- packed{allocator},
- info{&elem},
- mode{pol},
- head{policy_to_head()} {
- ENTT_ASSERT(traits_type::version_mask || mode != deletion_policy::in_place, "Policy does not support zero-sized versions");
- }
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_sparse_set(const basic_sparse_set &) = delete;
-
- /**
- * @brief Move constructor.
- * @param other The instance to move from.
- */
- basic_sparse_set(basic_sparse_set &&other) noexcept
- : sparse{std::move(other.sparse)},
- packed{std::move(other.packed)},
- info{other.info},
- mode{other.mode},
- head{std::exchange(other.head, policy_to_head())} {}
-
- /**
- * @brief Allocator-extended move constructor.
- * @param other The instance to move from.
- * @param allocator The allocator to use.
- */
- basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator)
- : sparse{std::move(other.sparse), allocator},
- packed{std::move(other.packed), allocator},
- info{other.info},
- mode{other.mode},
- head{std::exchange(other.head, policy_to_head())} {
- ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed");
- }
-
- /*! @brief Default destructor. */
- virtual ~basic_sparse_set() noexcept {
- release_sparse_pages();
- }
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This sparse set.
- */
- basic_sparse_set &operator=(const basic_sparse_set &) = delete;
-
- /**
- * @brief Move assignment operator.
- * @param other The instance to move from.
- * @return This sparse set.
- */
- basic_sparse_set &operator=(basic_sparse_set &&other) noexcept {
- ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed");
-
- release_sparse_pages();
- sparse = std::move(other.sparse);
- packed = std::move(other.packed);
- info = other.info;
- mode = other.mode;
- head = std::exchange(other.head, policy_to_head());
- return *this;
- }
-
- /**
- * @brief Exchanges the contents with those of a given sparse set.
- * @param other Sparse set to exchange the content with.
- */
- void swap(basic_sparse_set &other) {
- using std::swap;
- swap(sparse, other.sparse);
- swap(packed, other.packed);
- swap(info, other.info);
- swap(mode, other.mode);
- swap(head, other.head);
- }
-
- /**
- * @brief Returns the associated allocator.
- * @return The associated allocator.
- */
- [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
- return packed.get_allocator();
- }
-
- /**
- * @brief Returns the deletion policy of a sparse set.
- * @return The deletion policy of the sparse set.
- */
- [[nodiscard]] deletion_policy policy() const noexcept {
- return mode;
- }
-
- /**
- * @brief Returns data on the free list whose meaning depends on the mode.
- * @return Free list information that is mode dependent.
- */
- [[nodiscard]] size_type free_list() const noexcept {
- return head;
- }
-
- /**
- * @brief Sets data on the free list whose meaning depends on the mode.
- * @param value Free list information that is mode dependent.
- */
- void free_list(const size_type value) noexcept {
- ENTT_ASSERT((mode == deletion_policy::swap_only) && !(value > packed.size()), "Invalid value");
- head = value;
- }
-
- /**
- * @brief Increases the capacity of a sparse set.
- *
- * If the new capacity is greater than the current capacity, new storage is
- * allocated, otherwise the method does nothing.
- *
- * @param cap Desired capacity.
- */
- virtual void reserve(const size_type cap) {
- packed.reserve(cap);
- }
-
- /**
- * @brief Returns the number of elements that a sparse set has currently
- * allocated space for.
- * @return Capacity of the sparse set.
- */
- [[nodiscard]] virtual size_type capacity() const noexcept {
- return packed.capacity();
- }
-
- /*! @brief Requests the removal of unused capacity. */
- virtual void shrink_to_fit() {
- packed.shrink_to_fit();
- }
-
- /**
- * @brief Returns the extent of a sparse set.
- *
- * The extent of a sparse set is also the size of the internal sparse array.
- * There is no guarantee that the internal packed array has the same size.
- * Usually the size of the internal sparse array is equal or greater than
- * the one of the internal packed array.
- *
- * @return Extent of the sparse set.
- */
- [[nodiscard]] size_type extent() const noexcept {
- return sparse.size() * traits_type::page_size;
- }
-
- /**
- * @brief Returns the number of elements in a sparse set.
- *
- * The number of elements is also the size of the internal packed array.
- * There is no guarantee that the internal sparse array has the same size.
- * Usually the size of the internal sparse array is equal or greater than
- * the one of the internal packed array.
- *
- * @return Number of elements.
- */
- [[nodiscard]] size_type size() const noexcept {
- return packed.size();
- }
-
- /**
- * @brief Checks whether a sparse set is empty.
- * @return True if the sparse set is empty, false otherwise.
- */
- [[nodiscard]] bool empty() const noexcept {
- return packed.empty();
- }
-
- /**
- * @brief Checks whether a sparse set is fully packed.
- * @return True if the sparse set is fully packed, false otherwise.
- */
- [[nodiscard]] bool contiguous() const noexcept {
- return (mode != deletion_policy::in_place) || (head == max_size);
- }
-
- /**
- * @brief Direct access to the internal packed array.
- * @return A pointer to the internal packed array.
- */
- [[nodiscard]] pointer data() const noexcept {
- return packed.data();
- }
-
- /**
- * @brief Returns an iterator to the beginning.
- *
- * If the sparse set is empty, the returned iterator will be equal to
- * `end()`.
- *
- * @return An iterator to the first entity of the sparse set.
- */
- [[nodiscard]] iterator begin() const noexcept {
- const auto pos = static_cast<typename iterator::difference_type>(packed.size());
- return iterator{packed, pos};
- }
-
- /*! @copydoc begin */
- [[nodiscard]] const_iterator cbegin() const noexcept {
- return begin();
- }
-
- /**
- * @brief Returns an iterator to the end.
- * @return An iterator to the element following the last entity of a sparse
- * set.
- */
- [[nodiscard]] iterator end() const noexcept {
- return iterator{packed, {}};
- }
-
- /*! @copydoc end */
- [[nodiscard]] const_iterator cend() const noexcept {
- return end();
- }
-
- /**
- * @brief Returns a reverse iterator to the beginning.
- *
- * If the sparse set is empty, the returned iterator will be equal to
- * `rend()`.
- *
- * @return An iterator to the first entity of the reversed internal packed
- * array.
- */
- [[nodiscard]] reverse_iterator rbegin() const noexcept {
- return std::make_reverse_iterator(end());
- }
-
- /*! @copydoc rbegin */
- [[nodiscard]] const_reverse_iterator crbegin() const noexcept {
- return rbegin();
- }
-
- /**
- * @brief Returns a reverse iterator to the end.
- * @return An iterator to the element following the last entity of the
- * reversed sparse set.
- */
- [[nodiscard]] reverse_iterator rend() const noexcept {
- return std::make_reverse_iterator(begin());
- }
-
- /*! @copydoc rend */
- [[nodiscard]] const_reverse_iterator crend() const noexcept {
- return rend();
- }
-
- /**
- * @brief Finds an entity.
- * @param entt A valid identifier.
- * @return An iterator to the given entity if it's found, past the end
- * iterator otherwise.
- */
- [[nodiscard]] const_iterator find(const entity_type entt) const noexcept {
- return contains(entt) ? to_iterator(entt) : end();
- }
-
- /**
- * @brief Checks if a sparse set contains an entity.
- * @param entt A valid identifier.
- * @return True if the sparse set contains the entity, false otherwise.
- */
- [[nodiscard]] bool contains(const entity_type entt) const noexcept {
- const auto elem = sparse_ptr(entt);
- constexpr auto cap = traits_type::entity_mask;
- constexpr auto mask = traits_type::to_integral(null) & ~cap;
- // testing versions permits to avoid accessing the packed array
- return elem && (((mask & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap);
- }
-
- /**
- * @brief Returns the contained version for an identifier.
- * @param entt A valid identifier.
- * @return The version for the given identifier if present, the tombstone
- * version otherwise.
- */
- [[nodiscard]] version_type current(const entity_type entt) const noexcept {
- const auto elem = sparse_ptr(entt);
- constexpr auto fallback = traits_type::to_version(tombstone);
- return elem ? traits_type::to_version(*elem) : fallback;
- }
-
- /**
- * @brief Returns the position of an entity in a sparse set.
- *
- * @warning
- * Attempting to get the position of an entity that doesn't belong to the
- * sparse set results in undefined behavior.
- *
- * @param entt A valid identifier.
- * @return The position of the entity in the sparse set.
- */
- [[nodiscard]] size_type index(const entity_type entt) const noexcept {
- ENTT_ASSERT(contains(entt), "Set does not contain entity");
- return static_cast<size_type>(traits_type::to_entity(sparse_ref(entt)));
- }
-
- /**
- * @brief Returns the entity at specified location.
- * @param pos The position for which to return the entity.
- * @return The entity at specified location.
- */
- [[nodiscard]] entity_type operator[](const size_type pos) const noexcept {
- ENTT_ASSERT(pos < packed.size(), "Index out of bounds");
- return packed[pos];
- }
-
- /**
- * @brief Returns the element assigned to an entity, if any.
- *
- * @warning
- * Attempting to use an entity that doesn't belong to the sparse set results
- * in undefined behavior.
- *
- * @param entt A valid identifier.
- * @return An opaque pointer to the element assigned to the entity, if any.
- */
- [[nodiscard]] const void *value(const entity_type entt) const noexcept {
- return get_at(index(entt));
- }
-
- /*! @copydoc value */
- [[nodiscard]] void *value(const entity_type entt) noexcept {
- return const_cast<void *>(std::as_const(*this).value(entt));
- }
-
- /**
- * @brief Assigns an entity to a sparse set.
- *
- * @warning
- * Attempting to assign an entity that already belongs to the sparse set
- * results in undefined behavior.
- *
- * @param entt A valid identifier.
- * @param elem Optional opaque element to forward to mixins, if any.
- * @return Iterator pointing to the emplaced element in case of success, the
- * `end()` iterator otherwise.
- */
- iterator push(const entity_type entt, const void *elem = nullptr) {
- return try_emplace(entt, false, elem);
- }
-
- /**
- * @brief Assigns one or more entities to a sparse set.
- *
- * @warning
- * Attempting to assign an entity that already belongs to the sparse set
- * results in undefined behavior.
- *
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @return Iterator pointing to the first element inserted in case of
- * success, the `end()` iterator otherwise.
- */
- template<typename It>
- iterator push(It first, It last) {
- auto curr = end();
-
- for(; first != last; ++first) {
- curr = try_emplace(*first, true);
- }
-
- return curr;
- }
-
- /**
- * @brief Bump the version number of an entity.
- *
- * @warning
- * Attempting to bump the version of an entity that doesn't belong to the
- * sparse set results in undefined behavior.
- *
- * @param entt A valid identifier.
- * @return The version of the given identifier.
- */
- version_type bump(const entity_type entt) {
- auto &elem = sparse_ref(entt);
- ENTT_ASSERT(entt != null && elem != tombstone, "Cannot set the required version");
- elem = traits_type::combine(traits_type::to_integral(elem), traits_type::to_integral(entt));
- packed[static_cast<size_type>(traits_type::to_entity(elem))] = entt;
- return traits_type::to_version(entt);
- }
-
- /**
- * @brief Erases an entity from a sparse set.
- *
- * @warning
- * Attempting to erase an entity that doesn't belong to the sparse set
- * results in undefined behavior.
- *
- * @param entt A valid identifier.
- */
- void erase(const entity_type entt) {
- const auto it = to_iterator(entt);
- pop(it, it + 1u);
- }
-
- /**
- * @brief Erases entities from a set.
- *
- * @sa erase
- *
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- */
- template<typename It>
- void erase(It first, It last) {
- if constexpr(std::is_same_v<It, basic_iterator>) {
- pop(first, last);
- } else {
- for(; first != last; ++first) {
- erase(*first);
- }
- }
- }
-
- /**
- * @brief Removes an entity from a sparse set if it exists.
- * @param entt A valid identifier.
- * @return True if the entity is actually removed, false otherwise.
- */
- bool remove(const entity_type entt) {
- return contains(entt) && (erase(entt), true);
- }
-
- /**
- * @brief Removes entities from a sparse set if they exist.
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @return The number of entities actually removed.
- */
- template<typename It>
- size_type remove(It first, It last) {
- size_type count{};
-
- if constexpr(std::is_same_v<It, basic_iterator>) {
- while(first != last) {
- while(first != last && !contains(*first)) {
- ++first;
- }
-
- const auto it = first;
-
- while(first != last && contains(*first)) {
- ++first;
- }
-
- count += std::distance(it, first);
- erase(it, first);
- }
- } else {
- for(; first != last; ++first) {
- count += remove(*first);
- }
- }
-
- return count;
- }
-
- /*! @brief Removes all tombstones from a sparse set. */
- void compact() {
- if(mode == deletion_policy::in_place) {
- size_type from = packed.size();
- size_type pos = std::exchange(head, max_size);
-
- for(; from && packed[from - 1u] == tombstone; --from) {}
-
- while(pos != max_size) {
- if(const auto to = std::exchange(pos, static_cast<size_type>(traits_type::to_entity(packed[pos]))); to < from) {
- --from;
- swap_or_move(from, to);
-
- packed[to] = packed[from];
- const auto elem = static_cast<typename traits_type::entity_type>(to);
- sparse_ref(packed[to]) = traits_type::combine(elem, traits_type::to_integral(packed[to]));
-
- for(; from && packed[from - 1u] == tombstone; --from) {}
- }
- }
-
- packed.erase(packed.begin() + from, packed.end());
- }
- }
-
- /**
- * @brief Swaps two entities in a sparse set.
- *
- * For what it's worth, this function affects both the internal sparse array
- * and the internal packed array. Users should not care of that anyway.
- *
- * @warning
- * Attempting to swap entities that don't belong to the sparse set results
- * in undefined behavior.
- *
- * @param lhs A valid identifier.
- * @param rhs A valid identifier.
- */
- void swap_elements(const entity_type lhs, const entity_type rhs) {
- const auto from = index(lhs);
- const auto to = index(rhs);
-
- // basic no-leak guarantee if swapping throws
- swap_or_move(from, to);
- swap_at(from, to);
- }
-
- /**
- * @brief Sort the first count elements according to the given comparison
- * function.
- *
- * The comparison function object must return `true` if the first element
- * is _less_ than the second one, `false` otherwise. The signature of the
- * comparison function should be equivalent to the following:
- *
- * @code{.cpp}
- * bool(const Entity, const Entity);
- * @endcode
- *
- * Moreover, the comparison function object shall induce a
- * _strict weak ordering_ on the values.
- *
- * The sort function object must offer a member function template
- * `operator()` that accepts three arguments:
- *
- * * An iterator to the first element of the range to sort.
- * * An iterator past the last element of the range to sort.
- * * A comparison function to use to compare the elements.
- *
- * @tparam Compare Type of comparison function object.
- * @tparam Sort Type of sort function object.
- * @tparam Args Types of arguments to forward to the sort function object.
- * @param length Number of elements to sort.
- * @param compare A valid comparison function object.
- * @param algo A valid sort function object.
- * @param args Arguments to forward to the sort function object, if any.
- */
- template<typename Compare, typename Sort = std_sort, typename... Args>
- void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) {
- ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
- ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
-
- algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...);
-
- for(size_type pos{}; pos < length; ++pos) {
- auto curr = pos;
- auto next = index(packed[curr]);
-
- while(curr != next) {
- const auto idx = index(packed[next]);
- const auto entt = packed[curr];
-
- swap_or_move(next, idx);
- const auto elem = static_cast<typename traits_type::entity_type>(curr);
- sparse_ref(entt) = traits_type::combine(elem, traits_type::to_integral(packed[curr]));
- curr = std::exchange(next, idx);
- }
- }
- }
-
- /**
- * @brief Sort all elements according to the given comparison function.
- *
- * @sa sort_n
- *
- * @tparam Compare Type of comparison function object.
- * @tparam Sort Type of sort function object.
- * @tparam Args Types of arguments to forward to the sort function object.
- * @param compare A valid comparison function object.
- * @param algo A valid sort function object.
- * @param args Arguments to forward to the sort function object, if any.
- */
- template<typename Compare, typename Sort = std_sort, typename... Args>
- void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
- const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size();
- sort_n(len, std::move(compare), std::move(algo), std::forward<Args>(args)...);
- }
-
- /**
- * @brief Sort entities according to their order in a range.
- *
- * Entities that are part of both the sparse set and the range are ordered
- * internally according to the order they have in the range.<br/>
- * All other entities goes to the end of the sparse set and there are no
- * guarantees on their order.
- *
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @return An iterator past the last of the elements actually shared.
- */
- template<typename It>
- iterator sort_as(It first, It last) {
- ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
- const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size();
- auto it = end() - static_cast<typename iterator::difference_type>(len);
-
- for(const auto other = end(); (it != other) && (first != last); ++first) {
- if(const auto curr = *first; contains(curr)) {
- if(const auto entt = *it; entt != curr) {
- // basic no-leak guarantee (with invalid state) if swapping throws
- swap_elements(entt, curr);
- }
-
- ++it;
- }
- }
-
- return it;
- }
-
- /*! @brief Clears a sparse set. */
- void clear() {
- pop_all();
- // sanity check to avoid subtle issues due to storage classes
- ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set");
- head = policy_to_head();
- packed.clear();
- }
-
- /**
- * @brief Returned value type, if any.
- * @return Returned value type, if any.
- */
- [[nodiscard]] const type_info &type() const noexcept {
- return *info;
- }
-
- /*! @brief Forwards variables to derived classes, if any. */
- // NOLINTNEXTLINE(performance-unnecessary-value-param)
- virtual void bind(any) noexcept {}
-
-private:
- sparse_container_type sparse;
- packed_container_type packed;
- const type_info *info;
- deletion_policy mode;
- size_type head;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/storage.hpp b/deps/include/entt/entity/storage.hpp deleted file mode 100644 index 06cb256..0000000 --- a/deps/include/entt/entity/storage.hpp +++ /dev/null @@ -1,1205 +0,0 @@ -#ifndef ENTT_ENTITY_STORAGE_HPP
-#define ENTT_ENTITY_STORAGE_HPP
-
-#include <cstddef>
-#include <iterator>
-#include <memory>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include <vector>
-#include "../config/config.h"
-#include "../core/bit.hpp"
-#include "../core/iterator.hpp"
-#include "../core/memory.hpp"
-#include "../core/type_info.hpp"
-#include "component.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-#include "sparse_set.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename Container>
-class storage_iterator final {
- friend storage_iterator<const Container>;
-
- using container_type = std::remove_const_t<Container>;
- using alloc_traits = std::allocator_traits<typename container_type::allocator_type>;
-
- using iterator_traits = std::iterator_traits<std::conditional_t<
- std::is_const_v<Container>,
- typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
- typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
-
-public:
- using value_type = typename iterator_traits::value_type;
- using pointer = typename iterator_traits::pointer;
- using reference = typename iterator_traits::reference;
- using difference_type = typename iterator_traits::difference_type;
- using iterator_category = std::random_access_iterator_tag;
-
- constexpr storage_iterator() noexcept = default;
-
- constexpr storage_iterator(Container *ref, const difference_type idx) noexcept
- : payload{ref},
- offset{idx} {}
-
- template<bool Const = std::is_const_v<Container>, typename = std::enable_if_t<Const>>
- constexpr storage_iterator(const storage_iterator<std::remove_const_t<Container>> &other) noexcept
- : storage_iterator{other.payload, other.offset} {}
-
- constexpr storage_iterator &operator++() noexcept {
- return --offset, *this;
- }
-
- constexpr storage_iterator operator++(int) noexcept {
- storage_iterator orig = *this;
- return ++(*this), orig;
- }
-
- constexpr storage_iterator &operator--() noexcept {
- return ++offset, *this;
- }
-
- constexpr storage_iterator operator--(int) noexcept {
- storage_iterator orig = *this;
- return operator--(), orig;
- }
-
- constexpr storage_iterator &operator+=(const difference_type value) noexcept {
- offset -= value;
- return *this;
- }
-
- constexpr storage_iterator operator+(const difference_type value) const noexcept {
- storage_iterator copy = *this;
- return (copy += value);
- }
-
- constexpr storage_iterator &operator-=(const difference_type value) noexcept {
- return (*this += -value);
- }
-
- constexpr storage_iterator operator-(const difference_type value) const noexcept {
- return (*this + -value);
- }
-
- [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
- const auto pos = index() - value;
- constexpr auto page_size = component_traits<value_type>::page_size;
- return (*payload)[pos / page_size][fast_mod(static_cast<std::size_t>(pos), page_size)];
- }
-
- [[nodiscard]] constexpr pointer operator->() const noexcept {
- return std::addressof(operator[](0));
- }
-
- [[nodiscard]] constexpr reference operator*() const noexcept {
- return operator[](0);
- }
-
- [[nodiscard]] constexpr difference_type index() const noexcept {
- return offset - 1;
- }
-
-private:
- Container *payload;
- difference_type offset;
-};
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
- return rhs.index() - lhs.index();
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator==(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
- return lhs.index() == rhs.index();
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator!=(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator<(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
- return lhs.index() > rhs.index();
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator>(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
- return rhs < lhs;
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator<=(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
- return !(lhs > rhs);
-}
-
-template<typename Lhs, typename Rhs>
-[[nodiscard]] constexpr bool operator>=(const storage_iterator<Lhs> &lhs, const storage_iterator<Rhs> &rhs) noexcept {
- return !(lhs < rhs);
-}
-
-template<typename It, typename... Other>
-class extended_storage_iterator final {
- template<typename Iter, typename... Args>
- friend class extended_storage_iterator;
-
-public:
- using iterator_type = It;
- using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::forward_as_tuple(*std::declval<Other>()...)));
- using pointer = input_iterator_pointer<value_type>;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category = std::input_iterator_tag;
- using iterator_concept = std::forward_iterator_tag;
-
- constexpr extended_storage_iterator()
- : it{} {}
-
- constexpr extended_storage_iterator(iterator_type base, Other... other)
- : it{base, other...} {}
-
- template<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>>
- constexpr extended_storage_iterator(const extended_storage_iterator<It, Args...> &other)
- : it{other.it} {}
-
- constexpr extended_storage_iterator &operator++() noexcept {
- return ++std::get<It>(it), (++std::get<Other>(it), ...), *this;
- }
-
- constexpr extended_storage_iterator operator++(int) noexcept {
- extended_storage_iterator orig = *this;
- return ++(*this), orig;
- }
-
- [[nodiscard]] constexpr pointer operator->() const noexcept {
- return operator*();
- }
-
- [[nodiscard]] constexpr reference operator*() const noexcept {
- return {*std::get<It>(it), *std::get<Other>(it)...};
- }
-
- [[nodiscard]] constexpr iterator_type base() const noexcept {
- return std::get<It>(it);
- }
-
- template<typename... Lhs, typename... Rhs>
- friend constexpr bool operator==(const extended_storage_iterator<Lhs...> &, const extended_storage_iterator<Rhs...> &) noexcept;
-
-private:
- std::tuple<It, Other...> it;
-};
-
-template<typename... Lhs, typename... Rhs>
-[[nodiscard]] constexpr bool operator==(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
- return std::get<0>(lhs.it) == std::get<0>(rhs.it);
-}
-
-template<typename... Lhs, typename... Rhs>
-[[nodiscard]] constexpr bool operator!=(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief Storage implementation.
- *
- * Internal data structures arrange elements to maximize performance. There are
- * no guarantees that objects are returned in the insertion order when iterate
- * a storage. Do not make assumption on the order in any case.
- *
- * @warning
- * Empty types aren't explicitly instantiated. Therefore, many of the functions
- * normally available for non-empty types will not be available for empty ones.
- *
- * @tparam Type Element type.
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Type, typename Entity, typename Allocator, typename>
-class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
- using alloc_traits = std::allocator_traits<Allocator>;
- static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
- using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
- using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
- using underlying_iterator = typename underlying_type::basic_iterator;
- using traits_type = component_traits<Type>;
-
- [[nodiscard]] auto &element_at(const std::size_t pos) const {
- return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
- }
-
- auto assure_at_least(const std::size_t pos) {
- const auto idx = pos / traits_type::page_size;
-
- if(!(idx < payload.size())) {
- auto curr = payload.size();
- allocator_type allocator{get_allocator()};
- payload.resize(idx + 1u, nullptr);
-
- ENTT_TRY {
- for(const auto last = payload.size(); curr < last; ++curr) {
- payload[curr] = alloc_traits::allocate(allocator, traits_type::page_size);
- }
- }
- ENTT_CATCH {
- payload.resize(curr);
- ENTT_THROW;
- }
- }
-
- return payload[idx] + fast_mod(pos, traits_type::page_size);
- }
-
- template<typename... Args>
- auto emplace_element(const Entity entt, const bool force_back, Args &&...args) {
- const auto it = base_type::try_emplace(entt, force_back);
-
- ENTT_TRY {
- auto elem = assure_at_least(static_cast<size_type>(it.index()));
- entt::uninitialized_construct_using_allocator(to_address(elem), get_allocator(), std::forward<Args>(args)...);
- }
- ENTT_CATCH {
- base_type::pop(it, it + 1u);
- ENTT_THROW;
- }
-
- return it;
- }
-
- void shrink_to_size(const std::size_t sz) {
- const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size;
- allocator_type allocator{get_allocator()};
-
- for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
- if constexpr(traits_type::in_place_delete) {
- if(base_type::data()[pos] != tombstone) {
- alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
- }
- } else {
- alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
- }
- }
-
- for(auto pos = from, last = payload.size(); pos < last; ++pos) {
- alloc_traits::deallocate(allocator, payload[pos], traits_type::page_size);
- }
-
- payload.resize(from);
- }
-
-private:
- [[nodiscard]] const void *get_at(const std::size_t pos) const final {
- return std::addressof(element_at(pos));
- }
-
- void swap_or_move([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) override {
- static constexpr bool is_pinned_type_v = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>);
- // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy
- ENTT_ASSERT((from + 1u) && !is_pinned_type_v, "Pinned type");
-
- if constexpr(!is_pinned_type_v) {
- auto &elem = element_at(from);
-
- if constexpr(traits_type::in_place_delete) {
- if(base_type::operator[](to) == tombstone) {
- allocator_type allocator{get_allocator()};
- entt::uninitialized_construct_using_allocator(to_address(assure_at_least(to)), allocator, std::move(elem));
- alloc_traits::destroy(allocator, std::addressof(elem));
- return;
- }
- }
-
- using std::swap;
- swap(elem, element_at(to));
- }
- }
-
-protected:
- /**
- * @brief Erases entities from a storage.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- */
- void pop(underlying_iterator first, underlying_iterator last) override {
- for(allocator_type allocator{get_allocator()}; first != last; ++first) {
- // cannot use first.index() because it would break with cross iterators
- auto &elem = element_at(base_type::index(*first));
-
- if constexpr(traits_type::in_place_delete) {
- base_type::in_place_pop(first);
- alloc_traits::destroy(allocator, std::addressof(elem));
- } else {
- auto &other = element_at(base_type::size() - 1u);
- // destroying on exit allows reentrant destructors
- [[maybe_unused]] auto unused = std::exchange(elem, std::move(other));
- alloc_traits::destroy(allocator, std::addressof(other));
- base_type::swap_and_pop(first);
- }
- }
- }
-
- /*! @brief Erases all entities of a storage. */
- void pop_all() override {
- allocator_type allocator{get_allocator()};
-
- for(auto first = base_type::begin(); !(first.index() < 0); ++first) {
- if constexpr(traits_type::in_place_delete) {
- if(*first != tombstone) {
- base_type::in_place_pop(first);
- alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
- }
- } else {
- base_type::swap_and_pop(first);
- alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
- }
- }
- }
-
- /**
- * @brief Assigns an entity to a storage.
- * @param entt A valid identifier.
- * @param value Optional opaque value.
- * @param force_back Force back insertion.
- * @return Iterator pointing to the emplaced element.
- */
- underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override {
- if(value) {
- if constexpr(std::is_copy_constructible_v<element_type>) {
- return emplace_element(entt, force_back, *static_cast<const element_type *>(value));
- } else {
- return base_type::end();
- }
- } else {
- if constexpr(std::is_default_constructible_v<element_type>) {
- return emplace_element(entt, force_back);
- } else {
- return base_type::end();
- }
- }
- }
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = Allocator;
- /*! @brief Base type. */
- using base_type = underlying_type;
- /*! @brief Element type. */
- using element_type = Type;
- /*! @brief Type of the objects assigned to entities. */
- using value_type = element_type;
- /*! @brief Underlying entity identifier. */
- using entity_type = Entity;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Pointer type to contained elements. */
- using pointer = typename container_type::pointer;
- /*! @brief Constant pointer type to contained elements. */
- using const_pointer = typename alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
- /*! @brief Random access iterator type. */
- using iterator = internal::storage_iterator<container_type>;
- /*! @brief Constant random access iterator type. */
- using const_iterator = internal::storage_iterator<const container_type>;
- /*! @brief Reverse iterator type. */
- using reverse_iterator = std::reverse_iterator<iterator>;
- /*! @brief Constant reverse iterator type. */
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- /*! @brief Extended iterable storage proxy. */
- using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator, iterator>>;
- /*! @brief Constant extended iterable storage proxy. */
- using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator, const_iterator>>;
- /*! @brief Extended reverse iterable storage proxy. */
- using reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::reverse_iterator, reverse_iterator>>;
- /*! @brief Constant extended reverse iterable storage proxy. */
- using const_reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_reverse_iterator, const_reverse_iterator>>;
- /*! @brief Storage deletion policy. */
- static constexpr deletion_policy storage_policy{traits_type::in_place_delete};
-
- /*! @brief Default constructor. */
- basic_storage()
- : basic_storage{allocator_type{}} {}
-
- /**
- * @brief Constructs an empty storage with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_storage(const allocator_type &allocator)
- : base_type{type_id<element_type>(), storage_policy, allocator},
- payload{allocator} {}
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_storage(const basic_storage &) = delete;
-
- /**
- * @brief Move constructor.
- * @param other The instance to move from.
- */
- basic_storage(basic_storage &&other) noexcept
- : base_type{std::move(other)},
- payload{std::move(other.payload)} {}
-
- /**
- * @brief Allocator-extended move constructor.
- * @param other The instance to move from.
- * @param allocator The allocator to use.
- */
- basic_storage(basic_storage &&other, const allocator_type &allocator)
- : base_type{std::move(other), allocator},
- payload{std::move(other.payload), allocator} {
- ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed");
- }
-
- /*! @brief Default destructor. */
- ~basic_storage() noexcept override {
- shrink_to_size(0u);
- }
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This storage.
- */
- basic_storage &operator=(const basic_storage &) = delete;
-
- /**
- * @brief Move assignment operator.
- * @param other The instance to move from.
- * @return This storage.
- */
- basic_storage &operator=(basic_storage &&other) noexcept {
- ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed");
- shrink_to_size(0u);
- payload = std::move(other.payload);
- base_type::operator=(std::move(other));
- return *this;
- }
-
- /**
- * @brief Exchanges the contents with those of a given storage.
- * @param other Storage to exchange the content with.
- */
- void swap(basic_storage &other) {
- using std::swap;
- swap(payload, other.payload);
- base_type::swap(other);
- }
-
- /**
- * @brief Returns the associated allocator.
- * @return The associated allocator.
- */
- [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
- return payload.get_allocator();
- }
-
- /**
- * @brief Increases the capacity of a storage.
- *
- * If the new capacity is greater than the current capacity, new storage is
- * allocated, otherwise the method does nothing.
- *
- * @param cap Desired capacity.
- */
- void reserve(const size_type cap) override {
- if(cap != 0u) {
- base_type::reserve(cap);
- assure_at_least(cap - 1u);
- }
- }
-
- /**
- * @brief Returns the number of elements that a storage has currently
- * allocated space for.
- * @return Capacity of the storage.
- */
- [[nodiscard]] size_type capacity() const noexcept override {
- return payload.size() * traits_type::page_size;
- }
-
- /*! @brief Requests the removal of unused capacity. */
- void shrink_to_fit() override {
- base_type::shrink_to_fit();
- shrink_to_size(base_type::size());
- }
-
- /**
- * @brief Direct access to the array of objects.
- * @return A pointer to the array of objects.
- */
- [[nodiscard]] const_pointer raw() const noexcept {
- return payload.data();
- }
-
- /*! @copydoc raw */
- [[nodiscard]] pointer raw() noexcept {
- return payload.data();
- }
-
- /**
- * @brief Returns an iterator to the beginning.
- *
- * If the storage is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first instance of the internal array.
- */
- [[nodiscard]] const_iterator cbegin() const noexcept {
- const auto pos = static_cast<typename iterator::difference_type>(base_type::size());
- return const_iterator{&payload, pos};
- }
-
- /*! @copydoc cbegin */
- [[nodiscard]] const_iterator begin() const noexcept {
- return cbegin();
- }
-
- /*! @copydoc begin */
- [[nodiscard]] iterator begin() noexcept {
- const auto pos = static_cast<typename iterator::difference_type>(base_type::size());
- return iterator{&payload, pos};
- }
-
- /**
- * @brief Returns an iterator to the end.
- * @return An iterator to the element following the last instance of the
- * internal array.
- */
- [[nodiscard]] const_iterator cend() const noexcept {
- return const_iterator{&payload, {}};
- }
-
- /*! @copydoc cend */
- [[nodiscard]] const_iterator end() const noexcept {
- return cend();
- }
-
- /*! @copydoc end */
- [[nodiscard]] iterator end() noexcept {
- return iterator{&payload, {}};
- }
-
- /**
- * @brief Returns a reverse iterator to the beginning.
- *
- * If the storage is empty, the returned iterator will be equal to `rend()`.
- *
- * @return An iterator to the first instance of the reversed internal array.
- */
- [[nodiscard]] const_reverse_iterator crbegin() const noexcept {
- return std::make_reverse_iterator(cend());
- }
-
- /*! @copydoc crbegin */
- [[nodiscard]] const_reverse_iterator rbegin() const noexcept {
- return crbegin();
- }
-
- /*! @copydoc rbegin */
- [[nodiscard]] reverse_iterator rbegin() noexcept {
- return std::make_reverse_iterator(end());
- }
-
- /**
- * @brief Returns a reverse iterator to the end.
- * @return An iterator to the element following the last instance of the
- * reversed internal array.
- */
- [[nodiscard]] const_reverse_iterator crend() const noexcept {
- return std::make_reverse_iterator(cbegin());
- }
-
- /*! @copydoc crend */
- [[nodiscard]] const_reverse_iterator rend() const noexcept {
- return crend();
- }
-
- /*! @copydoc rend */
- [[nodiscard]] reverse_iterator rend() noexcept {
- return std::make_reverse_iterator(begin());
- }
-
- /**
- * @brief Returns the object assigned to an entity.
- *
- * @warning
- * Attempting to use an entity that doesn't belong to the storage results in
- * undefined behavior.
- *
- * @param entt A valid identifier.
- * @return The object assigned to the entity.
- */
- [[nodiscard]] const value_type &get(const entity_type entt) const noexcept {
- return element_at(base_type::index(entt));
- }
-
- /*! @copydoc get */
- [[nodiscard]] value_type &get(const entity_type entt) noexcept {
- return const_cast<value_type &>(std::as_const(*this).get(entt));
- }
-
- /**
- * @brief Returns the object assigned to an entity as a tuple.
- * @param entt A valid identifier.
- * @return The object assigned to the entity as a tuple.
- */
- [[nodiscard]] std::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept {
- return std::forward_as_tuple(get(entt));
- }
-
- /*! @copydoc get_as_tuple */
- [[nodiscard]] std::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept {
- return std::forward_as_tuple(get(entt));
- }
-
- /**
- * @brief Assigns an entity to a storage and constructs its object.
- *
- * @warning
- * Attempting to use an entity that already belongs to the storage results
- * in undefined behavior.
- *
- * @tparam Args Types of arguments to use to construct the object.
- * @param entt A valid identifier.
- * @param args Parameters to use to construct an object for the entity.
- * @return A reference to the newly created object.
- */
- template<typename... Args>
- value_type &emplace(const entity_type entt, Args &&...args) {
- if constexpr(std::is_aggregate_v<value_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<value_type>)) {
- const auto it = emplace_element(entt, false, Type{std::forward<Args>(args)...});
- return element_at(static_cast<size_type>(it.index()));
- } else {
- const auto it = emplace_element(entt, false, std::forward<Args>(args)...);
- return element_at(static_cast<size_type>(it.index()));
- }
- }
-
- /**
- * @brief Updates the instance assigned to a given entity in-place.
- * @tparam Func Types of the function objects to invoke.
- * @param entt A valid identifier.
- * @param func Valid function objects.
- * @return A reference to the updated instance.
- */
- template<typename... Func>
- value_type &patch(const entity_type entt, Func &&...func) {
- const auto idx = base_type::index(entt);
- auto &elem = element_at(idx);
- (std::forward<Func>(func)(elem), ...);
- return elem;
- }
-
- /**
- * @brief Assigns one or more entities to a storage and constructs their
- * objects from a given instance.
- *
- * @warning
- * Attempting to assign an entity that already belongs to the storage
- * results in undefined behavior.
- *
- * @tparam It Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @param value An instance of the object to construct.
- * @return Iterator pointing to the first element inserted, if any.
- */
- template<typename It>
- iterator insert(It first, It last, const value_type &value = {}) {
- for(; first != last; ++first) {
- emplace_element(*first, true, value);
- }
-
- return begin();
- }
-
- /**
- * @brief Assigns one or more entities to a storage and constructs their
- * objects from a given range.
- *
- * @sa construct
- *
- * @tparam EIt Type of input iterator.
- * @tparam CIt Type of input iterator.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @param from An iterator to the first element of the range of objects.
- * @return Iterator pointing to the first element inserted, if any.
- */
- template<typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, value_type>>>
- iterator insert(EIt first, EIt last, CIt from) {
- for(; first != last; ++first, ++from) {
- emplace_element(*first, true, *from);
- }
-
- return begin();
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a storage.
- *
- * The iterable object returns a tuple that contains the current entity and
- * a reference to its element.
- *
- * @return An iterable object to use to _visit_ the storage.
- */
- [[nodiscard]] iterable each() noexcept {
- return iterable{{base_type::begin(), begin()}, {base_type::end(), end()}};
- }
-
- /*! @copydoc each */
- [[nodiscard]] const_iterable each() const noexcept {
- return const_iterable{{base_type::cbegin(), cbegin()}, {base_type::cend(), cend()}};
- }
-
- /**
- * @brief Returns a reverse iterable object to use to _visit_ a storage.
- *
- * @sa each
- *
- * @return A reverse iterable object to use to _visit_ the storage.
- */
- [[nodiscard]] reverse_iterable reach() noexcept {
- return reverse_iterable{{base_type::rbegin(), rbegin()}, {base_type::rend(), rend()}};
- }
-
- /*! @copydoc reach */
- [[nodiscard]] const_reverse_iterable reach() const noexcept {
- return const_reverse_iterable{{base_type::crbegin(), crbegin()}, {base_type::crend(), crend()}};
- }
-
-private:
- container_type payload;
-};
-
-/*! @copydoc basic_storage */
-template<typename Type, typename Entity, typename Allocator>
-class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits<Type>::page_size == 0u>>
- : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
- using alloc_traits = std::allocator_traits<Allocator>;
- static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
- using traits_type = component_traits<Type>;
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = Allocator;
- /*! @brief Base type. */
- using base_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
- /*! @brief Element type. */
- using element_type = Type;
- /*! @brief Type of the objects assigned to entities. */
- using value_type = void;
- /*! @brief Underlying entity identifier. */
- using entity_type = Entity;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Extended iterable storage proxy. */
- using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
- /*! @brief Constant extended iterable storage proxy. */
- using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator>>;
- /*! @brief Extended reverse iterable storage proxy. */
- using reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::reverse_iterator>>;
- /*! @brief Constant extended reverse iterable storage proxy. */
- using const_reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_reverse_iterator>>;
- /*! @brief Storage deletion policy. */
- static constexpr deletion_policy storage_policy{traits_type::in_place_delete};
-
- /*! @brief Default constructor. */
- basic_storage()
- : basic_storage{allocator_type{}} {}
-
- /**
- * @brief Constructs an empty container with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_storage(const allocator_type &allocator)
- : base_type{type_id<element_type>(), storage_policy, allocator} {}
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_storage(const basic_storage &) = delete;
-
- /**
- * @brief Move constructor.
- * @param other The instance to move from.
- */
- basic_storage(basic_storage &&other) noexcept = default;
-
- /**
- * @brief Allocator-extended move constructor.
- * @param other The instance to move from.
- * @param allocator The allocator to use.
- */
- basic_storage(basic_storage &&other, const allocator_type &allocator)
- : base_type{std::move(other), allocator} {}
-
- /*! @brief Default destructor. */
- ~basic_storage() noexcept override = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This storage.
- */
- basic_storage &operator=(const basic_storage &) = delete;
-
- /**
- * @brief Move assignment operator.
- * @param other The instance to move from.
- * @return This storage.
- */
- basic_storage &operator=(basic_storage &&other) noexcept = default;
-
- /**
- * @brief Returns the associated allocator.
- * @return The associated allocator.
- */
- [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
- // std::allocator<void> has no cross constructors (waiting for C++20)
- if constexpr(std::is_void_v<element_type> && !std::is_constructible_v<allocator_type, typename base_type::allocator_type>) {
- return allocator_type{};
- } else {
- return allocator_type{base_type::get_allocator()};
- }
- }
-
- /**
- * @brief Returns the object assigned to an entity, that is `void`.
- *
- * @warning
- * Attempting to use an entity that doesn't belong to the storage results in
- * undefined behavior.
- *
- * @param entt A valid identifier.
- */
- void get([[maybe_unused]] const entity_type entt) const noexcept {
- ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
- }
-
- /**
- * @brief Returns an empty tuple.
- * @param entt A valid identifier.
- * @return Returns an empty tuple.
- */
- [[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
- ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
- return std::tuple{};
- }
-
- /**
- * @brief Assigns an entity to a storage and constructs its object.
- *
- * @warning
- * Attempting to use an entity that already belongs to the storage results
- * in undefined behavior.
- *
- * @tparam Args Types of arguments to use to construct the object.
- * @param entt A valid identifier.
- */
- template<typename... Args>
- void emplace(const entity_type entt, Args &&...) {
- base_type::try_emplace(entt, false);
- }
-
- /**
- * @brief Updates the instance assigned to a given entity in-place.
- * @tparam Func Types of the function objects to invoke.
- * @param entt A valid identifier.
- * @param func Valid function objects.
- */
- template<typename... Func>
- void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
- ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
- (std::forward<Func>(func)(), ...);
- }
-
- /**
- * @brief Assigns entities to a storage.
- * @tparam It Type of input iterator.
- * @tparam Args Types of optional arguments.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- */
- template<typename It, typename... Args>
- void insert(It first, It last, Args &&...) {
- for(; first != last; ++first) {
- base_type::try_emplace(*first, true);
- }
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a storage.
- *
- * The iterable object returns a tuple that contains the current entity.
- *
- * @return An iterable object to use to _visit_ the storage.
- */
- [[nodiscard]] iterable each() noexcept {
- return iterable{base_type::begin(), base_type::end()};
- }
-
- /*! @copydoc each */
- [[nodiscard]] const_iterable each() const noexcept {
- return const_iterable{base_type::cbegin(), base_type::cend()};
- }
-
- /**
- * @brief Returns a reverse iterable object to use to _visit_ a storage.
- *
- * @sa each
- *
- * @return A reverse iterable object to use to _visit_ the storage.
- */
- [[nodiscard]] reverse_iterable reach() noexcept {
- return reverse_iterable{{base_type::rbegin()}, {base_type::rend()}};
- }
-
- /*! @copydoc reach */
- [[nodiscard]] const_reverse_iterable reach() const noexcept {
- return const_reverse_iterable{{base_type::crbegin()}, {base_type::crend()}};
- }
-};
-
-/**
- * @brief Swap-only entity storage specialization.
- * @tparam Entity A valid entity type.
- * @tparam Allocator Type of allocator used to manage memory and elements.
- */
-template<typename Entity, typename Allocator>
-class basic_storage<Entity, Entity, Allocator>
- : public basic_sparse_set<Entity, Allocator> {
- using alloc_traits = std::allocator_traits<Allocator>;
- static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
- using underlying_iterator = typename basic_sparse_set<Entity, Allocator>::basic_iterator;
- using traits_type = entt_traits<Entity>;
-
- auto next() noexcept {
- entity_type entt = null;
-
- do {
- ENTT_ASSERT(placeholder < traits_type::to_entity(null), "No more entities available");
- entt = traits_type::combine(static_cast<typename traits_type::entity_type>(placeholder++), {});
- } while(base_type::current(entt) != traits_type::to_version(tombstone) && entt != null);
-
- return entt;
- }
-
-protected:
- /*! @brief Erases all entities of a storage. */
- void pop_all() override {
- base_type::pop_all();
- placeholder = {};
- }
-
- /**
- * @brief Assigns an entity to a storage.
- * @param hint A valid identifier.
- * @return Iterator pointing to the emplaced element.
- */
- underlying_iterator try_emplace(const Entity hint, const bool, const void *) override {
- return base_type::find(emplace(hint));
- }
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = Allocator;
- /*! @brief Base type. */
- using base_type = basic_sparse_set<Entity, Allocator>;
- /*! @brief Element type. */
- using element_type = Entity;
- /*! @brief Type of the objects assigned to entities. */
- using value_type = void;
- /*! @brief Underlying entity identifier. */
- using entity_type = Entity;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Extended iterable storage proxy. */
- using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
- /*! @brief Constant extended iterable storage proxy. */
- using const_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_iterator>>;
- /*! @brief Extended reverse iterable storage proxy. */
- using reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::reverse_iterator>>;
- /*! @brief Constant extended reverse iterable storage proxy. */
- using const_reverse_iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::const_reverse_iterator>>;
- /*! @brief Storage deletion policy. */
- static constexpr deletion_policy storage_policy = deletion_policy::swap_only;
-
- /*! @brief Default constructor. */
- basic_storage()
- : basic_storage{allocator_type{}} {
- }
-
- /**
- * @brief Constructs an empty container with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit basic_storage(const allocator_type &allocator)
- : base_type{type_id<void>(), storage_policy, allocator} {}
-
- /*! @brief Default copy constructor, deleted on purpose. */
- basic_storage(const basic_storage &) = delete;
-
- /**
- * @brief Move constructor.
- * @param other The instance to move from.
- */
- basic_storage(basic_storage &&other) noexcept
- : base_type{std::move(other)},
- placeholder{other.placeholder} {}
-
- /**
- * @brief Allocator-extended move constructor.
- * @param other The instance to move from.
- * @param allocator The allocator to use.
- */
- basic_storage(basic_storage &&other, const allocator_type &allocator)
- : base_type{std::move(other), allocator},
- placeholder{other.placeholder} {}
-
- /*! @brief Default destructor. */
- ~basic_storage() noexcept override = default;
-
- /**
- * @brief Default copy assignment operator, deleted on purpose.
- * @return This storage.
- */
- basic_storage &operator=(const basic_storage &) = delete;
-
- /**
- * @brief Move assignment operator.
- * @param other The instance to move from.
- * @return This storage.
- */
- basic_storage &operator=(basic_storage &&other) noexcept {
- placeholder = other.placeholder;
- base_type::operator=(std::move(other));
- return *this;
- }
-
- /**
- * @brief Returns the object assigned to an entity, that is `void`.
- *
- * @warning
- * Attempting to use an entity that doesn't belong to the storage results in
- * undefined behavior.
- *
- * @param entt A valid identifier.
- */
- void get([[maybe_unused]] const entity_type entt) const noexcept {
- ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
- }
-
- /**
- * @brief Returns an empty tuple.
- * @param entt A valid identifier.
- * @return Returns an empty tuple.
- */
- [[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
- ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
- return std::tuple{};
- }
-
- /**
- * @brief Creates a new identifier or recycles a destroyed one.
- * @return A valid identifier.
- */
- entity_type emplace() {
- const auto len = base_type::free_list();
- const auto entt = (len == base_type::size()) ? next() : base_type::data()[len];
- return *base_type::try_emplace(entt, true);
- }
-
- /**
- * @brief Creates a new identifier or recycles a destroyed one.
- *
- * If the requested identifier isn't in use, the suggested one is used.
- * Otherwise, a new identifier is returned.
- *
- * @param hint Required identifier.
- * @return A valid identifier.
- */
- entity_type emplace(const entity_type hint) {
- if(hint != null && hint != tombstone) {
- if(const auto curr = traits_type::construct(traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone || !(base_type::index(curr) < base_type::free_list())) {
- return *base_type::try_emplace(hint, true);
- }
- }
-
- return emplace();
- }
-
- /**
- * @brief Updates a given identifier.
- * @tparam Func Types of the function objects to invoke.
- * @param entt A valid identifier.
- * @param func Valid function objects.
- */
- template<typename... Func>
- void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
- ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
- (std::forward<Func>(func)(), ...);
- }
-
- /**
- * @brief Assigns each element in a range an identifier.
- * @tparam It Type of mutable forward iterator.
- * @param first An iterator to the first element of the range to generate.
- * @param last An iterator past the last element of the range to generate.
- */
- template<typename It>
- void insert(It first, It last) {
- for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
- *first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true);
- }
-
- for(; first != last; ++first) {
- *first = *base_type::try_emplace(next(), true);
- }
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a storage.
- *
- * The iterable object returns a tuple that contains the current entity.
- *
- * @return An iterable object to use to _visit_ the storage.
- */
- [[nodiscard]] iterable each() noexcept {
- return std::as_const(*this).each();
- }
-
- /*! @copydoc each */
- [[nodiscard]] const_iterable each() const noexcept {
- const auto it = base_type::cend();
- return const_iterable{it - base_type::free_list(), it};
- }
-
- /**
- * @brief Returns a reverse iterable object to use to _visit_ a storage.
- *
- * @sa each
- *
- * @return A reverse iterable object to use to _visit_ the storage.
- */
- [[nodiscard]] reverse_iterable reach() noexcept {
- return std::as_const(*this).reach();
- }
-
- /*! @copydoc reach */
- [[nodiscard]] const_reverse_iterable reach() const noexcept {
- const auto it = base_type::crbegin();
- return const_reverse_iterable{it, it + base_type::free_list()};
- }
-
-private:
- size_type placeholder{};
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/storage_mixin.hpp b/deps/include/entt/entity/storage_mixin.hpp deleted file mode 100644 index 5ea18a8..0000000 --- a/deps/include/entt/entity/storage_mixin.hpp +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef ENTT_ENTITY_SIGH_STORAGE_MIXIN_HPP
-#define ENTT_ENTITY_SIGH_STORAGE_MIXIN_HPP
-
-#include <utility>
-#include "../config/config.h"
-#include "../core/any.hpp"
-#include "../signal/sigh.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/**
- * @brief Mixin type used to add signal support to storage types.
- *
- * The function type of a listener is equivalent to:
- *
- * @code{.cpp}
- * void(basic_registry<entity_type> &, entity_type);
- * @endcode
- *
- * This applies to all signals made available.
- *
- * @tparam Type The type of the underlying storage.
- */
-template<typename Type>
-class sigh_storage_mixin final: public Type {
- using basic_registry_type = basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>;
- using sigh_type = sigh<void(basic_registry_type &, const typename Type::entity_type), typename Type::allocator_type>;
- using basic_iterator = typename Type::basic_iterator;
-
- void pop(basic_iterator first, basic_iterator last) override {
- ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
-
- for(; first != last; ++first) {
- const auto entt = *first;
- destruction.publish(*owner, entt);
- const auto it = Type::find(entt);
- Type::pop(it, it + 1u);
- }
- }
-
- basic_iterator try_emplace(const typename basic_registry_type::entity_type entt, const bool force_back, const void *value) final {
- ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
- Type::try_emplace(entt, force_back, value);
- construction.publish(*owner, entt);
- return Type::find(entt);
- }
-
-public:
- /*! @brief Allocator type. */
- using allocator_type = typename Type::allocator_type;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename Type::entity_type;
- /*! @brief Expected registry type. */
- using registry_type = basic_registry_type;
-
- /*! @brief Default constructor. */
- sigh_storage_mixin()
- : sigh_storage_mixin{allocator_type{}} {}
-
- /**
- * @brief Constructs an empty storage with a given allocator.
- * @param allocator The allocator to use.
- */
- explicit sigh_storage_mixin(const allocator_type &allocator)
- : Type{allocator},
- owner{},
- construction{allocator},
- destruction{allocator},
- update{allocator} {}
-
- /**
- * @brief Move constructor.
- * @param other The instance to move from.
- */
- sigh_storage_mixin(sigh_storage_mixin &&other) noexcept
- : Type{std::move(other)},
- owner{other.owner},
- construction{std::move(other.construction)},
- destruction{std::move(other.destruction)},
- update{std::move(other.update)} {}
-
- /**
- * @brief Allocator-extended move constructor.
- * @param other The instance to move from.
- * @param allocator The allocator to use.
- */
- sigh_storage_mixin(sigh_storage_mixin &&other, const allocator_type &allocator) noexcept
- : Type{std::move(other), allocator},
- owner{other.owner},
- construction{std::move(other.construction), allocator},
- destruction{std::move(other.destruction), allocator},
- update{std::move(other.update), allocator} {}
-
- /**
- * @brief Move assignment operator.
- * @param other The instance to move from.
- * @return This storage.
- */
- sigh_storage_mixin &operator=(sigh_storage_mixin &&other) noexcept {
- Type::operator=(std::move(other));
- owner = other.owner;
- construction = std::move(other.construction);
- destruction = std::move(other.destruction);
- update = std::move(other.update);
- return *this;
- }
-
- /**
- * @brief Exchanges the contents with those of a given storage.
- * @param other Storage to exchange the content with.
- */
- void swap(sigh_storage_mixin &other) {
- using std::swap;
- Type::swap(other);
- swap(owner, other.owner);
- swap(construction, other.construction);
- swap(destruction, other.destruction);
- swap(update, other.update);
- }
-
- /**
- * @brief Returns a sink object.
- *
- * The sink returned by this function can be used to receive notifications
- * whenever a new instance is created and assigned to an entity.<br/>
- * Listeners are invoked after the object has been assigned to the entity.
- *
- * @sa sink
- *
- * @return A temporary sink object.
- */
- [[nodiscard]] auto on_construct() noexcept {
- return sink{construction};
- }
-
- /**
- * @brief Returns a sink object.
- *
- * The sink returned by this function can be used to receive notifications
- * whenever an instance is explicitly updated.<br/>
- * Listeners are invoked after the object has been updated.
- *
- * @sa sink
- *
- * @return A temporary sink object.
- */
- [[nodiscard]] auto on_update() noexcept {
- return sink{update};
- }
-
- /**
- * @brief Returns a sink object.
- *
- * The sink returned by this function can be used to receive notifications
- * whenever an instance is removed from an entity and thus destroyed.<br/>
- * Listeners are invoked before the object has been removed from the entity.
- *
- * @sa sink
- *
- * @return A temporary sink object.
- */
- [[nodiscard]] auto on_destroy() noexcept {
- return sink{destruction};
- }
-
- /**
- * @brief Assigns entities to a storage.
- * @tparam Args Types of arguments to use to construct the object.
- * @param entt A valid identifier.
- * @param args Parameters to use to initialize the object.
- * @return A reference to the newly created object.
- */
- template<typename... Args>
- decltype(auto) emplace(const entity_type entt, Args &&...args) {
- ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
- Type::emplace(entt, std::forward<Args>(args)...);
- construction.publish(*owner, entt);
- return this->get(entt);
- }
-
- /**
- * @brief Patches the given instance for an entity.
- * @tparam Func Types of the function objects to invoke.
- * @param entt A valid identifier.
- * @param func Valid function objects.
- * @return A reference to the patched instance.
- */
- template<typename... Func>
- decltype(auto) patch(const entity_type entt, Func &&...func) {
- ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
- Type::patch(entt, std::forward<Func>(func)...);
- update.publish(*owner, entt);
- return this->get(entt);
- }
-
- /**
- * @brief Assigns entities to a storage.
- * @tparam It Type of input iterator.
- * @tparam Args Types of arguments to use to construct the objects assigned
- * to the entities.
- * @param first An iterator to the first element of the range of entities.
- * @param last An iterator past the last element of the range of entities.
- * @param args Parameters to use to initialize the objects assigned to the
- * entities.
- */
- template<typename It, typename... Args>
- void insert(It first, It last, Args &&...args) {
- ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
- Type::insert(first, last, std::forward<Args>(args)...);
-
- for(auto it = construction.empty() ? last : first; it != last; ++it) {
- construction.publish(*owner, *it);
- }
- }
-
- /**
- * @brief Forwards variables to derived classes, if any.
- * @param value A variable wrapped in an opaque container.
- */
- void bind(any value) noexcept final {
- auto *reg = any_cast<basic_registry_type>(&value);
- owner = reg ? reg : owner;
- Type::bind(std::move(value));
- }
-
-private:
- basic_registry_type *owner;
- sigh_type construction;
- sigh_type destruction;
- sigh_type update;
-};
-
-} // namespace entt
-
-#endif
diff --git a/deps/include/entt/entity/view.hpp b/deps/include/entt/entity/view.hpp deleted file mode 100644 index 1009efe..0000000 --- a/deps/include/entt/entity/view.hpp +++ /dev/null @@ -1,1076 +0,0 @@ -#ifndef ENTT_ENTITY_VIEW_HPP
-#define ENTT_ENTITY_VIEW_HPP
-
-#include <array>
-#include <cstddef>
-#include <iterator>
-#include <tuple>
-#include <type_traits>
-#include <utility>
-#include "../config/config.h"
-#include "../core/iterator.hpp"
-#include "../core/type_traits.hpp"
-#include "entity.hpp"
-#include "fwd.hpp"
-
-namespace entt {
-
-/*! @cond TURN_OFF_DOXYGEN */
-namespace internal {
-
-template<typename It, typename Entity>
-[[nodiscard]] bool all_of(It first, const It last, const Entity entt) noexcept {
- for(; (first != last) && (*first)->contains(entt); ++first) {}
- return first == last;
-}
-
-template<typename It, typename Entity>
-[[nodiscard]] bool none_of(It first, const It last, const Entity entt) noexcept {
- for(; (first != last) && !(*first && (*first)->contains(entt)); ++first) {}
- return first == last;
-}
-
-template<typename It>
-[[nodiscard]] bool fully_initialized(It first, const It last) noexcept {
- for(; (first != last) && *first; ++first) {}
- return first == last;
-}
-
-template<typename Result, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
-[[nodiscard]] Result view_pack(const View &view, const Other &other, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>) {
- Result elem{};
- // friend-initialization, avoid multiple calls to refresh
- elem.pools = {view.template storage<GLhs>()..., other.template storage<GRhs>()...};
- elem.filter = {view.template storage<sizeof...(GLhs) + ELhs>()..., other.template storage<sizeof...(GRhs) + ERhs>()...};
- elem.refresh();
- return elem;
-}
-
-template<typename Type, std::size_t Get, std::size_t Exclude>
-class view_iterator final {
- template<typename, typename...>
- friend class extended_view_iterator;
-
- using iterator_type = typename Type::const_iterator;
- using iterator_traits = std::iterator_traits<iterator_type>;
-
- [[nodiscard]] bool valid(const typename iterator_traits::value_type entt) const noexcept {
- return ((Get != 1u) || (entt != tombstone))
- && internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt)
- && internal::none_of(filter.begin(), filter.end(), entt);
- }
-
- void seek_next() {
- for(constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {}
- }
-
-public:
- using value_type = typename iterator_traits::value_type;
- using pointer = typename iterator_traits::pointer;
- using reference = typename iterator_traits::reference;
- using difference_type = typename iterator_traits::difference_type;
- using iterator_category = std::forward_iterator_tag;
-
- constexpr view_iterator() noexcept
- : it{},
- pools{},
- filter{},
- index{} {}
-
- view_iterator(iterator_type first, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl, const std::size_t idx) noexcept
- : it{first},
- pools{value},
- filter{excl},
- index{idx} {
- seek_next();
- }
-
- view_iterator &operator++() noexcept {
- ++it;
- seek_next();
- return *this;
- }
-
- view_iterator operator++(int) noexcept {
- view_iterator orig = *this;
- return ++(*this), orig;
- }
-
- [[nodiscard]] pointer operator->() const noexcept {
- return &*it;
- }
-
- [[nodiscard]] reference operator*() const noexcept {
- return *operator->();
- }
-
- template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
- friend constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &, const view_iterator<RhsType, RhsArgs...> &) noexcept;
-
-private:
- iterator_type it;
- std::array<const Type *, Get> pools;
- std::array<const Type *, Exclude> filter;
- std::size_t index;
-};
-
-template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
-[[nodiscard]] constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
- return lhs.it == rhs.it;
-}
-
-template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
-[[nodiscard]] constexpr bool operator!=(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-template<typename It, typename... Get>
-class extended_view_iterator final {
- template<std::size_t... Index>
- [[nodiscard]] auto dereference(std::index_sequence<Index...>) const noexcept {
- return std::tuple_cat(std::make_tuple(*it), static_cast<Get *>(const_cast<constness_as_t<typename Get::base_type, Get> *>(std::get<Index>(it.pools)))->get_as_tuple(*it)...);
- }
-
-public:
- using iterator_type = It;
- using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Get>().get_as_tuple({})...));
- using pointer = input_iterator_pointer<value_type>;
- using reference = value_type;
- using difference_type = std::ptrdiff_t;
- using iterator_category = std::input_iterator_tag;
- using iterator_concept = std::forward_iterator_tag;
-
- constexpr extended_view_iterator()
- : it{} {}
-
- extended_view_iterator(iterator_type from)
- : it{from} {}
-
- extended_view_iterator &operator++() noexcept {
- return ++it, *this;
- }
-
- extended_view_iterator operator++(int) noexcept {
- extended_view_iterator orig = *this;
- return ++(*this), orig;
- }
-
- [[nodiscard]] reference operator*() const noexcept {
- return dereference(std::index_sequence_for<Get...>{});
- }
-
- [[nodiscard]] pointer operator->() const noexcept {
- return operator*();
- }
-
- [[nodiscard]] constexpr iterator_type base() const noexcept {
- return it;
- }
-
- template<typename... Lhs, typename... Rhs>
- friend bool constexpr operator==(const extended_view_iterator<Lhs...> &, const extended_view_iterator<Rhs...> &) noexcept;
-
-private:
- It it;
-};
-
-template<typename... Lhs, typename... Rhs>
-[[nodiscard]] constexpr bool operator==(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
- return lhs.it == rhs.it;
-}
-
-template<typename... Lhs, typename... Rhs>
-[[nodiscard]] constexpr bool operator!=(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
- return !(lhs == rhs);
-}
-
-} // namespace internal
-/*! @endcond */
-
-/**
- * @brief View implementation.
- *
- * Primary template isn't defined on purpose. All the specializations give a
- * compile-time error, but for a few reasonable cases.
- *
- * @b Important
- *
- * View iterators aren't invalidated if:
- *
- * * New elements are added to the storage iterated by the view.
- * * The entity currently returned is modified (for example, elements are added
- * or removed from it).
- * * The entity currently returned is destroyed.
- *
- * In all other cases, modifying the storage iterated by a view in any way can
- * invalidate all iterators.
- */
-template<typename, typename, typename>
-class basic_view;
-
-/**
- * @brief Basic storage view implementation.
- * @warning For internal use only, backward compatibility not guaranteed.
- * @tparam Type Common type among all storage types.
- * @tparam Get Number of storage iterated by the view.
- * @tparam Exclude Number of storage used to filter the view.
- */
-template<typename Type, std::size_t Get, std::size_t Exclude>
-class basic_common_view {
- template<typename Return, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
- friend Return internal::view_pack(const View &, const Other &, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>);
-
- [[nodiscard]] auto offset() const noexcept {
- ENTT_ASSERT(index != Get, "Invalid view");
- return (pools[index]->policy() == deletion_policy::swap_only) ? pools[index]->free_list() : pools[index]->size();
- }
-
- void unchecked_refresh() noexcept {
- index = 0u;
-
- if constexpr(Get > 1u) {
- for(size_type pos{1u}; pos < Get; ++pos) {
- if(pools[pos]->size() < pools[index]->size()) {
- index = pos;
- }
- }
- }
- }
-
-protected:
- /*! @cond TURN_OFF_DOXYGEN */
- basic_common_view() noexcept = default;
-
- basic_common_view(std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl) noexcept
- : pools{value},
- filter{excl},
- index{Get} {
- unchecked_refresh();
- }
-
- [[nodiscard]] const Type *pool_at(const std::size_t pos) const noexcept {
- return pools[pos];
- }
-
- [[nodiscard]] const Type *storage(const std::size_t pos) const noexcept {
- return (pos < Get) ? pools[pos] : filter[pos - Get];
- }
-
- void storage(const std::size_t pos, const Type *elem) noexcept {
- if(pos < Get) {
- pools[pos] = elem;
- refresh();
- } else {
- filter[pos - Get] = elem;
- }
- }
-
- [[nodiscard]] bool none_of(const typename Type::entity_type entt) const noexcept {
- return internal::none_of(filter.begin(), filter.end(), entt);
- }
-
- void use(const std::size_t pos) noexcept {
- index = (index != Get) ? pos : Get;
- }
- /*! @endcond */
-
-public:
- /*! @brief Common type among all storage types. */
- using common_type = Type;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename Type::entity_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Forward iterator type. */
- using iterator = internal::view_iterator<common_type, Get, Exclude>;
-
- /*! @brief Updates the internal leading view if required. */
- void refresh() noexcept {
- size_type pos = (index != Get) * Get;
- for(; pos < Get && pools[pos] != nullptr; ++pos) {}
-
- if(pos == Get) {
- unchecked_refresh();
- }
- }
-
- /**
- * @brief Returns the leading storage of a view, if any.
- * @return The leading storage of the view.
- */
- [[nodiscard]] const common_type *handle() const noexcept {
- return (index != Get) ? pools[index] : nullptr;
- }
-
- /**
- * @brief Estimates the number of entities iterated by the view.
- * @return Estimated number of entities iterated by the view.
- */
- [[nodiscard]] size_type size_hint() const noexcept {
- return (index != Get) ? pools[index]->size() : size_type{};
- }
-
- /**
- * @brief Returns an iterator to the first entity of the view.
- *
- * If the view is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first entity of the view.
- */
- [[nodiscard]] iterator begin() const noexcept {
- return (index != Get) ? iterator{pools[index]->end() - static_cast<typename iterator::difference_type>(offset()), pools, filter, index} : iterator{};
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the view.
- * @return An iterator to the entity following the last entity of the view.
- */
- [[nodiscard]] iterator end() const noexcept {
- return (index != Get) ? iterator{pools[index]->end(), pools, filter, index} : iterator{};
- }
-
- /**
- * @brief Returns the first entity of the view, if any.
- * @return The first entity of the view if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type front() const noexcept {
- const auto it = begin();
- return it != end() ? *it : null;
- }
-
- /**
- * @brief Returns the last entity of the view, if any.
- * @return The last entity of the view if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type back() const noexcept {
- if(index != Get) {
- auto it = pools[index]->rbegin();
- const auto last = it + static_cast<typename iterator::difference_type>(offset());
- for(; it != last && !contains(*it); ++it) {}
- return it == last ? null : *it;
- }
-
- return null;
- }
-
- /**
- * @brief Finds an entity.
- * @param entt A valid identifier.
- * @return An iterator to the given entity if it's found, past the end
- * iterator otherwise.
- */
- [[nodiscard]] iterator find(const entity_type entt) const noexcept {
- return contains(entt) ? iterator{pools[index]->find(entt), pools, filter, index} : end();
- }
-
- /**
- * @brief Checks if a view is fully initialized.
- * @return True if the view is fully initialized, false otherwise.
- */
- [[nodiscard]] explicit operator bool() const noexcept {
- return (index != Get) && internal::fully_initialized(filter.begin(), filter.end());
- }
-
- /**
- * @brief Checks if a view contains an entity.
- * @param entt A valid identifier.
- * @return True if the view contains the given entity, false otherwise.
- */
- [[nodiscard]] bool contains(const entity_type entt) const noexcept {
- return (index != Get)
- && internal::all_of(pools.begin(), pools.end(), entt)
- && internal::none_of(filter.begin(), filter.end(), entt)
- && pools[index]->index(entt) < offset();
- }
-
-private:
- std::array<const common_type *, Get> pools{};
- std::array<const common_type *, Exclude> filter{};
- size_type index{Get};
-};
-
-/**
- * @brief General purpose view.
- *
- * This view visits all entities that are at least in the given storage. During
- * initialization, it also looks at the number of elements available for each
- * storage and uses the smallest set in order to get a performance boost.
- *
- * @sa basic_view
- *
- * @tparam Get Types of storage iterated by the view.
- * @tparam Exclude Types of storage used to filter the view.
- */
-template<typename... Get, typename... Exclude>
-class basic_view<get_t<Get...>, exclude_t<Exclude...>, std::enable_if_t<(sizeof...(Get) + sizeof...(Exclude) > 1)>>
- : public basic_common_view<std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>, sizeof...(Get), sizeof...(Exclude)> {
- using base_type = basic_common_view<std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>, sizeof...(Get), sizeof...(Exclude)>;
-
- template<typename Type>
- static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
-
- template<std::size_t... Index>
- [[nodiscard]] auto get(const typename base_type::entity_type entt, std::index_sequence<Index...>) const noexcept {
- return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
- }
-
- template<std::size_t Curr, std::size_t Other, typename... Args>
- [[nodiscard]] auto dispatch_get(const std::tuple<typename base_type::entity_type, Args...> &curr) const {
- if constexpr(Curr == Other) {
- return std::forward_as_tuple(std::get<Args>(curr)...);
- } else {
- return storage<Other>()->get_as_tuple(std::get<0>(curr));
- }
- }
-
- template<std::size_t Curr, typename Func, std::size_t... Index>
- void each(Func &func, std::index_sequence<Index...>) const {
- static constexpr bool tombstone_check_required = ((sizeof...(Get) == 1u) && ... && (Get::storage_policy == deletion_policy::in_place));
-
- for(const auto curr: storage<Curr>()->each()) {
- if(const auto entt = std::get<0>(curr); (!tombstone_check_required || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) {
- if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
- std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get<Curr, Index>(curr)...));
- } else {
- std::apply(func, std::tuple_cat(dispatch_get<Curr, Index>(curr)...));
- }
- }
- }
- }
-
- template<typename Func, std::size_t... Index>
- void pick_and_each(Func &func, std::index_sequence<Index...> seq) const {
- if(const auto *view = base_type::handle(); view != nullptr) {
- ((view == base_type::pool_at(Index) ? each<Index>(func, seq) : void()), ...);
- }
- }
-
-public:
- /*! @brief Common type among all storage types. */
- using common_type = typename base_type::common_type;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename base_type::entity_type;
- /*! @brief Unsigned integer type. */
- using size_type = typename base_type::size_type;
- /*! @brief Forward iterator type. */
- using iterator = typename base_type::iterator;
- /*! @brief Iterable view type. */
- using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, Get...>>;
-
- /*! @brief Default constructor to use to create empty, invalid views. */
- basic_view() noexcept
- : base_type{} {}
-
- /**
- * @brief Constructs a view from a set of storage classes.
- * @param value The storage for the types to iterate.
- * @param excl The storage for the types used to filter the view.
- */
- basic_view(Get &...value, Exclude &...excl) noexcept
- : base_type{{&value...}, {&excl...}} {
- }
-
- /**
- * @brief Constructs a view from a set of storage classes.
- * @param value The storage for the types to iterate.
- * @param excl The storage for the types used to filter the view.
- */
- basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {}) noexcept
- : basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(value, excl))} {}
-
- /**
- * @brief Forces a view to use a given element to drive iterations
- * @tparam Type Type of element to use to drive iterations.
- */
- template<typename Type>
- void use() noexcept {
- use<index_of<Type>>();
- }
-
- /**
- * @brief Forces a view to use a given element to drive iterations
- * @tparam Index Index of the element to use to drive iterations.
- */
- template<std::size_t Index>
- void use() noexcept {
- base_type::use(Index);
- }
-
- /**
- * @brief Returns the storage for a given element type, if any.
- * @tparam Type Type of element of which to return the storage.
- * @return The storage for the given element type.
- */
- template<typename Type>
- [[nodiscard]] auto *storage() const noexcept {
- return storage<index_of<Type>>();
- }
-
- /**
- * @brief Returns the storage for a given index, if any.
- * @tparam Index Index of the storage to return.
- * @return The storage for the given index.
- */
- template<std::size_t Index>
- [[nodiscard]] auto *storage() const noexcept {
- using type = type_list_element_t<Index, type_list<Get..., Exclude...>>;
- return static_cast<type *>(const_cast<constness_as_t<common_type, type> *>(base_type::storage(Index)));
- }
-
- /**
- * @brief Assigns a storage to a view.
- * @tparam Type Type of storage to assign to the view.
- * @param elem A storage to assign to the view.
- */
- template<typename Type>
- void storage(Type &elem) noexcept {
- storage<index_of<typename Type::element_type>>(elem);
- }
-
- /**
- * @brief Assigns a storage to a view.
- * @tparam Index Index of the storage to assign to the view.
- * @tparam Type Type of storage to assign to the view.
- * @param elem A storage to assign to the view.
- */
- template<std::size_t Index, typename Type>
- void storage(Type &elem) noexcept {
- static_assert(std::is_convertible_v<Type &, type_list_element_t<Index, type_list<Get..., Exclude...>> &>, "Unexpected type");
- base_type::storage(Index, &elem);
- }
-
- /**
- * @brief Returns the elements assigned to the given entity.
- * @param entt A valid identifier.
- * @return The elements assigned to the given entity.
- */
- [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
- return get(entt);
- }
-
- /**
- * @brief Returns the elements assigned to the given entity.
- * @tparam Type Type of the element to get.
- * @tparam Other Other types of elements to get.
- * @param entt A valid identifier.
- * @return The elements assigned to the entity.
- */
- template<typename Type, typename... Other>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- return get<index_of<Type>, index_of<Other>...>(entt);
- }
-
- /**
- * @brief Returns the elements assigned to the given entity.
- * @tparam Index Indexes of the elements to get.
- * @param entt A valid identifier.
- * @return The elements assigned to the entity.
- */
- template<std::size_t... Index>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- if constexpr(sizeof...(Index) == 0) {
- return get(entt, std::index_sequence_for<Get...>{});
- } else if constexpr(sizeof...(Index) == 1) {
- return (storage<Index>()->get(entt), ...);
- } else {
- return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
- }
- }
-
- /**
- * @brief Iterates entities and elements and applies the given function
- * object to them.
- *
- * The signature of the function must be equivalent to one of the following
- * (non-empty types only, constness as requested):
- *
- * @code{.cpp}
- * void(const entity_type, Type &...);
- * void(Type &...);
- * @endcode
- *
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template<typename Func>
- void each(Func func) const {
- pick_and_each(func, std::index_sequence_for<Get...>{});
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a view.
- *
- * The iterable object returns a tuple that contains the current entity and
- * a set of references to its non-empty elements. The _constness_ of the
- * elements is as requested.
- *
- * @return An iterable object to use to _visit_ the view.
- */
- [[nodiscard]] iterable each() const noexcept {
- return iterable{base_type::begin(), base_type::end()};
- }
-
- /**
- * @brief Combines two views in a _more specific_ one.
- * @tparam OGet Element list of the view to combine with.
- * @tparam OExclude Filter list of the view to combine with.
- * @param other The view to combine with.
- * @return A more specific view.
- */
- template<typename... OGet, typename... OExclude>
- [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
- return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
- *this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
- }
-};
-
-/**
- * @brief Basic storage view implementation.
- * @warning For internal use only, backward compatibility not guaranteed.
- * @tparam Type Common type among all storage types.
- * @tparam Policy Storage policy.
- */
-template<typename Type, deletion_policy Policy>
-class basic_storage_view {
-protected:
- /*! @cond TURN_OFF_DOXYGEN */
- basic_storage_view() noexcept = default;
-
- basic_storage_view(const Type *value) noexcept
- : leading{value} {
- ENTT_ASSERT(leading->policy() == Policy, "Unexpected storage policy");
- }
- /*! @endcond */
-
-public:
- /*! @brief Common type among all storage types. */
- using common_type = Type;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename common_type::entity_type;
- /*! @brief Unsigned integer type. */
- using size_type = std::size_t;
- /*! @brief Random access iterator type. */
- using iterator = std::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, 1u, 0u>, typename common_type::iterator>;
- /*! @brief Reverse iterator type. */
- using reverse_iterator = std::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
-
- /**
- * @brief Returns the leading storage of a view, if any.
- * @return The leading storage of the view.
- */
- [[nodiscard]] const common_type *handle() const noexcept {
- return leading;
- }
-
- /**
- * @brief Returns the number of entities that have the given element.
- * @tparam Pol Dummy template parameter used for sfinae purposes only.
- * @return Number of entities that have the given element.
- */
- template<typename..., deletion_policy Pol = Policy>
- [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, size_type> size() const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop) {
- return leading ? leading->size() : size_type{};
- } else {
- static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
- return leading ? leading->free_list() : size_type{};
- }
- }
-
- /**
- * @brief Estimates the number of entities iterated by the view.
- * @tparam Pol Dummy template parameter used for sfinae purposes only.
- * @return Estimated number of entities iterated by the view.
- */
- template<typename..., deletion_policy Pol = Policy>
- [[nodiscard]] std::enable_if_t<Pol == deletion_policy::in_place, size_type> size_hint() const noexcept {
- return leading ? leading->size() : size_type{};
- }
-
- /**
- * @brief Checks whether a view is empty.
- * @tparam Pol Dummy template parameter used for sfinae purposes only.
- * @return True if the view is empty, false otherwise.
- */
- template<typename..., deletion_policy Pol = Policy>
- [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, bool> empty() const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop) {
- return !leading || leading->empty();
- } else {
- static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
- return !leading || (leading->free_list() == 0u);
- }
- }
-
- /**
- * @brief Returns an iterator to the first entity of the view.
- *
- * If the view is empty, the returned iterator will be equal to `end()`.
- *
- * @return An iterator to the first entity of the view.
- */
- [[nodiscard]] iterator begin() const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop) {
- return leading ? leading->begin() : iterator{};
- } else if constexpr(Policy == deletion_policy::swap_only) {
- return leading ? (leading->end() - leading->free_list()) : iterator{};
- } else {
- static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
- return leading ? iterator{leading->begin(), {leading}, {}, 0u} : iterator{};
- }
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the view.
- * @return An iterator to the entity following the last entity of the view.
- */
- [[nodiscard]] iterator end() const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
- return leading ? leading->end() : iterator{};
- } else {
- static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
- return leading ? iterator{leading->end(), {leading}, {}, 0u} : iterator{};
- }
- }
-
- /**
- * @brief Returns an iterator to the first entity of the reversed view.
- *
- * If the view is empty, the returned iterator will be equal to `rend()`.
- *
- * @tparam Pol Dummy template parameter used for sfinae purposes only.
- * @return An iterator to the first entity of the reversed view.
- */
- template<typename..., deletion_policy Pol = Policy>
- [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rbegin() const noexcept {
- return leading ? leading->rbegin() : reverse_iterator{};
- }
-
- /**
- * @brief Returns an iterator that is past the last entity of the reversed
- * view.
- * @tparam Pol Dummy template parameter used for sfinae purposes only.
- * @return An iterator to the entity following the last entity of the
- * reversed view.
- */
- template<typename..., deletion_policy Pol = Policy>
- [[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rend() const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop) {
- return leading ? leading->rend() : reverse_iterator{};
- } else {
- static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
- return leading ? (leading->rbegin() + leading->free_list()) : reverse_iterator{};
- }
- }
-
- /**
- * @brief Returns the first entity of the view, if any.
- * @return The first entity of the view if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type front() const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop) {
- return empty() ? null : *leading->begin();
- } else if constexpr(Policy == deletion_policy::swap_only) {
- return empty() ? null : *(leading->end() - leading->free_list());
- } else {
- static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
- const auto it = begin();
- return (it == end()) ? null : *it;
- }
- }
-
- /**
- * @brief Returns the last entity of the view, if any.
- * @return The last entity of the view if one exists, the null entity
- * otherwise.
- */
- [[nodiscard]] entity_type back() const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
- return empty() ? null : *leading->rbegin();
- } else {
- static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy");
-
- if(leading) {
- auto it = leading->rbegin();
- const auto last = leading->rend();
- for(; (it != last) && (*it == tombstone); ++it) {}
- return it == last ? null : *it;
- }
-
- return null;
- }
- }
-
- /**
- * @brief Finds an entity.
- * @param entt A valid identifier.
- * @return An iterator to the given entity if it's found, past the end
- * iterator otherwise.
- */
- [[nodiscard]] iterator find(const entity_type entt) const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop) {
- return leading ? leading->find(entt) : iterator{};
- } else if constexpr(Policy == deletion_policy::swap_only) {
- const auto it = leading ? leading->find(entt) : iterator{};
- return leading && (static_cast<size_type>(it.index()) < leading->free_list()) ? it : iterator{};
- } else {
- const auto it = leading ? leading->find(entt) : typename common_type::iterator{};
- return iterator{it, {leading}, {}, 0u};
- }
- }
-
- /**
- * @brief Checks if a view is fully initialized.
- * @return True if the view is fully initialized, false otherwise.
- */
- [[nodiscard]] explicit operator bool() const noexcept {
- return (leading != nullptr);
- }
-
- /**
- * @brief Checks if a view contains an entity.
- * @param entt A valid identifier.
- * @return True if the view contains the given entity, false otherwise.
- */
- [[nodiscard]] bool contains(const entity_type entt) const noexcept {
- if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::in_place) {
- return leading && leading->contains(entt);
- } else {
- static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy");
- return leading && leading->contains(entt) && (leading->index(entt) < leading->free_list());
- }
- }
-
-private:
- const common_type *leading{};
-};
-
-/**
- * @brief Storage view specialization.
- *
- * This specialization offers a boost in terms of performance. It can access the
- * underlying data structure directly and avoid superfluous checks.
- *
- * @sa basic_view
- *
- * @tparam Get Type of storage iterated by the view.
- */
-template<typename Get>
-class basic_view<get_t<Get>, exclude_t<>>
- : public basic_storage_view<typename Get::base_type, Get::storage_policy> {
- using base_type = basic_storage_view<typename Get::base_type, Get::storage_policy>;
-
-public:
- /*! @brief Common type among all storage types. */
- using common_type = typename base_type::common_type;
- /*! @brief Underlying entity identifier. */
- using entity_type = typename base_type::entity_type;
- /*! @brief Unsigned integer type. */
- using size_type = typename base_type::size_type;
- /*! @brief Random access iterator type. */
- using iterator = typename base_type::iterator;
- /*! @brief Reverse iterator type. */
- using reverse_iterator = typename base_type::reverse_iterator;
- /*! @brief Iterable view type. */
- using iterable = std::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>, decltype(std::declval<Get>().each())>;
-
- /*! @brief Default constructor to use to create empty, invalid views. */
- basic_view() noexcept
- : base_type{} {}
-
- /**
- * @brief Constructs a view from a storage class.
- * @param value The storage for the type to iterate.
- */
- basic_view(Get &value) noexcept
- : base_type{&value} {
- }
-
- /**
- * @brief Constructs a view from a storage class.
- * @param value The storage for the type to iterate.
- */
- basic_view(std::tuple<Get &> value, std::tuple<> = {}) noexcept
- : basic_view{std::get<0>(value)} {}
-
- /**
- * @brief Returns the storage for a given element type, if any.
- * @tparam Type Type of element of which to return the storage.
- * @return The storage for the given element type.
- */
- template<typename Type = typename Get::element_type>
- [[nodiscard]] auto *storage() const noexcept {
- static_assert(std::is_same_v<std::remove_const_t<Type>, typename Get::element_type>, "Invalid element type");
- return storage<0>();
- }
-
- /**
- * @brief Returns the storage for a given index, if any.
- * @tparam Index Index of the storage to return.
- * @return The storage for the given index.
- */
- template<std::size_t Index>
- [[nodiscard]] auto *storage() const noexcept {
- static_assert(Index == 0u, "Index out of bounds");
- return static_cast<Get *>(const_cast<constness_as_t<common_type, Get> *>(base_type::handle()));
- }
-
- /**
- * @brief Assigns a storage to a view.
- * @param elem A storage to assign to the view.
- */
- void storage(Get &elem) noexcept {
- storage<0>(elem);
- }
-
- /**
- * @brief Assigns a storage to a view.
- * @tparam Index Index of the storage to assign to the view.
- * @param elem A storage to assign to the view.
- */
- template<std::size_t Index>
- void storage(Get &elem) noexcept {
- static_assert(Index == 0u, "Index out of bounds");
- *this = basic_view{elem};
- }
-
- /**
- * @brief Returns a pointer to the underlying storage.
- * @return A pointer to the underlying storage.
- */
- [[nodiscard]] Get *operator->() const noexcept {
- return storage();
- }
-
- /**
- * @brief Returns the element assigned to the given entity.
- * @param entt A valid identifier.
- * @return The element assigned to the given entity.
- */
- [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
- return storage()->get(entt);
- }
-
- /**
- * @brief Returns the element assigned to the given entity.
- * @tparam Elem Type of the element to get.
- * @param entt A valid identifier.
- * @return The element assigned to the entity.
- */
- template<typename Elem>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- static_assert(std::is_same_v<std::remove_const_t<Elem>, typename Get::element_type>, "Invalid element type");
- return get<0>(entt);
- }
-
- /**
- * @brief Returns the element assigned to the given entity.
- * @tparam Index Index of the element to get.
- * @param entt A valid identifier.
- * @return The element assigned to the entity.
- */
- template<std::size_t... Index>
- [[nodiscard]] decltype(auto) get(const entity_type entt) const {
- if constexpr(sizeof...(Index) == 0) {
- return storage()->get_as_tuple(entt);
- } else {
- return storage<Index...>()->get(entt);
- }
- }
-
- /**
- * @brief Iterates entities and elements and applies the given function
- * object to them.
- *
- * The signature of the function must be equivalent to one of the following
- * (non-empty types only, constness as requested):
- *
- * @code{.cpp}
- * void(const entity_type, Type &);
- * void(typename Type &);
- * @endcode
- *
- * @tparam Func Type of the function object to invoke.
- * @param func A valid function object.
- */
- template<typename Func>
- void each(Func func) const {
- if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
- for(const auto pack: each()) {
- std::apply(func, pack);
- }
- } else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
- if constexpr(std::is_void_v<typename Get::value_type>) {
- for(size_type pos = base_type::size(); pos; --pos) {
- func();
- }
- } else {
- if(const auto len = base_type::size(); len != 0u) {
- for(auto last = storage()->end(), first = last - len; first != last; ++first) {
- func(*first);
- }
- }
- }
- } else {
- static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
-
- for(const auto pack: each()) {
- std::apply([&func](const auto, auto &&...elem) { func(std::forward<decltype(elem)>(elem)...); }, pack);
- }
- }
- }
-
- /**
- * @brief Returns an iterable object to use to _visit_ a view.
- *
- * The iterable object returns a tuple that contains the current entity and
- * a reference to its element if it's a non-empty one. The _constness_ of
- * the element is as requested.
- *
- * @return An iterable object to use to _visit_ the view.
- */
- [[nodiscard]] iterable each() const noexcept {
- if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
- return base_type::handle() ? storage()->each() : iterable{};
- } else {
- static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
- return iterable{base_type::begin(), base_type::end()};
- }
- }
-
- /**
- * @brief Combines two views in a _more specific_ one.
- * @tparam OGet Element list of the view to combine with.
- * @tparam OExclude Filter list of the view to combine with.
- * @param other The view to combine with.
- * @return A more specific view.
- */
- template<typename... OGet, typename... OExclude>
- [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
- return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
- *this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
- }
-};
-
-/**
- * @brief Deduction guide.
- * @tparam Type Type of storage classes used to create the view.
- * @param storage The storage for the types to iterate.
- */
-template<typename... Type>
-basic_view(Type &...storage) -> basic_view<get_t<Type...>, exclude_t<>>;
-
-/**
- * @brief Deduction guide.
- * @tparam Get Types of elements iterated by the view.
- * @tparam Exclude Types of elements used to filter the view.
- */
-template<typename... Get, typename... Exclude>
-basic_view(std::tuple<Get &...>, std::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
-
-} // namespace entt
-
-#endif
|
