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/group.hpp | 1057 ------------------------------------ 1 file changed, 1057 deletions(-) delete mode 100644 deps/include/entt/entity/group.hpp (limited to 'deps/include/entt/entity/group.hpp') 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 -- cgit