From 61e5bcef2629e2d68b805a956a96fff264d4f74d Mon Sep 17 00:00:00 2001 From: untodesu Date: Sat, 28 Jun 2025 01:59:49 +0500 Subject: 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) --- deps/include/entt/entity/component.hpp | 56 -- deps/include/entt/entity/entity.hpp | 388 --------- deps/include/entt/entity/fwd.hpp | 267 ------ deps/include/entt/entity/group.hpp | 1057 ------------------------ deps/include/entt/entity/handle.hpp | 431 ---------- deps/include/entt/entity/helper.hpp | 255 ------ deps/include/entt/entity/mixin.hpp | 318 -------- deps/include/entt/entity/observer.hpp | 438 ---------- deps/include/entt/entity/organizer.hpp | 424 ---------- deps/include/entt/entity/ranges.hpp | 26 - deps/include/entt/entity/registry.hpp | 1222 ---------------------------- deps/include/entt/entity/runtime_view.hpp | 318 -------- deps/include/entt/entity/snapshot.hpp | 509 ------------ deps/include/entt/entity/sparse_set.hpp | 1068 ------------------------ deps/include/entt/entity/storage.hpp | 1205 --------------------------- deps/include/entt/entity/storage_mixin.hpp | 236 ------ deps/include/entt/entity/view.hpp | 1076 ------------------------ 17 files changed, 9294 deletions(-) delete mode 100644 deps/include/entt/entity/component.hpp delete mode 100644 deps/include/entt/entity/entity.hpp delete mode 100644 deps/include/entt/entity/fwd.hpp delete mode 100644 deps/include/entt/entity/group.hpp delete mode 100644 deps/include/entt/entity/handle.hpp delete mode 100644 deps/include/entt/entity/helper.hpp delete mode 100644 deps/include/entt/entity/mixin.hpp delete mode 100644 deps/include/entt/entity/observer.hpp delete mode 100644 deps/include/entt/entity/organizer.hpp delete mode 100644 deps/include/entt/entity/ranges.hpp delete mode 100644 deps/include/entt/entity/registry.hpp delete mode 100644 deps/include/entt/entity/runtime_view.hpp delete mode 100644 deps/include/entt/entity/snapshot.hpp delete mode 100644 deps/include/entt/entity/sparse_set.hpp delete mode 100644 deps/include/entt/entity/storage.hpp delete mode 100644 deps/include/entt/entity/storage_mixin.hpp delete mode 100644 deps/include/entt/entity/view.hpp (limited to 'deps/include/entt/entity') 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 -#include -#include "../config/config.h" -#include "fwd.hpp" - -namespace entt { - -/*! @cond TURN_OFF_DOXYGEN */ -namespace internal { - -template -struct in_place_delete: std::bool_constant && std::is_move_assignable_v)> {}; - -template<> -struct in_place_delete: std::false_type {}; - -template -struct in_place_delete> - : std::true_type {}; - -template -struct page_size: std::integral_constant * ENTT_PACKED_PAGE> {}; - -template<> -struct page_size: std::integral_constant {}; - -template -struct page_size> - : std::integral_constant {}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Common way to access various properties of components. - * @tparam Type Type of component. - */ -template -struct component_traits { - static_assert(std::is_same_v, 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::value; - /*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */ - static constexpr std::size_t page_size = internal::page_size::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 -#include -#include -#include "../config/config.h" -#include "../core/bit.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond TURN_OFF_DOXYGEN */ -namespace internal { - -template -struct entt_traits; - -template -struct entt_traits>> - : entt_traits> { - using value_type = Type; -}; - -template -struct entt_traits>> - : entt_traits { - using value_type = Type; -}; - -template<> -struct entt_traits { - 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 { - 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 -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(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(to_integral(value) >> length) & version_mask); - } - } - - /** - * @brief Returns the successor of a given identifier. - * @param value The identifier of which to return the successor. - * @return The successor of the given identifier. - */ - [[nodiscard]] static constexpr value_type next(const value_type value) noexcept { - const auto vers = to_version(value) + 1; - return construct(to_integral(value), static_cast(vers + (vers == version_mask))); - } - - /** - * @brief Constructs an identifier from its parts. - * - * If the version part is not provided, a tombstone is returned.
- * If the entity part is not provided, a null identifier is returned. - * - * @param entity The entity part of the identifier. - * @param version The version part of the identifier. - * @return A properly constructed identifier. - */ - [[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept { - if constexpr(Traits::version_mask == 0u) { - return value_type{entity & entity_mask}; - } else { - return value_type{(entity & entity_mask) | (static_cast(version & version_mask) << length)}; - } - } - - /** - * @brief Combines two identifiers in a single one. - * - * The returned identifier is a copy of the first element except for its - * version, which is taken from the second element. - * - * @param lhs The identifier from which to take the entity part. - * @param rhs The identifier from which to take the version part. - * @return A properly constructed identifier. - */ - [[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept { - if constexpr(Traits::version_mask == 0u) { - return value_type{lhs & entity_mask}; - } else { - return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))}; - } - } -}; - -/** - * @brief Entity traits. - * @tparam Type Type of identifier. - */ -template -struct entt_traits: basic_entt_traits> { - /*! @brief Base type. */ - using base_type = basic_entt_traits>; - /*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */ - static constexpr 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 -[[nodiscard]] constexpr typename entt_traits::entity_type to_integral(const Entity value) noexcept { - return entt_traits::to_integral(value); -} - -/** - * @brief Returns the entity part once converted to the underlying type. - * @tparam Entity The value type. - * @param value The value to convert. - * @return The integral representation of the entity part. - */ -template -[[nodiscard]] constexpr typename entt_traits::entity_type to_entity(const Entity value) noexcept { - return entt_traits::to_entity(value); -} - -/** - * @brief Returns the version part once converted to the underlying type. - * @tparam Entity The value type. - * @param value The value to convert. - * @return The integral representation of the version part. - */ -template -[[nodiscard]] constexpr typename entt_traits::version_type to_version(const Entity value) noexcept { - return entt_traits::to_version(value); -} - -/*! @brief Null object for all identifiers. */ -struct null_t { - /** - * @brief Converts the null object to identifiers of any type. - * @tparam Entity Type of identifier. - * @return The null representation for the given type. - */ - template - [[nodiscard]] constexpr operator Entity() const noexcept { - using traits_type = entt_traits; - 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 - [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { - using traits_type = entt_traits; - return traits_type::to_entity(entity) == traits_type::to_entity(*this); - } - - /** - * @brief 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 - [[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 -[[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 -[[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 - [[nodiscard]] constexpr operator Entity() const noexcept { - using traits_type = entt_traits; - 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 - [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { - using traits_type = entt_traits; - - if constexpr(traits_type::version_mask == 0u) { - return false; - } else { - return (traits_type::to_version(entity) == traits_type::to_version(*this)); - } - } - - /** - * @brief 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 - [[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 -[[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 -[[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 -#include -#include -#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> -class basic_sparse_set; - -template, typename = void> -class basic_storage; - -template -class basic_sigh_mixin; - -template> -class basic_registry; - -template -class basic_view; - -template> -class basic_runtime_view; - -template -class basic_group; - -template> -class basic_observer; - -template -class basic_organizer; - -template -class basic_handle; - -template -class basic_snapshot; - -template -class basic_snapshot_loader; - -template -class basic_continuous_loader; - -/*! @brief Alias declaration for the most common use case. */ -using sparse_set = basic_sparse_set<>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Element type. - */ -template -using storage = basic_storage; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Underlying storage type. - */ -template -using sigh_mixin = basic_sigh_mixin>; - -/*! @brief Alias declaration for the most common use case. */ -using registry = basic_registry<>; - -/*! @brief Alias declaration for the most common use case. */ -using observer = basic_observer; - -/*! @brief Alias declaration for the most common use case. */ -using organizer = basic_organizer; - -/*! @brief Alias declaration for the most common use case. */ -using handle = basic_handle; - -/*! @brief Alias declaration for the most common use case. */ -using const_handle = basic_handle; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using handle_view = basic_handle; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using const_handle_view = basic_handle; - -/*! @brief Alias declaration for the most common use case. */ -using snapshot = basic_snapshot; - -/*! @brief Alias declaration for the most common use case. */ -using snapshot_loader = basic_snapshot_loader; - -/*! @brief Alias declaration for the most common use case. */ -using continuous_loader = basic_continuous_loader; - -/*! @brief Alias declaration for the most common use case. */ -using runtime_view = basic_runtime_view; - -/*! @brief Alias declaration for the most common use case. */ -using const_runtime_view = basic_runtime_view; - -/** - * @brief Alias for exclusion lists. - * @tparam Type List of types. - */ -template -struct exclude_t final: type_list { - /*! @brief Default constructor. */ - explicit constexpr exclude_t() = default; -}; - -/** - * @brief Variable template for exclusion lists. - * @tparam Type List of types. - */ -template -inline constexpr exclude_t exclude{}; - -/** - * @brief Alias for lists of observed elements. - * @tparam Type List of types. - */ -template -struct get_t final: type_list { - /*! @brief Default constructor. */ - explicit constexpr get_t() = default; -}; - -/** - * @brief Variable template for lists of observed elements. - * @tparam Type List of types. - */ -template -inline constexpr get_t get{}; - -/** - * @brief Alias for lists of owned elements. - * @tparam Type List of types. - */ -template -struct owned_t final: type_list { - /*! @brief Default constructor. */ - explicit constexpr owned_t() = default; -}; - -/** - * @brief Variable template for lists of owned elements. - * @tparam Type List of types. - */ -template -inline constexpr owned_t owned{}; - -/** - * @brief Applies a given _function_ to a get list and generate a new list. - * @tparam Type Types provided by the get list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting get list after applying the transform function. */ - using type = get_t::type...>; -}; - -/** - * @brief Applies a given _function_ to an exclude list and generate a new list. - * @tparam Type Types provided by the exclude list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting exclude list after applying the transform function. */ - using type = exclude_t::type...>; -}; - -/** - * @brief Applies a given _function_ to an owned list and generate a new list. - * @tparam Type Types provided by the owned list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting owned list after applying the transform function. */ - using type = owned_t::type...>; -}; - -/** - * @brief Provides a common way to define storage types. - * @tparam Type Storage value type. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template, typename = void> -struct storage_type { - /*! @brief Type-to-storage conversion result. */ - using type = ENTT_STORAGE(sigh_mixin, basic_storage); -}; - -/** - * @brief Helper type. - * @tparam Args Arguments to forward. - */ -template -using storage_type_t = typename storage_type::type; - -/** - * Type-to-storage conversion utility that preserves constness. - * @tparam Type Storage value type, eventually const. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template>> -struct storage_for { - /*! @brief Type-to-storage conversion result. */ - using type = constness_as_t, Entity, Allocator>, Type>; -}; - -/** - * @brief Helper type. - * @tparam Args Arguments to forward. - */ -template -using storage_for_t = typename storage_for::type; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Get Types of storage iterated by the view. - * @tparam Exclude Types of storage used to filter the view. - */ -template> -using view = basic_view, type_list_transform_t>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Owned Types of storage _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - */ -template -using group = basic_group, type_list_transform_t, type_list_transform_t>; - -} // 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 -#include -#include -#include -#include -#include -#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 -class extended_group_iterator; - -template -class extended_group_iterator, get_t> { - template - [[nodiscard]] auto index_to_element([[maybe_unused]] Type &cpool) const { - if constexpr(std::is_void_v) { - 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()), std::declval().get_as_tuple({})..., std::declval().get_as_tuple({})...)); - using pointer = input_iterator_pointer; - 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 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(pools))..., std::get(pools)->get_as_tuple(*it)...); - } - - [[nodiscard]] pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr iterator_type base() const noexcept { - return it; - } - - template - friend constexpr bool operator==(const extended_group_iterator &, const extended_group_iterator &) noexcept; - -private: - It it; - std::tuple pools; -}; - -template -[[nodiscard]] constexpr bool operator==(const extended_group_iterator &lhs, const extended_group_iterator &rhs) noexcept { - return lhs.it == rhs.it; -} - -template -[[nodiscard]] constexpr bool operator!=(const extended_group_iterator &lhs, const extended_group_iterator &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 -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 - group_handler(std::tuple ogpool, std::tuple epool) - : pools{std::apply([](auto &&...cpool) { return std::array{&cpool...}; }, ogpool)}, - filter{std::apply([](auto &&...cpool) { return std::array{&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 - [[nodiscard]] common_type *storage() const noexcept { - if constexpr(Index < (Owned + Get)) { - return pools[Index]; - } else { - return filter[Index - (Owned + Get)]; - } - } - -private: - std::array pools; - std::array filter; - std::size_t len{}; -}; - -template -class group_handler 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 - group_handler(const Allocator &allocator, std::tuple gpool, std::tuple epool) - : pools{std::apply([](auto &&...cpool) { return std::array{&cpool...}; }, gpool)}, - filter{std::apply([](auto &&...cpool) { return std::array{&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 - [[nodiscard]] common_type *storage() const noexcept { - if constexpr(Index < Get) { - return pools[Index]; - } else { - return filter[Index - Get]; - } - } - -private: - std::array pools; - std::array filter; - common_type elem; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Group. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class basic_group; - -/** - * @brief Non-owning group. - * - * A non-owning group returns all entities and only the entities that are at - * least in the given storage. Moreover, it's guaranteed that the entity list is - * tightly packed in memory for fast iterations. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New elements are added to the storage. - * * The entity currently pointed is modified (for example, elements are added - * or removed from it). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the group in any way - * invalidates all the iterators. - * - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - */ -template -class basic_group, get_t, exclude_t> { - using base_type = std::common_type_t; - using underlying_type = typename base_type::entity_type; - - template - static constexpr std::size_t index_of = type_list_index_v, type_list>; - - template - [[nodiscard]] auto pools_for(std::index_sequence) const noexcept { - using return_type = std::tuple; - return descriptor ? return_type{static_cast(descriptor->template storage())...} : return_type{}; - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = underlying_type; - /*! @brief Unsigned integer type. */ - using size_type = 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, get_t>>; - /*! @brief Group handler type. */ - using handler = internal::group_handler; - - /** - * @brief Group opaque identifier. - * @return Group opaque identifier. - */ - static id_type group_id() noexcept { - return type_hash, get_t...>, exclude_t...>>>::value(); - } - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() noexcept - : descriptor{} {} - - /** - * @brief Constructs a group from a set of storage classes. - * @param ref A reference to a group handler. - */ - basic_group(handler &ref) noexcept - : descriptor{&ref} {} - - /** - * @brief Returns the leading storage of a group. - * @return The leading storage of the group. - */ - [[nodiscard]] const common_type &handle() const noexcept { - return descriptor->handle(); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @return The storage for the given element type. - */ - template - [[nodiscard]] auto *storage() const noexcept { - return storage>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - using type = type_list_element_t>; - return *this ? static_cast(descriptor->template storage()) : nullptr; - } - - /** - * @brief Returns the number of entities that are part of the group. - * @return Number of entities that are part of the group. - */ - [[nodiscard]] size_type size() const noexcept { - return *this ? handle().size() : size_type{}; - } - - /** - * @brief Returns the number of elements that a group has currently - * allocated space for. - * @return Capacity of the group. - */ - [[nodiscard]] size_type capacity() const noexcept { - return *this ? handle().capacity() : size_type{}; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - if(*this) { - descriptor->handle().shrink_to_fit(); - } - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return !*this || handle().empty(); - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * If the group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const noexcept { - return *this ? handle().begin() : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the group. - * @return An iterator to the entity following the last entity of the - * group. - */ - [[nodiscard]] iterator end() const noexcept { - return *this ? handle().end() : iterator{}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed group. - * - * If the group is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed group. - */ - [[nodiscard]] reverse_iterator rbegin() const noexcept { - return *this ? handle().rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * group. - * @return An iterator to the entity following the last entity of the - * reversed group. - */ - [[nodiscard]] reverse_iterator rend() const noexcept { - return *this ? handle().rend() : reverse_iterator{}; - } - - /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const noexcept { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the group, if any. - * @return The last entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const noexcept { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const noexcept { - return *this ? handle().find(entt) : iterator{}; - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[pos]; - } - - /** - * @brief Checks if a group is properly initialized. - * @return True if the group is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return descriptor != nullptr; - } - - /** - * @brief Checks if a group contains an entity. - * @param entt A valid identifier. - * @return True if the group contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const noexcept { - return *this && handle().contains(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Type Type of the element to get. - * @tparam Other Other types of elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - return get, index_of...>(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Index Indexes of the elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - const auto cpools = pools_for(std::index_sequence_for{}); - - 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(cpools)->get(entt), ...); - } else { - return std::tuple_cat(std::get(cpools)->get_as_tuple(entt)...); - } - } - - /** - * @brief Iterates entities and elements and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty elements. The - * _constness_ of the elements is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entt: *this) { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt))); - } else { - std::apply(func, get(entt)); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ 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{}); - 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, std::tuple); - * bool(const Type &..., const Type &...); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Type` are such that they are iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Type Optional type of element to compare. - * @tparam Other Other optional types of elements to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { - sort, index_of...>(std::move(compare), std::move(algo), std::forward(args)...); - } - - /** - * @brief Sort a group according to the given comparison function. - * - * @sa sort - * - * @tparam Index Optional indexes of elements to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { - if(*this) { - if constexpr(sizeof...(Index) == 0) { - static_assert(std::is_invocable_v, "Invalid comparison function"); - descriptor->handle().sort(std::move(compare), std::move(algo), std::forward(args)...); - } else { - auto comp = [&compare, cpools = pools_for(std::index_sequence_for{})](const entity_type lhs, const entity_type rhs) { - if constexpr(sizeof...(Index) == 1) { - return compare((std::get(cpools)->get(lhs), ...), (std::get(cpools)->get(rhs), ...)); - } else { - return compare(std::forward_as_tuple(std::get(cpools)->get(lhs)...), std::forward_as_tuple(std::get(cpools)->get(rhs)...)); - } - }; - - descriptor->handle().sort(std::move(comp), std::move(algo), std::forward(args)...); - } - } - } - - /** - * @brief Sort entities according to their order in a range. - * - * The shared pool of entities and thus its order is affected by the changes - * to each and every pool that it tracks. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void 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 -class basic_group, get_t, exclude_t> { - static_assert(((Owned::storage_policy != deletion_policy::in_place) && ...), "Groups do not support in-place delete"); - - using base_type = std::common_type_t; - using underlying_type = typename base_type::entity_type; - - template - static constexpr std::size_t index_of = type_list_index_v, type_list>; - - template - [[nodiscard]] auto pools_for(std::index_sequence, std::index_sequence) const noexcept { - using return_type = std::tuple; - return descriptor ? return_type{static_cast(descriptor->template storage())..., static_cast(descriptor->template storage())...} : return_type{}; - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = underlying_type; - /*! @brief Unsigned integer type. */ - using size_type = 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, get_t>>; - /*! @brief Group handler type. */ - using handler = internal::group_handler; - - /** - * @brief Group opaque identifier. - * @return Group opaque identifier. - */ - static id_type group_id() noexcept { - return type_hash...>, get_t...>, exclude_t...>>>::value(); - } - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() noexcept - : descriptor{} {} - - /** - * @brief Constructs a group from a set of storage classes. - * @param ref A reference to a group handler. - */ - basic_group(handler &ref) noexcept - : descriptor{&ref} {} - - /** - * @brief Returns the leading storage of a group. - * @return The leading storage of the group. - */ - [[nodiscard]] const common_type &handle() const noexcept { - return *storage<0>(); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @return The storage for the given element type. - */ - template - [[nodiscard]] auto *storage() const noexcept { - return storage>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - using type = type_list_element_t>; - return *this ? static_cast(descriptor->template storage()) : nullptr; - } - - /** - * @brief Returns the number of entities that that are part of the group. - * @return Number of entities that that are part of the group. - */ - [[nodiscard]] size_type size() const noexcept { - return *this ? descriptor->length() : size_type{}; - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return !*this || !descriptor->length(); - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * If the group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const noexcept { - return *this ? (handle().end() - 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 - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - return get, index_of...>(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Index Indexes of the elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - const auto cpools = pools_for(std::index_sequence_for{}, std::index_sequence_for{}); - - 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(cpools)->get(entt), ...); - } else { - return std::tuple_cat(std::get(cpools)->get_as_tuple(entt)...); - } - } - - /** - * @brief Iterates entities and elements and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to non-empty elements. The - * _constness_ of the elements is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(auto args: each()) { - if constexpr(is_applicable_v{}, std::declval().get({})))>) { - std::apply(func, args); - } else { - std::apply([&func](auto, auto &&...less) { func(std::forward(less)...); }, args); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ 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{}, std::index_sequence_for{}); - return iterable{{begin(), cpools}, {end(), cpools}}; - } - - /** - * @brief Sort a group according to the given comparison function. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to one of the following: - * - * @code{.cpp} - * bool(std::tuple, std::tuple); - * bool(const Type &, const Type &); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Type` are either owned types or not but still such that they are - * iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Type Optional type of element to compare. - * @tparam Other Other optional types of elements to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const { - sort, index_of...>(std::move(compare), std::move(algo), std::forward(args)...); - } - - /** - * @brief Sort a group according to the given comparison function. - * - * @sa sort - * - * @tparam Index Optional indexes of elements to compare. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const { - const auto cpools = pools_for(std::index_sequence_for{}, std::index_sequence_for{}); - - if constexpr(sizeof...(Index) == 0) { - static_assert(std::is_invocable_v, "Invalid comparison function"); - storage<0>()->sort_n(descriptor->length(), std::move(compare), std::move(algo), std::forward(args)...); - } else { - auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) { - if constexpr(sizeof...(Index) == 1) { - return compare((std::get(cpools)->get(lhs), ...), (std::get(cpools)->get(rhs), ...)); - } else { - return compare(std::forward_as_tuple(std::get(cpools)->get(lhs)...), std::forward_as_tuple(std::get(cpools)->get(rhs)...)); - } - }; - - storage<0>()->sort_n(descriptor->length(), std::move(comp), std::move(algo), std::forward(args)...); - } - - auto cb = [this](auto *head, auto *...other) { - for(auto next = descriptor->length(); next; --next) { - const auto pos = next - 1; - [[maybe_unused]] const auto entt = head->data()[pos]; - (other->swap_elements(other->data()[pos], entt), ...); - } - }; - - 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 -#include -#include -#include -#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 -class handle_storage_iterator final { - template - friend class handle_storage_iterator; - - using underlying_type = std::remove_reference_t; - using entity_type = typename underlying_type::entity_type; - -public: - using value_type = typename std::iterator_traits::value_type; - using pointer = input_iterator_pointer; - 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 - friend constexpr bool operator==(const handle_storage_iterator &, const handle_storage_iterator &) noexcept; - -private: - entity_type entt; - It it; - It last; -}; - -template -[[nodiscard]] constexpr bool operator==(const handle_storage_iterator &lhs, const handle_storage_iterator &rhs) noexcept { - return lhs.it == rhs.it; -} - -template -[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator &lhs, const handle_storage_iterator &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 -class basic_handle { - using traits_type = entt_traits; - - [[nodiscard]] auto &owner_or_assert() const noexcept { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - return static_cast(*owner); - } - -public: - /*! @brief Type of registry accepted by the handle. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = 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().storage())::iterator>>; - - /*! @brief Constructs an invalid handle. */ - basic_handle() noexcept - : owner{}, - entt{null} {} - - /** - * @brief Constructs a handle from a given registry and entity. - * @param ref An instance of the registry class. - * @param value A valid identifier. - */ - basic_handle(registry_type &ref, entity_type value) noexcept - : owner{&ref}, - entt{value} {} - - /** - * @brief Returns an iterable object to use to _visit_ a handle. - * - * The iterable object returns a pair that contains the name and a reference - * to the current storage.
- * Returned storage are those that contain the entity associated with the - * handle. - * - * @return An iterable object to use to _visit_ the handle. - */ - [[nodiscard]] iterable storage() const noexcept { - auto underlying = owner_or_assert().storage(); - return iterable{{entt, underlying.begin(), underlying.end()}, {entt, underlying.end(), underlying.end()}}; - } - - /*! @copydoc valid */ - [[nodiscard]] explicit operator bool() const noexcept { - return owner && owner->valid(entt); - } - - /** - * @brief Checks if a handle refers to 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(*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 - // NOLINTNEXTLINE(modernize-use-nodiscard) - decltype(auto) emplace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v), "Invalid type"); - return owner_or_assert().template emplace(entt, std::forward(args)...); - } - - /** - * @brief Assigns or replaces the given element for a handle. - * @tparam Type Type of element to assign or replace. - * @tparam Args Types of arguments to use to construct the element. - * @param args Parameters to use to initialize the element. - * @return A reference to the newly created element. - */ - template - decltype(auto) emplace_or_replace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v), "Invalid type"); - return owner_or_assert().template emplace_or_replace(entt, std::forward(args)...); - } - - /** - * @brief Patches the given element for a handle. - * @tparam Type Type of element to patch. - * @tparam Func Types of the function objects to invoke. - * @param func Valid function objects. - * @return A reference to the patched element. - */ - template - decltype(auto) patch(Func &&...func) const { - static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v), "Invalid type"); - return owner_or_assert().template patch(entt, std::forward(func)...); - } - - /** - * @brief Replaces the given element for a handle. - * @tparam Type Type of element to replace. - * @tparam Args Types of arguments to use to construct the element. - * @param args Parameters to use to initialize the element. - * @return A reference to the element being replaced. - */ - template - decltype(auto) replace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v), "Invalid type"); - return owner_or_assert().template replace(entt, std::forward(args)...); - } - - /** - * @brief Removes the given elements from a handle. - * @tparam Type Types of elements to remove. - * @return The number of elements actually removed. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - size_type remove() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - return owner_or_assert().template remove(entt); - } - - /** - * @brief Erases the given elements from a handle. - * @tparam Type Types of elements to erase. - */ - template - void erase() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - owner_or_assert().template erase(entt); - } - - /** - * @brief Checks if a handle has all the given elements. - * @tparam Type Elements for which to perform the check. - * @return True if the handle has all the elements, false otherwise. - */ - template - [[nodiscard]] decltype(auto) all_of() const { - return owner_or_assert().template all_of(entt); - } - - /** - * @brief Checks if a handle has at least one of the given elements. - * @tparam Type Elements for which to perform the check. - * @return True if the handle has at least one of the given elements, - * false otherwise. - */ - template - [[nodiscard]] decltype(auto) any_of() const { - return owner_or_assert().template any_of(entt); - } - - /** - * @brief Returns references to the given elements for a handle. - * @tparam Type Types of elements to get. - * @return References to the elements owned by the handle. - */ - template - [[nodiscard]] decltype(auto) get() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - return owner_or_assert().template get(entt); - } - - /** - * @brief Returns a reference to the given element for a handle. - * @tparam Type Type of element to get. - * @tparam Args Types of arguments to use to construct the element. - * @param args Parameters to use to initialize the element. - * @return Reference to the element owned by the handle. - */ - template - [[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v), "Invalid type"); - return owner_or_assert().template get_or_emplace(entt, std::forward(args)...); - } - - /** - * @brief Returns pointers to the given elements for a handle. - * @tparam Type Types of elements to get. - * @return Pointers to the elements owned by the handle. - */ - template - [[nodiscard]] auto try_get() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - return owner_or_assert().template try_get(entt); - } - - /** - * @brief Checks if a handle has elements assigned. - * @return True if the handle has no elements assigned, false otherwise. - */ - [[nodiscard]] bool orphan() const { - return owner_or_assert().orphan(entt); - } - - /** - * @brief Returns a const handle from a non-const one. - * @tparam Other A valid entity type. - * @tparam Args Scope of the handle to construct. - * @return A const handle referring to the same registry and the same - * entity. - */ - template - operator basic_handle() const noexcept { - static_assert(std::is_same_v || std::is_same_v, Registry>, "Invalid conversion between different handles"); - static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v, Args>))), "Invalid conversion between different handles"); - return owner ? basic_handle{*owner, entt} : basic_handle{}; - } - -private: - registry_type *owner; - entity_type entt; -}; - -/** - * @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 -[[nodiscard]] bool operator==(const basic_handle &lhs, const basic_handle &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 -[[nodiscard]] bool operator!=(const basic_handle &lhs, const basic_handle &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 -[[nodiscard]] constexpr bool operator==(const basic_handle &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 -[[nodiscard]] constexpr bool operator==(const null_t lhs, const basic_handle &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 -[[nodiscard]] constexpr bool operator!=(const basic_handle &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 -[[nodiscard]] constexpr bool operator!=(const null_t lhs, const basic_handle &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 -#include -#include -#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 -class as_view { - template - [[nodiscard]] auto dispatch(get_t, exclude_t) const { - return reg.template view...>(exclude_t...>{}); - } - -public: - /*! @brief Type of registry to convert. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = 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 - operator basic_view() const { - return dispatch(Get{}, Exclude{}); - } - -private: - registry_type ® -}; - -/** - * @brief Converts a registry to a group. - * @tparam Registry Basic registry type. - */ -template -class as_group { - template - [[nodiscard]] auto dispatch(owned_t, get_t, exclude_t) const { - if constexpr(std::is_const_v) { - return reg.template group_if_exists(get_t{}, exclude_t{}); - } else { - return reg.template group...>(get_t...>{}, exclude_t...>{}); - } - } - -public: - /*! @brief Type of registry to convert. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = 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 - operator basic_group() 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>> -void invoke(Registry ®, const typename Registry::entity_type entt) { - static_assert(std::is_member_function_pointer_v, "Invalid pointer to non-static member function"); - (reg.template get>(entt).*Member)(reg, entt); -} - -/** - * @brief Returns the entity associated with a given element. - * - * @warning - * Currently, this function only works correctly with the default storage as it - * makes assumptions about how the elements are laid out. - * - * @tparam Args Storage type template parameters. - * @param storage A storage that contains the given element. - * @param instance A valid element instance. - * @return The entity associated with the given element. - */ -template -typename basic_storage::entity_type to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) { - using traits_type = component_traits::value_type>; - static_assert(traits_type::page_size != 0u, "Unexpected page size"); - const typename basic_storage::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(traits_type::page_size)) { - return *(it + dist); - } - } - - return null; -} - -/*! @brief Primary template isn't defined on purpose. */ -template -struct sigh_helper; - -/** - * @brief Signal connection helper for registries. - * @tparam Registry Basic registry type. - */ -template -struct sigh_helper { - /*! @brief Registry type. */ - using registry_type = Registry; - - /** - * @brief Constructs a helper for a given registry. - * @param ref A valid reference to a registry. - */ - sigh_helper(registry_type &ref) - : bucket{&ref} {} - - /** - * @brief Binds a properly initialized helper to a given signal type. - * @tparam Type Type of signal to bind the helper to. - * @param id Optional name for the underlying storage to use. - * @return A helper for a given registry and signal type. - */ - template - auto with(const id_type id = type_hash::value()) noexcept { - return sigh_helper{*bucket, id}; - } - - /** - * @brief Returns a reference to the underlying registry. - * @return A reference to the underlying registry. - */ - [[nodiscard]] registry_type ®istry() noexcept { - return *bucket; - } - -private: - registry_type *bucket; -}; - -/** - * @brief Signal connection helper for registries. - * @tparam Registry Basic registry type. - * @tparam Type Type of signal to connect listeners to. - */ -template -struct sigh_helper final: sigh_helper { - /*! @brief Registry type. */ - using registry_type = Registry; - - /** - * @brief Constructs a helper for a given registry. - * @param ref A valid reference to a registry. - * @param id Optional name for the underlying storage to use. - */ - sigh_helper(registry_type &ref, const id_type id = type_hash::value()) - : sigh_helper{ref}, - name{id} {} - - /** - * @brief Forwards the call to `on_construct` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_construct(Args &&...args) { - this->registry().template on_construct(name).template connect(std::forward(args)...); - return *this; - } - - /** - * @brief Forwards the call to `on_update` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_update(Args &&...args) { - this->registry().template on_update(name).template connect(std::forward(args)...); - return *this; - } - - /** - * @brief Forwards the call to `on_destroy` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_destroy(Args &&...args) { - this->registry().template on_destroy(name).template connect(std::forward(args)...); - return *this; - } - -private: - id_type name; -}; - -/** - * @brief Deduction guide. - * @tparam Registry Basic registry type. - */ -template -sigh_helper(Registry &) -> sigh_helper; - -} // namespace entt - -#endif 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 -#include -#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); - * @endcode - * - * This applies to all signals made available. - * - * @tparam Type Underlying storage type. - * @tparam Registry Basic registry type. - */ -template -class basic_sigh_mixin final: public Type { - using underlying_type = Type; - using owner_type = Registry; - - using basic_registry_type = basic_registry; - using sigh_type = sigh; - using underlying_iterator = typename underlying_type::base_type::basic_iterator; - - static_assert(std::is_base_of_v, "Invalid registry type"); - - [[nodiscard]] auto &owner_or_assert() const noexcept { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - return static_cast(*owner); - } - -private: - void pop(underlying_iterator first, underlying_iterator last) final { - if(auto ® = owner_or_assert(); destruction.empty()) { - underlying_type::pop(first, last); - } else { - for(; first != last; ++first) { - const auto entt = *first; - destruction.publish(reg, entt); - const auto it = underlying_type::find(entt); - underlying_type::pop(it, it + 1u); - } - } - } - - void pop_all() final { - if(auto ® = owner_or_assert(); !destruction.empty()) { - if constexpr(std::is_same_v) { - for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) { - destruction.publish(reg, underlying_type::base_type::operator[](pos)); - } - } else { - for(auto entt: static_cast(*this)) { - if constexpr(underlying_type::storage_policy == deletion_policy::in_place) { - if(entt != tombstone) { - destruction.publish(reg, entt); - } - } else { - destruction.publish(reg, entt); - } - } - } - } - - underlying_type::pop_all(); - } - - underlying_iterator try_emplace(const 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.
- * Listeners are invoked after the object has been assigned to the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_construct() noexcept { - return sink{construction}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is explicitly updated.
- * Listeners are invoked after the object has been updated. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_update() noexcept { - return sink{update}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is removed from an entity and thus destroyed.
- * Listeners are invoked before the object has been removed from the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_destroy() noexcept { - return sink{destruction}; - } - - /** - * @brief Emplace elements into a storage. - * - * The behavior of this operation depends on the underlying storage type - * (for example, components vs entities).
- * 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).
- * 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 - decltype(auto) emplace(const entity_type hint, Args &&...args) { - if constexpr(std::is_same_v) { - const auto entt = underlying_type::emplace(hint, std::forward(args)...); - construction.publish(owner_or_assert(), entt); - return entt; - } else { - underlying_type::emplace(hint, std::forward(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 - decltype(auto) patch(const entity_type entt, Func &&...func) { - underlying_type::patch(entt, std::forward(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).
- * 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 - void insert(It first, It last, Args &&...args) { - auto from = underlying_type::size(); - underlying_type::insert(first, last, std::forward(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(&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 -#include -#include -#include -#include -#include "../core/type_traits.hpp" -#include "fwd.hpp" -#include "storage.hpp" - -namespace entt { - -/*! @brief Grouping matcher. */ -template -struct matcher {}; - -/** - * @brief Collector. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -struct basic_collector; - -/** - * @brief Collector. - * - * A collector contains a set of rules (literally, matchers) to use to track - * entities.
- * Its main purpose is to generate a descriptor that allows an observer to know - * how to connect to a registry. - */ -template<> -struct basic_collector<> { - /** - * @brief Adds a grouping matcher to the collector. - * @tparam AllOf Types of elements tracked by the matcher. - * @tparam NoneOf Types of elements used to filter out entities. - * @return The updated collector. - */ - template - static constexpr auto group(exclude_t = exclude_t{}) noexcept { - return basic_collector, type_list<>, type_list, 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 - static constexpr auto update() noexcept { - return basic_collector, type_list<>, AnyOf>>{}; - } -}; - -/** - * @brief Collector. - * @copydetails basic_collector<> - * @tparam Reject Untracked types used to filter out entities. - * @tparam Require Untracked types required by the matcher. - * @tparam Rule Specific details of the current matcher. - * @tparam Other Other matchers. - */ -template -struct basic_collector, type_list, Rule...>, Other...> { - /*! @brief Current matcher. */ - using current_type = matcher, type_list, Rule...>; - - /** - * @brief Adds a grouping matcher to the collector. - * @tparam AllOf Types of elements tracked by the matcher. - * @tparam NoneOf Types of elements used to filter out entities. - * @return The updated collector. - */ - template - static constexpr auto group(exclude_t = exclude_t{}) noexcept { - return basic_collector, type_list<>, type_list, 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 - static constexpr auto update() noexcept { - return basic_collector, 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 - static constexpr auto where(exclude_t = exclude_t{}) noexcept { - using extended_type = matcher, type_list, Rule...>; - return basic_collector{}; - } -}; - -/*! @brief Variable template used to ease the definition of collectors. */ -inline constexpr basic_collector<> collector{}; - -/** - * @brief Observer. - * - * An observer returns all the entities and only the entities that fit the - * requirements of at least one matcher. Moreover, it's guaranteed that the - * entity list is tightly packed in memory for fast iterations.
- * In general, observers don't stay true to the order of any set of 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.
- * 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 -class basic_observer { - using mask_type = std::uint64_t; - using storage_type = basic_storage::template rebind_alloc>; - - template - 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 - struct matcher_handler; - - template - struct matcher_handler, type_list, AnyOf>> { - template - static void maybe_valid_if(storage_type &storage, Registry &parent, const typename Registry::entity_type entt) { - if(parent.template all_of(entt) && !parent.template any_of(entt)) { - if(!storage.contains(entt)) { - storage.emplace(entt); - } - - storage.get(entt) |= (1 << Index); - } - } - - template - static void connect(storage_type &storage, Registry &parent) { - (parent.template on_destroy().template connect<&discard_if>(storage), ...); - (parent.template on_construct().template connect<&discard_if>(storage), ...); - parent.template on_update().template connect<&maybe_valid_if>(storage); - parent.template on_destroy().template connect<&discard_if>(storage); - } - - static void disconnect(storage_type &storage, Registry &parent) { - (parent.template on_destroy().disconnect(&storage), ...); - (parent.template on_construct().disconnect(&storage), ...); - parent.template on_update().disconnect(&storage); - parent.template on_destroy().disconnect(&storage); - } - }; - - template - struct matcher_handler, type_list, type_list, AllOf...>> { - template - 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(entt) && !parent.template any_of(entt); - } else { - guard = parent.template all_of(entt) && ((std::is_same_v || !parent.template any_of(entt)) && ...) && !parent.template any_of(entt); - } - - if(guard) { - if(!storage.contains(entt)) { - storage.emplace(entt); - } - - storage.get(entt) |= (1 << Index); - } - } - - template - static void connect(storage_type &storage, Registry &parent) { - (parent.template on_destroy().template connect<&discard_if>(storage), ...); - (parent.template on_construct().template connect<&discard_if>(storage), ...); - (parent.template on_construct().template connect<&maybe_valid_if>(storage), ...); - (parent.template on_destroy().template connect<&maybe_valid_if>(storage), ...); - (parent.template on_destroy().template connect<&discard_if>(storage), ...); - (parent.template on_construct().template connect<&discard_if>(storage), ...); - } - - static void disconnect(storage_type &storage, Registry &parent) { - (parent.template on_destroy().disconnect(&storage), ...); - (parent.template on_construct().disconnect(&storage), ...); - (parent.template on_construct().disconnect(&storage), ...); - (parent.template on_destroy().disconnect(&storage), ...); - (parent.template on_destroy().disconnect(&storage), ...); - (parent.template on_construct().disconnect(&storage), ...); - } - }; - - template - static void disconnect(Registry &parent, storage_type &storage) { - (matcher_handler::disconnect(storage, parent), ...); - } - - template - static void connect(Registry &parent, storage_type &storage, std::index_sequence) { - static_assert(sizeof...(Matcher) < std::numeric_limits::digits, "Too many matchers"); - (matcher_handler::template connect(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 - basic_observer(registry_type ®, basic_collector, const allocator_type &allocator = allocator_type{}) - : release{&basic_observer::disconnect}, - parent{®}, - storage{allocator} { - connect(reg, storage, std::index_sequence_for{}); - } - - /*! @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 - void connect(registry_type ®, basic_collector) { - disconnect(); - storage.clear(); - - parent = ® - release = &basic_observer::disconnect; - connect(reg, storage, std::index_sequence_for{}); - } - - /*! @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.
- * The signature of the function must be equivalent to the following form: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entity: *this) { - func(entity); - } - } - - /** - * @brief Iterates entities and applies the given function object to them, - * then clears the observer. - * - * @sa each - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) { - std::as_const(*this).each(std::move(func)); - clear(); - } - -private: - 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 -#include -#include -#include -#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 -struct is_view: std::false_type {}; - -template -struct is_view>: std::true_type {}; - -template -inline constexpr bool is_view_v = is_view::value; - -template -struct unpack_type { - using ro = std::conditional_t< - type_list_contains_v || (std::is_const_v && !type_list_contains_v>), - type_list>, - type_list<>>; - - using rw = std::conditional_t< - type_list_contains_v> || (!std::is_const_v && !type_list_contains_v), - type_list, - type_list<>>; -}; - -template -struct unpack_type, type_list> { - using ro = type_list<>; - using rw = type_list<>; -}; - -template -struct unpack_type, type_list> - : unpack_type, type_list> {}; - -template -struct unpack_type, exclude_t>, type_list> { - using ro = type_list_cat_t, typename unpack_type, type_list>::ro...>; - using rw = type_list_cat_t, type_list>::rw...>; -}; - -template -struct unpack_type, exclude_t>, type_list> - : unpack_type, exclude_t>, type_list> {}; - -template -struct resource_traits; - -template -struct resource_traits, type_list> { - using args = type_list...>; - using ro = type_list_cat_t>::ro..., typename unpack_type>::ro...>; - using rw = type_list_cat_t>::rw..., typename unpack_type>::rw...>; -}; - -template -resource_traits...>, type_list> free_function_to_resource_traits(Ret (*)(Args...)); - -template -resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (*)(Type &, Args...)); - -template -resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (Class::*)(Args...)); - -template -resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const); - -} // namespace internal -/*! @endcond */ - -/** - * @brief Utility class for creating a static task graph. - * - * This class offers minimal support (but sufficient in many cases) for creating - * an execution graph from functions and their requirements on resources.
- * Note that the resulting tasks aren't executed in any case. This isn't the - * goal of the tool. Instead, they are returned to the user in the form of a - * graph that allows for safe execution. - * - * @tparam Registry Basic registry type. - */ -template -class basic_organizer final { - using callback_type = void(const void *, Registry &); - using prepare_type = void(Registry &); - using dependency_type = 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 - [[nodiscard]] static decltype(auto) extract(Registry ®) { - if constexpr(std::is_same_v) { - return reg; - } else if constexpr(internal::is_view_v) { - return static_cast(as_view{reg}); - } else { - return reg.ctx().template emplace>(); - } - } - - template - [[nodiscard]] static auto to_args(Registry ®, type_list) { - return std::tuple(reg))...>(extract(reg)...); - } - - template - [[nodiscard]] static std::size_t fill_dependencies(type_list, [[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()...}; - const auto length = count < sizeof...(Type) ? count : sizeof...(Type); - - for(std::size_t pos{}; pos < length; ++pos) { - buffer[pos] = info[pos]; - } - - return length; - } - } - - template - void track_dependencies(std::size_t index, const bool requires_registry, type_list, type_list) { - builder.bind(static_cast(index)); - builder.set(type_hash::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u)); - (builder.ro(type_hash::value()), ...); - (builder.rw(type_hash::value()), ...); - } - -public: - /*! Basic registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = 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 from, std::vector 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 &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 &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 &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 in; - std::vector out; - }; - - /** - * @brief Adds a free function to the task list. - * @tparam Candidate Function to add to the task list. - * @tparam Req Additional requirements and/or override resource access mode. - * @param name Optional name to associate with the task. - */ - template - void emplace(const char *name = nullptr) { - using resource_type = decltype(internal::free_function_to_resource_traits(Candidate)); - constexpr auto requires_registry = type_list_contains_v; - - 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>()}; - - 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 - void emplace(Type &value_or_instance, const char *name = nullptr) { - using resource_type = decltype(internal::constrained_function_to_resource_traits(Candidate)); - constexpr auto requires_registry = type_list_contains_v; - - callback_type *callback = +[](const void *payload, registry_type ®) { - Type *curr = static_cast(const_cast *>(payload)); - std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{}))); - }; - - 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>()}; - - 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 - void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) { - using resource_type = internal::resource_traits, type_list>; - track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{}); - - vertex_data vdata{ - resource_type::ro::size, - resource_type::rw::size, - name, - payload, - func, - +[](const bool rw, const type_info **buffer, const 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()}; - - 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 graph() { - std::vector adjacency_list{}; - adjacency_list.reserve(vertices.size()); - auto adjacency_matrix = builder.graph(); - - for(auto curr: adjacency_matrix.vertices()) { - std::vector in{}; - std::vector out{}; - - for(auto &&edge: adjacency_matrix.in_edges(curr)) { - in.push_back(edge.first); - } - - for(auto &&edge: adjacency_matrix.out_edges(curr)) { - out.push_back(edge.second); - } - - adjacency_list.emplace_back(vertices[curr], 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 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() -# include -# -# if defined(__cpp_lib_ranges) -# include -# include "fwd.hpp" - -template -inline constexpr bool std::ranges::enable_borrowed_range>{true}; - -template -inline constexpr bool std::ranges::enable_borrowed_range>{true}; - -template -inline constexpr bool std::ranges::enable_view>{true}; - -template -inline constexpr bool std::ranges::enable_view>{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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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 -class registry_storage_iterator final { - template - friend class registry_storage_iterator; - - using mapped_type = std::remove_reference_t()->second)>; - -public: - using value_type = std::pair &>; - using pointer = input_iterator_pointer; - 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 && std::is_constructible_v>> - constexpr registry_storage_iterator(const registry_storage_iterator &other) noexcept - : registry_storage_iterator{other.it} {} - - constexpr registry_storage_iterator &operator++() noexcept { - return ++it, *this; - } - - constexpr registry_storage_iterator operator++(int) noexcept { - 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 - friend constexpr std::ptrdiff_t operator-(const registry_storage_iterator &, const registry_storage_iterator &) noexcept; - - template - friend constexpr bool operator==(const registry_storage_iterator &, const registry_storage_iterator &) noexcept; - - template - friend constexpr bool operator<(const registry_storage_iterator &, const registry_storage_iterator &) noexcept; - -private: - It it; -}; - -template -[[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { - return lhs.it - rhs.it; -} - -template -[[nodiscard]] constexpr bool operator==(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { - return lhs.it == rhs.it; -} - -template -[[nodiscard]] constexpr bool operator!=(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { - return !(lhs == rhs); -} - -template -[[nodiscard]] constexpr bool operator<(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { - return lhs.it < rhs.it; -} - -template -[[nodiscard]] constexpr bool operator>(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { - return rhs < lhs; -} - -template -[[nodiscard]] constexpr bool operator<=(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { - return !(lhs > rhs); -} - -template -[[nodiscard]] constexpr bool operator>=(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { - return !(lhs < rhs); -} - -template -class registry_context { - using alloc_traits = std::allocator_traits; - using allocator_type = typename alloc_traits::template rebind_alloc>>; - -public: - explicit registry_context(const allocator_type &allocator) - : ctx{allocator} {} - - template - Type &emplace_as(const id_type id, Args &&...args) { - return any_cast(ctx.try_emplace(id, std::in_place_type, std::forward(args)...).first->second); - } - - template - Type &emplace(Args &&...args) { - return emplace_as(type_id().hash(), std::forward(args)...); - } - - template - Type &insert_or_assign(const id_type id, Type &&value) { - return any_cast> &>(ctx.insert_or_assign(id, std::forward(value)).first->second); - } - - template - Type &insert_or_assign(Type &&value) { - return insert_or_assign(type_id().hash(), std::forward(value)); - } - - template - bool erase(const id_type id = type_id().hash()) { - const auto it = ctx.find(id); - return it != ctx.end() && it->second.type() == type_id() ? (ctx.erase(it), true) : false; - } - - template - [[nodiscard]] const Type &get(const id_type id = type_id().hash()) const { - return any_cast(ctx.at(id)); - } - - template - [[nodiscard]] Type &get(const id_type id = type_id().hash()) { - return any_cast(ctx.at(id)); - } - - template - [[nodiscard]] const Type *find(const id_type id = type_id().hash()) const { - const auto it = ctx.find(id); - return it != ctx.cend() ? any_cast(&it->second) : nullptr; - } - - template - [[nodiscard]] Type *find(const id_type id = type_id().hash()) { - const auto it = ctx.find(id); - return it != ctx.end() ? any_cast(&it->second) : nullptr; - } - - template - [[nodiscard]] bool contains(const id_type id = type_id().hash()) const { - const auto it = ctx.find(id); - return it != ctx.cend() && it->second.type() == type_id(); - } - -private: - dense_map, 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 -class basic_registry { - using base_type = basic_sparse_set; - using alloc_traits = std::allocator_traits; - static_assert(std::is_same_v, "Invalid value type"); - // std::shared_ptr because of its type erased allocator which is useful here - using pool_container_type = dense_map, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc>>>; - using group_container_type = dense_map, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc>>>; - using traits_type = entt_traits; - - template - [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash::value()) { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - - if constexpr(std::is_same_v) { - ENTT_ASSERT(id == type_hash::value(), "User entity storage not allowed"); - return entities; - } else { - using storage_type = storage_for_type; - - if(auto it = pools.find(id); it == pools.cend()) { - using alloc_type = typename storage_type::allocator_type; - typename pool_container_type::mapped_type cpool{}; - - if constexpr(std::is_void_v && !std::is_constructible_v) { - // std::allocator has no cross constructors (waiting for C++20) - cpool = std::allocate_shared(get_allocator(), alloc_type{}); - } else { - cpool = std::allocate_shared(get_allocator(), get_allocator()); - } - - pools.emplace(id, cpool); - cpool->bind(forward_as_any(*this)); - - return static_cast(*cpool); - } else { - ENTT_ASSERT(it->second->type() == type_id(), "Unexpected type"); - return static_cast(*it->second); - } - } - } - - template - [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash::value()) const { - static_assert(std::is_same_v>, "Non-decayed types not allowed"); - - if constexpr(std::is_same_v) { - ENTT_ASSERT(id == type_hash::value(), "User entity storage not allowed"); - return &entities; - } else { - if(const auto it = pools.find(id); it != pools.cend()) { - ENTT_ASSERT(it->second->type() == type_id(), "Unexpected type"); - return static_cast *>(it->second.get()); - } - - return static_cast *>(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; - /*! @brief Iterable registry type. */ - using iterable = iterable_adaptor>; - /*! @brief Constant iterable registry type. */ - using const_iterable = iterable_adaptor>; - - /** - * @copybrief storage_for - * @tparam Type Storage value type, eventually const. - */ - template - using storage_for_type = typename storage_for>>::type; - - /*! @brief Default constructor. */ - basic_registry() - : basic_registry{allocator_type{}} {} - - /** - * @brief Constructs an empty registry with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_registry(const allocator_type &allocator) - : basic_registry{0u, allocator} {} - - /** - * @brief Allocates enough memory upon construction to store `count` pools. - * @param count The number of pools to allocate memory for. - * @param allocator The allocator to use. - */ - basic_registry(const size_type count, const allocator_type &allocator = allocator_type{}) - : vars{allocator}, - pools{allocator}, - groups{allocator}, - entities{allocator} { - pools.reserve(count); - rebind(); - } - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_registry(const basic_registry &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_registry(basic_registry &&other) noexcept - : vars{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(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 - storage_for_type &storage(const id_type id = type_hash::value()) { - return assure(id); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @param id Optional name used to map the storage within the registry. - * @return The storage for the given element type. - */ - template - [[nodiscard]] const storage_for_type *storage(const id_type id = type_hash::value()) const { - return assure(id); - } - - /** - * @brief Checks if an identifier refers to a valid entity. - * @param entt An identifier, either valid or not. - * @return True if the identifier is valid, false otherwise. - */ - [[nodiscard]] bool valid(const entity_type entt) const { - return static_cast(entities.find(entt).index()) < entities.free_list(); - } - - /** - * @brief Returns the actual version for an identifier. - * @param entt A valid identifier. - * @return The version for the given identifier if valid, the tombstone - * version otherwise. - */ - [[nodiscard]] version_type current(const entity_type entt) const { - return entities.current(entt); - } - - /** - * @brief Creates a new entity or recycles a destroyed one. - * @return A valid identifier. - */ - [[nodiscard]] entity_type create() { - return entities.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 - 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 - 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 - decltype(auto) emplace(const entity_type entt, Args &&...args) { - ENTT_ASSERT(valid(entt), "Invalid entity"); - return assure().emplace(entt, std::forward(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 - 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().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::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().insert(first, last, from); - } - - /** - * @brief Assigns or replaces the given element for an entity. - * - * @sa emplace - * @sa replace - * - * @tparam Type Type of element to assign or replace. - * @tparam Args Types of arguments to use to construct the element. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the element. - * @return A reference to the newly created element. - */ - template - decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) { - if(auto &cpool = assure(); cpool.contains(entt)) { - return cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward(args)...}), ...); }); - } else { - ENTT_ASSERT(valid(entt), "Invalid entity"); - return cpool.emplace(entt, std::forward(args)...); - } - } - - /** - * @brief Patches the given element for an entity. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(Type &); - * @endcode - * - * @warning - * Attempting to patch an element of an entity that doesn't own it results - * in undefined behavior. - * - * @tparam Type Type of element to patch. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - * @return A reference to the patched element. - */ - template - decltype(auto) patch(const entity_type entt, Func &&...func) { - return assure().patch(entt, std::forward(func)...); - } - - /** - * @brief Replaces the given element for an entity. - * - * The element must have a proper constructor or be of aggregate type. - * - * @warning - * Attempting to replace an element of an entity that doesn't own it results - * in undefined behavior. - * - * @tparam Type Type of element to replace. - * @tparam Args Types of arguments to use to construct the element. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the element. - * @return A reference to the element being replaced. - */ - template - decltype(auto) replace(const entity_type entt, Args &&...args) { - return patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward(args)...}), ...); }); - } - - /** - * @brief Removes the given elements from an entity. - * @tparam Type Type of element to remove. - * @tparam Other Other types of elements to remove. - * @param entt A valid identifier. - * @return The number of elements actually removed. - */ - template - size_type remove(const entity_type entt) { - return (assure().remove(entt) + ... + assure().remove(entt)); - } - - /** - * @brief Removes the given elements from all the entities in a range. - * - * @sa remove - * - * @tparam Type Type of element to remove. - * @tparam Other Other types of elements to remove. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @return The number of elements actually removed. - */ - template - size_type remove(It first, It last) { - size_type count{}; - - if constexpr(std::is_same_v) { - std::array cpools{static_cast(&assure()), static_cast(&assure())...}; - - for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) { - if constexpr(sizeof...(Other) != 0u) { - if((*from)->data() == first.data()) { - std::swap((*from), cpools.back()); - } - } - - count += (*from)->remove(first, last); - } - - } else { - for(auto cpools = std::forward_as_tuple(assure(), assure()...); 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 - void erase(const entity_type entt) { - (assure().erase(entt), (assure().erase(entt), ...)); - } - - /** - * @brief Erases the given elements from all the entities in a range. - * - * @sa erase - * - * @tparam Type Types of elements to erase. - * @tparam Other Other types of elements to erase. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void erase(It first, It last) { - if constexpr(std::is_same_v) { - std::array cpools{static_cast(&assure()), static_cast(&assure())...}; - - for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) { - if constexpr(sizeof...(Other) != 0u) { - if((*from)->data() == first.data()) { - std::swap(*from, cpools.back()); - } - } - - (*from)->erase(first, last); - } - } else { - for(auto cpools = std::forward_as_tuple(assure(), assure()...); 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::common_type &); - * @endcode - * - * Only storage where the entity exists are passed to the function. - * - * @tparam Func Type of the function object to invoke. - * @param entt A valid identifier. - * @param func A valid function object. - */ - template - void erase_if(const entity_type entt, Func func) { - for(auto [id, cpool]: storage()) { - if(cpool.contains(entt) && func(id, 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 - void compact() { - if constexpr(sizeof...(Type) == 0u) { - for(auto &&curr: pools) { - curr.second->compact(); - } - } else { - (assure().compact(), ...); - } - } - - /** - * @brief Check if an entity is part of all the given storage. - * @tparam Type Type of storage to check for. - * @param entt A valid identifier. - * @return True if the entity is part of all the storage, false otherwise. - */ - template - [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const { - if constexpr(sizeof...(Type) == 1u) { - auto *cpool = assure...>(); - return cpool && cpool->contains(entt); - } else { - return (all_of(entt) && ...); - } - } - - /** - * @brief Check if an entity is part of at least one given storage. - * @tparam Type Type of storage to check for. - * @param entt A valid identifier. - * @return True if the entity is part of at least one storage, false - * otherwise. - */ - template - [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const { - return (all_of(entt) || ...); - } - - /** - * @brief Returns references to the given elements for an entity. - * - * @warning - * Attempting to get an element from an entity that doesn't own it results - * in undefined behavior. - * - * @tparam Type Types of elements to get. - * @param entt A valid identifier. - * @return References to the elements owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const { - if constexpr(sizeof...(Type) == 1u) { - return (assure>()->get(entt), ...); - } else { - return std::forward_as_tuple(get(entt)...); - } - } - - /*! @copydoc get */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) { - if constexpr(sizeof...(Type) == 1u) { - return (static_cast &>(assure>()).get(entt), ...); - } else { - return std::forward_as_tuple(get(entt)...); - } - } - - /** - * @brief Returns a reference to the given element for an entity. - * - * In case the entity doesn't own the element, the parameters provided are - * used to construct it. - * - * @sa get - * @sa emplace - * - * @tparam Type Type of element to get. - * @tparam Args Types of arguments to use to construct the element. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the element. - * @return Reference to the element owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) { - if(auto &cpool = assure(); cpool.contains(entt)) { - return cpool.get(entt); - } else { - ENTT_ASSERT(valid(entt), "Invalid entity"); - return cpool.emplace(entt, std::forward(args)...); - } - } - - /** - * @brief Returns pointers to the given elements for an entity. - * - * @note - * The registry retains ownership of the pointed-to elements. - * - * @tparam Type Types of elements to get. - * @param entt A valid identifier. - * @return Pointers to the elements owned by the entity. - */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const { - if constexpr(sizeof...(Type) == 1u) { - const auto *cpool = assure...>(); - return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr; - } else { - return std::make_tuple(try_get(entt)...); - } - } - - /*! @copydoc try_get */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) { - if constexpr(sizeof...(Type) == 1u) { - return (const_cast(std::as_const(*this).template try_get(entt)), ...); - } else { - return std::make_tuple(try_get(entt)...); - } - } - - /** - * @brief Clears a whole registry or the pools for the given elements. - * @tparam Type Types of elements to remove from their entities. - */ - template - void clear() { - if constexpr(sizeof...(Type) == 0u) { - for(size_type pos = pools.size(); pos; --pos) { - pools.begin()[pos - 1u].second->clear(); - } - - const auto elem = entities.each(); - entities.erase(elem.begin().base(), elem.end().base()); - } else { - (assure().clear(), ...); - } - } - - /** - * @brief Checks if an entity has elements assigned. - * @param entt A valid identifier. - * @return True if the entity has no elements assigned, false otherwise. - */ - [[nodiscard]] bool orphan(const entity_type entt) const { - return 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.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** assigning the element to the entity. - * - * @sa sink - * - * @tparam Type Type of element of which to get the sink. - * @param id Optional name used to map the storage within the registry. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_construct(const id_type id = type_hash::value()) { - return assure(id).on_construct(); - } - - /** - * @brief Returns a sink object for the given element. - * - * Use this function to receive notifications whenever an instance of the - * given element is explicitly updated.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** updating the element. - * - * @sa sink - * - * @tparam Type Type of element of which to get the sink. - * @param id Optional name used to map the storage within the registry. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_update(const id_type id = type_hash::value()) { - return assure(id).on_update(); - } - - /** - * @brief Returns a sink object for the given element. - * - * Use this function to receive notifications whenever an instance of the - * given element is removed from an entity and thus destroyed.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **before** removing the element from the entity. - * - * @sa sink - * - * @tparam Type Type of element of which to get the sink. - * @param id Optional name used to map the storage within the registry. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_destroy(const id_type id = type_hash::value()) { - return assure(id).on_destroy(); - } - - /** - * @brief Returns a view for the given elements. - * @tparam Type Type of element used to construct the view. - * @tparam Other Other types of elements used to construct the view. - * @tparam Exclude Types of elements used to filter the view. - * @return A newly created view. - */ - template - [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> - view(exclude_t = exclude_t{}) const { - const auto cpools = std::make_tuple(assure>(), assure>()..., assure>()...); - basic_view, storage_for_type...>, exclude_t...>> elem{}; - std::apply([&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }, cpools); - return elem; - } - - /*! @copydoc view */ - template - [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> - view(exclude_t = exclude_t{}) { - return {assure>(), assure>()..., assure>()...}; - } - - /** - * @brief Returns a group for the given elements. - * @tparam Owned Types of storage _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group, if any. - * @tparam Exclude Types of storage used to filter the group, if any. - * @return A newly created group. - */ - template - basic_group...>, get_t...>, exclude_t...>> - group(get_t = get_t{}, exclude_t = exclude_t{}) { - using group_type = basic_group...>, get_t...>, exclude_t...>>; - using handler_type = typename group_type::handler; - - if(auto it = groups.find(group_type::group_id()); it != groups.cend()) { - return {*std::static_pointer_cast(it->second)}; - } - - std::shared_ptr handler{}; - - if constexpr(sizeof...(Owned) == 0u) { - handler = std::allocate_shared(get_allocator(), get_allocator(), std::forward_as_tuple(assure>()...), std::forward_as_tuple(assure>()...)); - } else { - handler = std::allocate_shared(get_allocator(), std::forward_as_tuple(assure>()..., assure>()...), std::forward_as_tuple(assure>()...)); - ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id().hash()) || ...); }), "Conflicting groups"); - } - - groups.emplace(group_type::group_id(), handler); - return {*handler}; - } - - /*! @copydoc group */ - template - [[nodiscard]] basic_group...>, get_t...>, exclude_t...>> - group_if_exists(get_t = get_t{}, exclude_t = exclude_t{}) const { - using group_type = basic_group...>, get_t...>, exclude_t...>>; - using handler_type = typename group_type::handler; - - if(auto it = groups.find(group_type::group_id()); it != groups.cend()) { - return {*std::static_pointer_cast(it->second)}; - } - - return {}; - } - - /** - * @brief Checks whether the given elements belong to any group. - * @tparam Type Types of elements in which one is interested. - * @return True if the pools of the given elements are _free_, false - * otherwise. - */ - template - [[nodiscard]] bool owned() const { - return std::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id().hash()) || ...); }); - } - - /** - * @brief Sorts the elements of a given element. - * - * The comparison function object returns `true` if the first element is - * _less_ than the second one, `false` otherwise. Its signature is also - * equivalent to one of the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * bool(const Type &, const Type &); - * @endcode - * - * Moreover, it shall induce a _strict weak ordering_ on the values.
- * The sort function object offers an `operator()` that accepts: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function object to use to compare the elements. - * - * The comparison function object hasn't necessarily the type of the one - * passed along with the other parameters to this member function. - * - * @warning - * Pools of elements owned by a group cannot be sorted. - * - * @tparam Type Type of elements to sort. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { - ENTT_ASSERT(!owned(), "Cannot sort owned storage"); - auto &cpool = assure(); - - if constexpr(std::is_invocable_v) { - 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)...); - } else { - cpool.sort(std::move(compare), std::move(algo), std::forward(args)...); - } - } - - /** - * @brief Sorts two pools of elements in the same way. - * - * Entities and elements in `To` which are part of both storage are sorted - * internally with the order they have in `From`. The others follow in no - * particular order. - * - * @warning - * Pools of elements owned by a group cannot be sorted. - * - * @tparam To Type of elements to sort. - * @tparam From Type of elements to use to sort. - */ - template - void sort() { - ENTT_ASSERT(!owned(), "Cannot sort owned storage"); - const base_type &cpool = assure(); - assure().sort_as(cpool.begin(), cpool.end()); - } - - /** - * @brief Returns the context object, that is, a general purpose container. - * @return The context object, that is, a general purpose container. - */ - [[nodiscard]] context &ctx() noexcept { - return vars; - } - - /*! @copydoc ctx */ - [[nodiscard]] const context &ctx() const noexcept { - return vars; - } - -private: - context vars; - pool_container_type pools; - group_container_type groups; - storage_for_type entities; -}; - -} // namespace entt - -#endif 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 -#include -#include -#include -#include -#include "entity.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond TURN_OFF_DOXYGEN */ -namespace internal { - -template -class runtime_view_iterator final { - using iterator_type = typename Set::iterator; - using iterator_traits = std::iterator_traits; - - [[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 &cpools, const std::vector &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 *pools; - const std::vector *filter; - iterator_type it; - bool tombstone_check; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Generic runtime view. - * - * Runtime views iterate over those entities that are at least in the given - * storage. During initialization, a runtime view looks at the number of - * entities available for each element and uses the smallest set in order to get - * a performance boost when iterating. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New elements are added to the storage. - * * The entity currently pointed is modified (for example, elements are added - * or removed from it). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the storage iterated by the view in any way - * invalidates all the iterators. - * - * @tparam Type Common base type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_runtime_view { - using alloc_traits = std::allocator_traits; - static_assert(std::is_same_v, "Invalid value type"); - using container_type = std::vector; - -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; - - /*! @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) = 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) = 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.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entity: *this) { - func(entity); - } - } - -private: - container_type pools; - container_type filter; -}; - -} // namespace entt - -#endif 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 -#include -#include -#include -#include -#include -#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 -void orphans(Registry ®istry) { - auto &storage = registry.template storage(); - - 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.
- * This type can be used in both cases if provided with a correctly configured - * output archive. - * - * @tparam Registry Basic registry type. - */ -template -class basic_snapshot { - static_assert(!std::is_const_v, "Non-const registry type required"); - using traits_type = entt_traits; - -public: - /*! Basic registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = 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 - const basic_snapshot &get(Archive &archive, const id_type id = type_hash::value()) const { - if(const auto *storage = reg->template storage(id); storage) { - const typename registry_type::common_type &base = *storage; - - archive(static_cast(storage->size())); - - if constexpr(std::is_same_v) { - archive(static_cast(storage->free_list())); - - for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) { - archive(*first); - } - } else if constexpr(registry_type::template storage_for_type::storage_policy == deletion_policy::in_place) { - for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) { - if(const auto entt = *it; entt == tombstone) { - archive(static_cast(null)); - } else { - archive(entt); - std::apply([&archive](auto &&...args) { (archive(std::forward(args)), ...); }, storage->get_as_tuple(entt)); - } - } - } else { - for(auto elem: storage->reach()) { - std::apply([&archive](auto &&...args) { (archive(std::forward(args)), ...); }, elem); - } - } - } else { - archive(typename traits_type::entity_type{}); - } - - return *this; - } - - /** - * @brief Serializes all elements of a type with associated identifiers for - * the entities in a range. - * @tparam Type Type of elements to serialize. - * @tparam Archive Type of output archive. - * @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 - const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash::value()) const { - static_assert(!std::is_same_v, "Entity types not supported"); - - if(const auto *storage = reg->template storage(id); storage && !storage->empty()) { - archive(static_cast(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(args)), ...); }, storage->get_as_tuple(entt)); - } else { - archive(static_cast(null)); - } - } - } else { - archive(typename traits_type::entity_type{}); - } - - return *this; - } - -private: - const registry_type *reg; -}; - -/** - * @brief Utility class to restore a snapshot as a whole. - * - * A snapshot loader requires that the destination registry be empty and loads - * all the data at once while keeping intact the identifiers that the entities - * originally had.
- * An example of use is the implementation of a save/restore utility. - * - * @tparam Registry Basic registry type. - */ -template -class basic_snapshot_loader { - static_assert(!std::is_const_v, "Non-const registry type required"); - using traits_type = entt_traits; - -public: - /*! Basic registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = 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().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 - basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash::value()) { - auto &storage = reg->template storage(id); - typename traits_type::entity_type length{}; - - archive(length); - - if constexpr(std::is_same_v) { - 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 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 == 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.
- * This function helps to identify and destroy those entities. - * - * @return A valid loader to continue restoring data. - */ - basic_snapshot_loader &orphans() { - internal::orphans(*reg); - return *this; - } - -private: - registry_type *reg; -}; - -/** - * @brief Utility class for _continuous loading_. - * - * A _continuous loader_ is designed to load data from a source registry to a - * (possibly) non-empty destination. The loader can accommodate in a registry - * more than one snapshot in a sort of _continuous loading_ that updates the - * destination one step at a time.
- * Identifiers that entities originally had are not transferred to the target. - * Instead, the loader maps remote identifiers to local ones while restoring a - * snapshot.
- * An example of use is the implementation of a client-server application with - * the requirement of transferring somehow parts of the representation side to - * side. - * - * @tparam Registry Basic registry type. - */ -template -class basic_continuous_loader { - static_assert(!std::is_const_v, "Non-const registry type required"); - using traits_type = entt_traits; - - 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 - auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) { - // map like container - Container other; - - for(auto &&pair: container) { - using first_type = std::remove_const_t::first_type>; - using second_type = typename std::decay_t::second_type; - - if constexpr(std::is_same_v && std::is_same_v) { - other.emplace(map(pair.first), map(pair.second)); - } else if constexpr(std::is_same_v) { - other.emplace(map(pair.first), std::move(pair.second)); - } else { - static_assert(std::is_same_v, "Neither the key nor the value are of entity type"); - other.emplace(std::move(pair.first), map(pair.second)); - } - } - - using std::swap; - swap(container, other); - } - - template - auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) { - // vector like container - static_assert(std::is_same_v, "Invalid value type"); - - for(auto &&entt: container) { - entt = map(entt); - } - } - - template - void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) { - if constexpr(!std::is_same_v) { - return; - } else if constexpr(std::is_same_v) { - instance.*member = map(instance.*member); - } else { - // maybe a container? let's try... - update(0, instance.*member); - } - } - -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.
- * Members are either data members of type entity_type or containers of - * entities. In both cases, a loader visits them and replaces entities with - * their local counterpart. - * - * @tparam Type Type of elements to restore. - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @param id Optional name used to map the storage within the registry. - * @return A valid loader to continue restoring data. - */ - template - basic_continuous_loader &get(Archive &archive, const id_type id = type_hash::value()) { - auto &storage = reg->template storage(id); - typename traits_type::entity_type length{}; - entity_type entt{null}; - - archive(length); - - if constexpr(std::is_same_v) { - 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 == 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.
- * This function helps to identify and destroy those entities. - * - * @return A non-const reference to this loader. - */ - basic_continuous_loader &orphans() { - internal::orphans(*reg); - return *this; - } - - /** - * @brief Tests if a loader knows about a given entity. - * @param entt A valid identifier. - * @return True if `entity` is managed by the loader, false otherwise. - */ - [[nodiscard]] bool contains(entity_type entt) const noexcept { - const auto it = remloc.find(to_entity(entt)); - return it != remloc.cend() && it->second.first == entt; - } - - /** - * @brief Returns the identifier to which an entity refers. - * @param entt A valid identifier. - * @return The local identifier if any, the null entity otherwise. - */ - [[nodiscard]] entity_type map(entity_type entt) const noexcept { - if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) { - return it->second.second; - } - - return null; - } - -private: - dense_map> remloc; - registry_type *reg; -}; - -} // namespace entt - -#endif 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 -#include -#include -#include -#include -#include -#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 -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 -[[nodiscard]] constexpr std::ptrdiff_t operator-(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { - return rhs.index() - lhs.index(); -} - -template -[[nodiscard]] constexpr bool operator==(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { - return lhs.index() == rhs.index(); -} - -template -[[nodiscard]] constexpr bool operator!=(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { - return !(lhs == rhs); -} - -template -[[nodiscard]] constexpr bool operator<(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { - return lhs.index() > rhs.index(); -} - -template -[[nodiscard]] constexpr bool operator>(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { - return rhs < lhs; -} - -template -[[nodiscard]] constexpr bool operator<=(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { - return !(lhs > rhs); -} - -template -[[nodiscard]] constexpr bool operator>=(const sparse_set_iterator &lhs, const sparse_set_iterator &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.
- * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a - * _packed_ one; one used for direct access through contiguous memory, the other - * one used to get the data through an extra level of indirection.
- * This type of data structure is widely documented in the literature and on the - * web. This is nothing more than a customized implementation suitable for the - * purpose of the framework. - * - * @note - * Internal data structures arrange elements to maximize performance. There are - * no guarantees that entities are returned in the insertion order when iterate - * a sparse set. Do not make assumption on the order in any case. - * - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_sparse_set { - using alloc_traits = std::allocator_traits; - static_assert(std::is_same_v, "Invalid value type"); - using sparse_container_type = std::vector>; - using packed_container_type = std::vector; - using traits_type = entt_traits; - - static constexpr auto max_size = static_cast(traits_type::to_entity(null)); - - [[nodiscard]] auto policy_to_head() const noexcept { - return static_cast(max_size * (mode != deletion_policy::swap_only)); - } - - [[nodiscard]] auto sparse_ptr(const Entity entt) const { - const auto pos = static_cast(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(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(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(rhs), traits_type::to_integral(from)); - sparse_ref(to) = traits_type::combine(static_cast(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; - - /** - * @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(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(traits_type::to_entity(std::exchange(sparse_ref(*it), null))); - packed[pos] = traits_type::combine(static_cast(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(head), traits_type::to_integral(entt)); - head = static_cast(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(packed.size() - 1u), traits_type::to_integral(entt)); - break; - case deletion_policy::swap_only: - if(elem == null) { - packed.push_back(entt); - elem = traits_type::combine(static_cast(packed.size() - 1u), traits_type::to_integral(entt)); - } else { - ENTT_ASSERT(!(static_cast(traits_type::to_entity(elem)) < head), "Slot not available"); - bump(entt); - } - - pos = head++; - swap_at(static_cast(traits_type::to_entity(elem)), pos); - break; - } - - return --(end() - static_cast(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; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = std::reverse_iterator; - - /*! @brief Default constructor. */ - basic_sparse_set() - : basic_sparse_set{type_id()} {} - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_sparse_set(const allocator_type &allocator) - : basic_sparse_set{deletion_policy::swap_and_pop, allocator} {} - - /** - * @brief Constructs an empty container with the given policy and allocator. - * @param pol Type of deletion policy. - * @param allocator The allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {}) - : basic_sparse_set{type_id(), pol, allocator} {} - - /** - * @brief Constructs an empty container with the given value type, policy - * and allocator. - * @param elem Returned value type, if any. - * @param pol Type of deletion policy. - * @param allocator The allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(const type_info &elem, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {}) - : sparse{allocator}, - packed{allocator}, - 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(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(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(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 - 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(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 - void erase(It first, It last) { - if constexpr(std::is_same_v) { - pop(first, last); - } else { - for(; first != last; ++first) { - erase(*first); - } - } - } - - /** - * @brief Removes an entity from a sparse set if it exists. - * @param entt A valid identifier. - * @return True if the entity is actually removed, false otherwise. - */ - bool remove(const entity_type entt) { - return contains(entt) && (erase(entt), true); - } - - /** - * @brief Removes entities from a sparse set if they exist. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @return The number of entities actually removed. - */ - template - size_type remove(It first, It last) { - size_type count{}; - - if constexpr(std::is_same_v) { - 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(traits_type::to_entity(packed[pos]))); to < from) { - --from; - swap_or_move(from, to); - - packed[to] = packed[from]; - const auto elem = static_cast(to); - sparse_ref(packed[to]) = traits_type::combine(elem, traits_type::to_integral(packed[to])); - - for(; from && packed[from - 1u] == tombstone; --from) {} - } - } - - packed.erase(packed.begin() + from, packed.end()); - } - } - - /** - * @brief Swaps two entities in a sparse set. - * - * For what it's worth, this function affects both the internal sparse array - * and the internal packed array. Users should not care of that anyway. - * - * @warning - * Attempting to swap entities that don't belong to the sparse set results - * in undefined behavior. - * - * @param lhs A valid identifier. - * @param rhs A valid identifier. - */ - void swap_elements(const entity_type lhs, const entity_type rhs) { - const auto from = index(lhs); - const auto to = index(rhs); - - // basic no-leak guarantee if swapping throws - swap_or_move(from, to); - swap_at(from, to); - } - - /** - * @brief Sort the first count elements according to the given comparison - * function. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param length Number of elements to sort. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) { - ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); - ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements"); - - algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward(args)...); - - for(size_type pos{}; pos < length; ++pos) { - auto curr = pos; - auto next = index(packed[curr]); - - while(curr != next) { - const auto idx = index(packed[next]); - const auto entt = packed[curr]; - - swap_or_move(next, idx); - const auto elem = static_cast(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 - 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)...); - } - - /** - * @brief Sort entities according to their order in a range. - * - * Entities that are part of both the sparse set and the range are ordered - * internally according to the order they have in the range.
- * All other entities goes to the end of the sparse set and there are no - * guarantees on their order. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @return An iterator past the last of the elements actually shared. - */ - template - iterator sort_as(It first, It last) { - ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); - const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size(); - auto it = end() - static_cast(len); - - for(const auto other = end(); (it != other) && (first != last); ++first) { - if(const auto curr = *first; contains(curr)) { - if(const auto entt = *it; entt != curr) { - // basic no-leak guarantee (with invalid state) if swapping throws - swap_elements(entt, curr); - } - - ++it; - } - } - - return it; - } - - /*! @brief Clears a sparse set. */ - void clear() { - pop_all(); - // sanity check to avoid subtle issues due to storage classes - ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set"); - head = policy_to_head(); - packed.clear(); - } - - /** - * @brief 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 -#include -#include -#include -#include -#include -#include -#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 -class storage_iterator final { - friend storage_iterator; - - using container_type = std::remove_const_t; - using alloc_traits = std::allocator_traits; - - using iterator_traits = std::iterator_traits, - typename alloc_traits::template rebind_traits::element_type>::const_pointer, - typename alloc_traits::template rebind_traits::element_type>::pointer>>; - -public: - using value_type = 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, typename = std::enable_if_t> - constexpr storage_iterator(const storage_iterator> &other) noexcept - : storage_iterator{other.payload, other.offset} {} - - constexpr storage_iterator &operator++() noexcept { - return --offset, *this; - } - - constexpr storage_iterator operator++(int) noexcept { - 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::page_size; - return (*payload)[pos / page_size][fast_mod(static_cast(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 -[[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { - return rhs.index() - lhs.index(); -} - -template -[[nodiscard]] constexpr bool operator==(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { - return lhs.index() == rhs.index(); -} - -template -[[nodiscard]] constexpr bool operator!=(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { - return !(lhs == rhs); -} - -template -[[nodiscard]] constexpr bool operator<(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { - return lhs.index() > rhs.index(); -} - -template -[[nodiscard]] constexpr bool operator>(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { - return rhs < lhs; -} - -template -[[nodiscard]] constexpr bool operator<=(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { - return !(lhs > rhs); -} - -template -[[nodiscard]] constexpr bool operator>=(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { - return !(lhs < rhs); -} - -template -class extended_storage_iterator final { - template - friend class extended_storage_iterator; - -public: - using iterator_type = It; - using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval()), std::forward_as_tuple(*std::declval()...))); - using pointer = input_iterator_pointer; - 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 && ...) && (std::is_constructible_v && ...)>> - constexpr extended_storage_iterator(const extended_storage_iterator &other) - : it{other.it} {} - - constexpr extended_storage_iterator &operator++() noexcept { - return ++std::get(it), (++std::get(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), *std::get(it)...}; - } - - [[nodiscard]] constexpr iterator_type base() const noexcept { - return std::get(it); - } - - template - friend constexpr bool operator==(const extended_storage_iterator &, const extended_storage_iterator &) noexcept; - -private: - std::tuple it; -}; - -template -[[nodiscard]] constexpr bool operator==(const extended_storage_iterator &lhs, const extended_storage_iterator &rhs) noexcept { - return std::get<0>(lhs.it) == std::get<0>(rhs.it); -} - -template -[[nodiscard]] constexpr bool operator!=(const extended_storage_iterator &lhs, const extended_storage_iterator &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 -class basic_storage: public basic_sparse_set::template rebind_alloc> { - using alloc_traits = std::allocator_traits; - static_assert(std::is_same_v, "Invalid value type"); - using container_type = std::vector>; - using underlying_type = basic_sparse_set>; - using underlying_iterator = typename underlying_type::basic_iterator; - using traits_type = component_traits; - - [[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 - 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(it.index())); - entt::uninitialized_construct_using_allocator(to_address(elem), get_allocator(), std::forward(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 && std::is_move_assignable_v); - // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy - ENTT_ASSERT((from + 1u) && !is_pinned_type_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(first.index())))); - } - } else { - base_type::swap_and_pop(first); - alloc_traits::destroy(allocator, std::addressof(element_at(static_cast(first.index())))); - } - } - } - - /** - * @brief Assigns an entity to a storage. - * @param entt A valid identifier. - * @param value Optional opaque value. - * @param force_back Force back insertion. - * @return Iterator pointing to the emplaced element. - */ - underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override { - if(value) { - if constexpr(std::is_copy_constructible_v) { - return emplace_element(entt, force_back, *static_cast(value)); - } else { - return base_type::end(); - } - } else { - if constexpr(std::is_default_constructible_v) { - return emplace_element(entt, force_back); - } else { - return base_type::end(); - } - } - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Base type. */ - using base_type = underlying_type; - /*! @brief Element type. */ - using element_type = Type; - /*! @brief Type of the objects assigned to entities. */ - using value_type = element_type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = 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::const_pointer; - /*! @brief Random access iterator type. */ - using iterator = internal::storage_iterator; - /*! @brief Constant random access iterator type. */ - using const_iterator = internal::storage_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = std::reverse_iterator; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = std::reverse_iterator; - /*! @brief Extended iterable storage proxy. */ - using iterable = iterable_adaptor>; - /*! @brief Constant extended iterable storage proxy. */ - using const_iterable = iterable_adaptor>; - /*! @brief Extended reverse iterable storage proxy. */ - using reverse_iterable = iterable_adaptor>; - /*! @brief Constant extended reverse iterable storage proxy. */ - using const_reverse_iterable = iterable_adaptor>; - /*! @brief Storage deletion policy. */ - static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; - - /*! @brief Default constructor. */ - basic_storage() - : basic_storage{allocator_type{}} {} - - /** - * @brief Constructs an empty storage with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_storage(const allocator_type &allocator) - : base_type{type_id(), storage_policy, allocator}, - payload{allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_storage(const basic_storage &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_storage(basic_storage &&other) noexcept - : base_type{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(base_type::size()); - return const_iterator{&payload, pos}; - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const noexcept { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() noexcept { - const auto pos = static_cast(base_type::size()); - return iterator{&payload, pos}; - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last instance of the - * internal array. - */ - [[nodiscard]] const_iterator cend() const noexcept { - return const_iterator{&payload, {}}; - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const noexcept { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() noexcept { - return iterator{&payload, {}}; - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * If the storage is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first instance of the reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crbegin() const noexcept { - return 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(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 get_as_tuple(const entity_type entt) const noexcept { - return std::forward_as_tuple(get(entt)); - } - - /*! @copydoc get_as_tuple */ - [[nodiscard]] std::tuple 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 - value_type &emplace(const entity_type entt, Args &&...args) { - if constexpr(std::is_aggregate_v && (sizeof...(Args) != 0u || !std::is_default_constructible_v)) { - const auto it = emplace_element(entt, false, Type{std::forward(args)...}); - return element_at(static_cast(it.index())); - } else { - const auto it = emplace_element(entt, false, std::forward(args)...); - return element_at(static_cast(it.index())); - } - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - * @return A reference to the updated instance. - */ - template - value_type &patch(const entity_type entt, Func &&...func) { - const auto idx = base_type::index(entt); - auto &elem = element_at(idx); - (std::forward(func)(elem), ...); - return elem; - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given instance. - * - * @warning - * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param value An instance of the object to construct. - * @return Iterator pointing to the first element inserted, if any. - */ - template - 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::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 -class basic_storage::page_size == 0u>> - : public basic_sparse_set::template rebind_alloc> { - using alloc_traits = std::allocator_traits; - static_assert(std::is_same_v, "Invalid value type"); - using traits_type = component_traits; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Base type. */ - using base_type = basic_sparse_set>; - /*! @brief Element type. */ - using element_type = Type; - /*! @brief Type of the objects assigned to entities. */ - using value_type = void; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Extended iterable storage proxy. */ - using iterable = iterable_adaptor>; - /*! @brief Constant extended iterable storage proxy. */ - using const_iterable = iterable_adaptor>; - /*! @brief Extended reverse iterable storage proxy. */ - using reverse_iterable = iterable_adaptor>; - /*! @brief Constant extended reverse iterable storage proxy. */ - using const_reverse_iterable = iterable_adaptor>; - /*! @brief Storage deletion policy. */ - static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; - - /*! @brief Default constructor. */ - basic_storage() - : basic_storage{allocator_type{}} {} - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_storage(const allocator_type &allocator) - : base_type{type_id(), storage_policy, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_storage(const basic_storage &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_storage(basic_storage &&other) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_storage(basic_storage &&other, const allocator_type &allocator) - : base_type{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 has no cross constructors (waiting for C++20) - if constexpr(std::is_void_v && !std::is_constructible_v) { - 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 - 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 - void patch([[maybe_unused]] const entity_type entt, Func &&...func) { - ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); - (std::forward(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 - 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 -class basic_storage - : public basic_sparse_set { - using alloc_traits = std::allocator_traits; - static_assert(std::is_same_v, "Invalid value type"); - using underlying_iterator = typename basic_sparse_set::basic_iterator; - using traits_type = entt_traits; - - 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(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; - /*! @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>; - /*! @brief Constant extended iterable storage proxy. */ - using const_iterable = iterable_adaptor>; - /*! @brief Extended reverse iterable storage proxy. */ - using reverse_iterable = iterable_adaptor>; - /*! @brief Constant extended reverse iterable storage proxy. */ - using const_reverse_iterable = iterable_adaptor>; - /*! @brief Storage deletion policy. */ - static constexpr deletion_policy storage_policy = deletion_policy::swap_only; - - /*! @brief Default constructor. */ - basic_storage() - : basic_storage{allocator_type{}} { - } - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_storage(const allocator_type &allocator) - : base_type{type_id(), storage_policy, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_storage(const basic_storage &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - 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 - 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)(), ...); - } - - /** - * @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 - 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 -#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); - * @endcode - * - * This applies to all signals made available. - * - * @tparam Type The type of the underlying storage. - */ -template -class sigh_storage_mixin final: public Type { - using basic_registry_type = basic_registry; - using sigh_type = sigh; - 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.
- * Listeners are invoked after the object has been assigned to the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_construct() noexcept { - return sink{construction}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is explicitly updated.
- * Listeners are invoked after the object has been updated. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_update() noexcept { - return sink{update}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is removed from an entity and thus destroyed.
- * Listeners are invoked before the object has been removed from the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_destroy() noexcept { - return sink{destruction}; - } - - /** - * @brief 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 - decltype(auto) emplace(const entity_type entt, Args &&...args) { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - Type::emplace(entt, std::forward(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 - decltype(auto) patch(const entity_type entt, Func &&...func) { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - Type::patch(entt, std::forward(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 - void insert(It first, It last, Args &&...args) { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - Type::insert(first, last, std::forward(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(&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 -#include -#include -#include -#include -#include -#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 -[[nodiscard]] bool all_of(It first, const It last, const Entity entt) noexcept { - for(; (first != last) && (*first)->contains(entt); ++first) {} - return first == last; -} - -template -[[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 -[[nodiscard]] bool fully_initialized(It first, const It last) noexcept { - for(; (first != last) && *first; ++first) {} - return first == last; -} - -template -[[nodiscard]] Result view_pack(const View &view, const Other &other, std::index_sequence, std::index_sequence, std::index_sequence, std::index_sequence) { - Result elem{}; - // friend-initialization, avoid multiple calls to refresh - elem.pools = {view.template storage()..., other.template storage()...}; - elem.filter = {view.template storage()..., other.template storage()...}; - elem.refresh(); - return elem; -} - -template -class view_iterator final { - template - friend class extended_view_iterator; - - using iterator_type = typename Type::const_iterator; - using iterator_traits = std::iterator_traits; - - [[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 value, std::array 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 - friend constexpr bool operator==(const view_iterator &, const view_iterator &) noexcept; - -private: - iterator_type it; - std::array pools; - std::array filter; - std::size_t index; -}; - -template -[[nodiscard]] constexpr bool operator==(const view_iterator &lhs, const view_iterator &rhs) noexcept { - return lhs.it == rhs.it; -} - -template -[[nodiscard]] constexpr bool operator!=(const view_iterator &lhs, const view_iterator &rhs) noexcept { - return !(lhs == rhs); -} - -template -class extended_view_iterator final { - template - [[nodiscard]] auto dereference(std::index_sequence) const noexcept { - return std::tuple_cat(std::make_tuple(*it), static_cast(const_cast *>(std::get(it.pools)))->get_as_tuple(*it)...); - } - -public: - using iterator_type = It; - using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval()), std::declval().get_as_tuple({})...)); - using pointer = input_iterator_pointer; - 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{}); - } - - [[nodiscard]] pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr iterator_type base() const noexcept { - return it; - } - - template - friend bool constexpr operator==(const extended_view_iterator &, const extended_view_iterator &) noexcept; - -private: - It it; -}; - -template -[[nodiscard]] constexpr bool operator==(const extended_view_iterator &lhs, const extended_view_iterator &rhs) noexcept { - return lhs.it == rhs.it; -} - -template -[[nodiscard]] constexpr bool operator!=(const extended_view_iterator &lhs, const extended_view_iterator &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 -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 -class basic_common_view { - template - friend Return internal::view_pack(const View &, const Other &, std::index_sequence, std::index_sequence, std::index_sequence, std::index_sequence); - - [[nodiscard]] auto offset() const noexcept { - ENTT_ASSERT(index != Get, "Invalid view"); - return (pools[index]->policy() == deletion_policy::swap_only) ? pools[index]->free_list() : pools[index]->size(); - } - - void unchecked_refresh() noexcept { - index = 0u; - - if constexpr(Get > 1u) { - for(size_type pos{1u}; pos < Get; ++pos) { - if(pools[pos]->size() < pools[index]->size()) { - index = pos; - } - } - } - } - -protected: - /*! @cond TURN_OFF_DOXYGEN */ - basic_common_view() noexcept = default; - - basic_common_view(std::array value, std::array 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; - - /*! @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(offset()), pools, filter, index} : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the view. - * @return An iterator to the entity following the last entity of the view. - */ - [[nodiscard]] iterator end() const noexcept { - return (index != Get) ? iterator{pools[index]->end(), pools, filter, index} : iterator{}; - } - - /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const noexcept { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the view, if any. - * @return The last entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const noexcept { - if(index != Get) { - auto it = pools[index]->rbegin(); - const auto last = it + static_cast(offset()); - for(; 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 pools{}; - std::array 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 -class basic_view, exclude_t, std::enable_if_t<(sizeof...(Get) + sizeof...(Exclude) > 1)>> - : public basic_common_view, sizeof...(Get), sizeof...(Exclude)> { - using base_type = basic_common_view, sizeof...(Get), sizeof...(Exclude)>; - - template - static constexpr std::size_t index_of = type_list_index_v, type_list>; - - template - [[nodiscard]] auto get(const typename base_type::entity_type entt, std::index_sequence) const noexcept { - return std::tuple_cat(storage()->get_as_tuple(entt)...); - } - - template - [[nodiscard]] auto dispatch_get(const std::tuple &curr) const { - if constexpr(Curr == Other) { - return std::forward_as_tuple(std::get(curr)...); - } else { - return storage()->get_as_tuple(std::get<0>(curr)); - } - } - - template - void each(Func &func, std::index_sequence) const { - static constexpr bool tombstone_check_required = ((sizeof...(Get) == 1u) && ... && (Get::storage_policy == deletion_policy::in_place)); - - for(const auto curr: storage()->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{}, std::declval().get({})))>) { - std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get(curr)...)); - } else { - std::apply(func, std::tuple_cat(dispatch_get(curr)...)); - } - } - } - } - - template - void pick_and_each(Func &func, std::index_sequence seq) const { - if(const auto *view = base_type::handle(); view != nullptr) { - ((view == base_type::pool_at(Index) ? each(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>; - - /*! @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 value, std::tuple excl = {}) noexcept - : basic_view{std::make_from_tuple(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 - void use() noexcept { - use>(); - } - - /** - * @brief Forces a view to use a given element to drive iterations - * @tparam Index Index of the element to use to drive iterations. - */ - template - void use() noexcept { - base_type::use(Index); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @return The storage for the given element type. - */ - template - [[nodiscard]] auto *storage() const noexcept { - return storage>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - using type = type_list_element_t>; - return static_cast(const_cast *>(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 - void storage(Type &elem) noexcept { - storage>(elem); - } - - /** - * @brief Assigns a storage to a view. - * @tparam Index Index of the storage to assign to the view. - * @tparam Type Type of storage to assign to the view. - * @param elem A storage to assign to the view. - */ - template - void storage(Type &elem) noexcept { - static_assert(std::is_convertible_v> &>, "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 - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - return get, index_of...>(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Index Indexes of the elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - if constexpr(sizeof...(Index) == 0) { - return get(entt, std::index_sequence_for{}); - } else if constexpr(sizeof...(Index) == 1) { - return (storage()->get(entt), ...); - } else { - return std::tuple_cat(storage()->get_as_tuple(entt)...); - } - } - - /** - * @brief Iterates entities and elements and applies the given function - * object to them. - * - * The signature of the function must be equivalent to one of the following - * (non-empty types only, constness as requested): - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - pick_and_each(func, std::index_sequence_for{}); - } - - /** - * @brief Returns an iterable object to use to _visit_ a view. - * - * The iterable object returns a tuple that contains the current entity and - * a set of references to its non-empty elements. The _constness_ of the - * elements is as requested. - * - * @return An iterable object to use to _visit_ the view. - */ - [[nodiscard]] iterable each() const noexcept { - return iterable{base_type::begin(), base_type::end()}; - } - - /** - * @brief Combines 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 - [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { - return internal::view_pack, exclude_t>>( - *this, other, std::index_sequence_for{}, std::index_sequence_for{}, std::index_sequence_for{}, std::index_sequence_for{}); - } -}; - -/** - * @brief Basic storage view implementation. - * @warning For internal use only, backward compatibility not guaranteed. - * @tparam Type Common type among all storage types. - * @tparam Policy Storage policy. - */ -template -class basic_storage_view { -protected: - /*! @cond 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, typename common_type::iterator>; - /*! @brief Reverse iterator type. */ - using reverse_iterator = std::conditional_t; - - /** - * @brief Returns the leading storage of a view, if any. - * @return The leading storage of the view. - */ - [[nodiscard]] const common_type *handle() const noexcept { - return leading; - } - - /** - * @brief Returns the number of entities that have the given element. - * @tparam Pol Dummy template parameter used for sfinae purposes only. - * @return Number of entities that have the given element. - */ - template - [[nodiscard]] std::enable_if_t 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 - [[nodiscard]] std::enable_if_t 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 - [[nodiscard]] std::enable_if_t 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 - [[nodiscard]] std::enable_if_t 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 - [[nodiscard]] std::enable_if_t 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(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 -class basic_view, exclude_t<>> - : public basic_storage_view { - using base_type = basic_storage_view; - -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>, decltype(std::declval().each())>; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view() noexcept - : base_type{} {} - - /** - * @brief Constructs a view from a storage class. - * @param value The storage for the type to iterate. - */ - basic_view(Get &value) noexcept - : base_type{&value} { - } - - /** - * @brief Constructs a view from a storage class. - * @param value The storage for the type to iterate. - */ - basic_view(std::tuple 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 - [[nodiscard]] auto *storage() const noexcept { - static_assert(std::is_same_v, typename Get::element_type>, "Invalid element type"); - return storage<0>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - static_assert(Index == 0u, "Index out of bounds"); - return static_cast(const_cast *>(base_type::handle())); - } - - /** - * @brief Assigns a storage to a view. - * @param elem A storage to assign to the view. - */ - void storage(Get &elem) noexcept { - storage<0>(elem); - } - - /** - * @brief Assigns a storage to a view. - * @tparam Index Index of the storage to assign to the view. - * @param elem A storage to assign to the view. - */ - template - void storage(Get &elem) noexcept { - static_assert(Index == 0u, "Index out of bounds"); - *this = basic_view{elem}; - } - - /** - * @brief Returns a pointer to the underlying storage. - * @return A pointer to the underlying storage. - */ - [[nodiscard]] Get *operator->() const noexcept { - return storage(); - } - - /** - * @brief Returns the element assigned to the given entity. - * @param entt A valid identifier. - * @return The element assigned to the given entity. - */ - [[nodiscard]] decltype(auto) operator[](const entity_type entt) const { - return storage()->get(entt); - } - - /** - * @brief Returns the element assigned to the given entity. - * @tparam Elem Type of the element to get. - * @param entt A valid identifier. - * @return The element assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - static_assert(std::is_same_v, typename Get::element_type>, "Invalid element type"); - return get<0>(entt); - } - - /** - * @brief Returns the element assigned to the given entity. - * @tparam Index Index of the element to get. - * @param entt A valid identifier. - * @return The element assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - if constexpr(sizeof...(Index) == 0) { - return storage()->get_as_tuple(entt); - } else { - return storage()->get(entt); - } - } - - /** - * @brief Iterates entities and elements and applies the given function - * object to them. - * - * The signature of the function must be equivalent to one of the following - * (non-empty types only, constness as requested): - * - * @code{.cpp} - * void(const entity_type, Type &); - * void(typename Type &); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - if constexpr(is_applicable_v{}, std::declval().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) { - 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(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 - [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { - return internal::view_pack, exclude_t>>( - *this, other, std::index_sequence_for{}, std::index_sequence_for<>{}, std::index_sequence_for{}, std::index_sequence_for{}); - } -}; - -/** - * @brief Deduction guide. - * @tparam Type Type of storage classes used to create the view. - * @param storage The storage for the types to iterate. - */ -template -basic_view(Type &...storage) -> basic_view, exclude_t<>>; - -/** - * @brief Deduction guide. - * @tparam Get Types of elements iterated by the view. - * @tparam Exclude Types of elements used to filter the view. - */ -template -basic_view(std::tuple, std::tuple = {}) -> basic_view, exclude_t>; - -} // namespace entt - -#endif -- cgit