|
|
@@ -192,29 +192,30 @@ template<typename... Lhs, typename... Rhs>
|
|
|
*
|
|
|
* 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, components are
|
|
|
+ * added or removed from it).
|
|
|
+ * * The entity currently returned is destroyed.
|
|
|
+ *
|
|
|
+ * In all other cases, modifying the storage iterated by a view in any way can
|
|
|
+ * invalidate all iterators.
|
|
|
*/
|
|
|
template<typename, typename, typename>
|
|
|
class basic_view;
|
|
|
|
|
|
/**
|
|
|
- * @brief Multi component view.
|
|
|
- *
|
|
|
- * Multi component views iterate over those entities that are at least in the
|
|
|
- * given storage. During initialization, a multi component view looks at the
|
|
|
- * number of entities available for each component and uses the smallest set in
|
|
|
- * order to get a performance boost when iterating.
|
|
|
- *
|
|
|
- * @b Important
|
|
|
- *
|
|
|
- * Iterators aren't invalidated if:
|
|
|
+ * @brief General purpose view.
|
|
|
*
|
|
|
- * * New elements are added to the storage.
|
|
|
- * * The entity currently pointed is modified (for example, components are added
|
|
|
- * or removed from it).
|
|
|
- * * The entity currently pointed is destroyed.
|
|
|
+ * 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.
|
|
|
*
|
|
|
- * In all other cases, modifying the storage iterated by the view in any way
|
|
|
- * invalidates all the iterators.
|
|
|
+ * @sa basic_view
|
|
|
*
|
|
|
* @tparam Get Types of storage iterated by the view.
|
|
|
* @tparam Exclude Types of storage used to filter the view.
|
|
|
@@ -559,23 +560,304 @@ private:
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
- * @brief Single component view specialization.
|
|
|
+ * @brief Single type view specialization.
|
|
|
*
|
|
|
- * Single component views are specialized in order to get a boost in terms of
|
|
|
- * performance. This kind of views can access the underlying data structure
|
|
|
- * directly and avoid superfluous checks.
|
|
|
+ * This specialization is a refinement of the general purpose view and offers a
|
|
|
+ * slightly revised interface to suit individual storage models.
|
|
|
*
|
|
|
- * @b Important
|
|
|
+ * @sa basic_view
|
|
|
*
|
|
|
- * Iterators aren't invalidated if:
|
|
|
+ * @tparam Get Type of storage iterated by the view.
|
|
|
+ * @tparam Exclude Types of storage used to filter the view.
|
|
|
+ */
|
|
|
+template<typename Get, typename... Exclude>
|
|
|
+class basic_view<get_t<Get>, exclude_t<Exclude...>> {
|
|
|
+ template<typename, typename, typename>
|
|
|
+ friend class basic_view;
|
|
|
+
|
|
|
+ template<typename Type>
|
|
|
+ static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::value_type, typename Exclude::value_type...>>;
|
|
|
+
|
|
|
+public:
|
|
|
+ /*! @brief Common type among all storage types. */
|
|
|
+ using common_type = std::common_type_t<typename Get::base_type, typename Exclude::base_type...>;
|
|
|
+ /*! @brief Underlying entity identifier. */
|
|
|
+ using entity_type = typename common_type::entity_type;
|
|
|
+ /*! @brief Unsigned integer type. */
|
|
|
+ using size_type = std::size_t;
|
|
|
+ /*! @brief Bidirectional iterator type. */
|
|
|
+ using iterator = internal::view_iterator<common_type, 0u, sizeof...(Exclude)>;
|
|
|
+ /*! @brief Iterable view type. */
|
|
|
+ using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, Get>>;
|
|
|
+
|
|
|
+ /*! @brief Default constructor to use to create empty, invalid views. */
|
|
|
+ basic_view() noexcept
|
|
|
+ : pools{},
|
|
|
+ filter{} {}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @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
|
|
|
+ : pools{&value},
|
|
|
+ filter{&excl...} {
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Constructs a view from a set of storage classes.
|
|
|
+ * @param value The storage for the types to iterate.
|
|
|
+ * @param excl The storage for the types used to filter the view.
|
|
|
+ */
|
|
|
+ basic_view(std::tuple<Get &> value, std::tuple<Exclude &...> excl = {}) noexcept
|
|
|
+ : basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(value, excl))} {}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Returns the leading storage of a view, if any.
|
|
|
+ * @return The leading storage of the view.
|
|
|
+ */
|
|
|
+ [[nodiscard]] const common_type *handle() const noexcept {
|
|
|
+ return storage<0>();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Returns the storage for a given component type, if any.
|
|
|
+ * @tparam Type Type of component of which to return the storage.
|
|
|
+ * @return The storage for the given component type.
|
|
|
+ */
|
|
|
+ template<typename Type>
|
|
|
+ [[nodiscard]] auto *storage() const noexcept {
|
|
|
+ return storage<index_of<Type>>();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Returns the storage for a given index, if any.
|
|
|
+ * @tparam Index Index of the storage to return.
|
|
|
+ * @return The storage for the given index.
|
|
|
+ */
|
|
|
+ template<std::size_t Index>
|
|
|
+ [[nodiscard]] auto *storage() const noexcept {
|
|
|
+ return std::get<Index>(std::tuple_cat(pools, internal::filter_as_tuple<Exclude...>(filter, std::index_sequence_for<Exclude...>{})));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Assigns a storage to a view.
|
|
|
+ * @tparam Type Type of storage to assign to the view.
|
|
|
+ * @param elem A storage to assign to the view.
|
|
|
+ */
|
|
|
+ template<typename Type>
|
|
|
+ void storage(Type &elem) noexcept {
|
|
|
+ storage<index_of<typename Type::value_type>>(elem);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Assigns a storage to a view.
|
|
|
+ * @tparam Index Index of the storage to assign to the view.
|
|
|
+ * @tparam Type Type of storage to assign to the view.
|
|
|
+ * @param elem A storage to assign to the view.
|
|
|
+ */
|
|
|
+ template<std::size_t Index, typename Type>
|
|
|
+ void storage(Type &elem) noexcept {
|
|
|
+ if constexpr(Index == 0u) {
|
|
|
+ std::get<Index>(pools) = &elem;
|
|
|
+ } else {
|
|
|
+ std::get<Index - 1u>(filter) = &elem;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @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 handle() ? handle()->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 handle() ? iterator{handle()->begin(), handle()->end(), std::array<const common_type *, 0u>{}, filter} : 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 handle() ? iterator{handle()->end(), handle()->end(), std::array<const common_type *, 0u>{}, filter} : 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(auto *view = handle(); view) {
|
|
|
+ auto it = view->rbegin();
|
|
|
+ for(const auto last = view->rend(); it != last && !contains(*it); ++it) {}
|
|
|
+ return it == view->rend() ? 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{handle()->find(entt), handle()->end(), std::array<const common_type *, 0u>{}, filter} : end();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Returns the components assigned to the given entity.
|
|
|
+ * @param entt A valid identifier.
|
|
|
+ * @return The components assigned to the given entity.
|
|
|
+ */
|
|
|
+ [[nodiscard]] decltype(auto) operator[](const entity_type entt) const {
|
|
|
+ return get(entt);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @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 handle() && internal::fully_initialized(filter);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @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 handle() && handle()->contains(entt) && internal::none_of(filter, entt);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Returns the component assigned to the given entity.
|
|
|
+ * @tparam Elem Type of the component to get.
|
|
|
+ * @param entt A valid identifier.
|
|
|
+ * @return The component assigned to the entity.
|
|
|
+ */
|
|
|
+ template<typename Elem>
|
|
|
+ [[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
|
|
+ static_assert(std::is_same_v<std::remove_const_t<Elem>, typename Get::value_type>, "Invalid component type");
|
|
|
+ return get<0>(entt);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Returns the component assigned to the given entity.
|
|
|
+ * @tparam Index Index of the component to get.
|
|
|
+ * @param entt A valid identifier.
|
|
|
+ * @return The component assigned to the entity.
|
|
|
+ */
|
|
|
+ template<std::size_t... Index>
|
|
|
+ [[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
|
|
+ if constexpr(sizeof...(Index) == 0) {
|
|
|
+ return std::get<0>(pools)->get_as_tuple(entt);
|
|
|
+ } else {
|
|
|
+ return std::get<Index...>(pools)->get(entt);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Iterates entities and components and applies the given function
|
|
|
+ * object to them.
|
|
|
+ *
|
|
|
+ * The signature of the function must be equivalent to one of the following
|
|
|
+ * (non-empty types only, constness as requested):
|
|
|
+ *
|
|
|
+ * @code{.cpp}
|
|
|
+ * void(const entity_type, Type &...);
|
|
|
+ * void(Type &...);
|
|
|
+ * @endcode
|
|
|
+ *
|
|
|
+ * @tparam Func Type of the function object to invoke.
|
|
|
+ * @param func A valid function object.
|
|
|
+ */
|
|
|
+ template<typename Func>
|
|
|
+ void each(Func func) const {
|
|
|
+ if(auto *view = storage<0>(); view) {
|
|
|
+ for(auto curr: view->each()) {
|
|
|
+ if(const auto entt = std::get<0>(curr); (!Get::traits_type::in_place_delete || (entt != tombstone)) && internal::none_of(filter, entt)) {
|
|
|
+ if constexpr(is_applicable_v<Func, decltype(curr)>) {
|
|
|
+ std::apply(func, curr);
|
|
|
+ } else {
|
|
|
+ func(std::get<1>(curr));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @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 components. The _constness_ of the
|
|
|
+ * components is as requested.
|
|
|
+ *
|
|
|
+ * @return An iterable object to use to _visit_ the view.
|
|
|
+ */
|
|
|
+ [[nodiscard]] iterable each() const noexcept {
|
|
|
+ if(auto *view = storage<0>(); view) {
|
|
|
+ auto elem = view->each();
|
|
|
+ iterator from{elem.begin().base(), elem.end().base(), std::array<const common_type *, 0u>{}, filter};
|
|
|
+ iterator to{elem.end().base(), elem.end().base(), std::array<const common_type *, 0u>{}, filter};
|
|
|
+ return iterable{internal::extended_view_iterator{from, pools}, internal::extended_view_iterator{to, pools}};
|
|
|
+ }
|
|
|
+
|
|
|
+ return {};
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Combines two views in a _more specific_ one (friend function).
|
|
|
+ * @tparam OGet Component list of the view to combine with.
|
|
|
+ * @tparam OExclude Filter list of the view to combine with.
|
|
|
+ * @param other The view to combine with.
|
|
|
+ * @return A more specific view.
|
|
|
+ */
|
|
|
+ template<typename... OGet, typename... OExclude>
|
|
|
+ [[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
|
|
|
+ return internal::view_pack(
|
|
|
+ std::tuple_cat(pools, other.pools),
|
|
|
+ std::tuple_cat(internal::filter_as_tuple<Exclude...>(filter, std::index_sequence_for<Exclude...>{}), internal::filter_as_tuple<OExclude...>(other.filter, std::index_sequence_for<OExclude...>{})),
|
|
|
+ std::index_sequence_for<Get, OGet..., Exclude..., OExclude...>{});
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ std::tuple<Get *> pools;
|
|
|
+ std::array<const common_type *, sizeof...(Exclude)> filter;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * @brief Storage view specialization.
|
|
|
*
|
|
|
- * * New elements are added to the storage.
|
|
|
- * * The entity currently pointed is modified (for example, components are added
|
|
|
- * or removed from it).
|
|
|
- * * The entity currently pointed is destroyed.
|
|
|
+ * This specialization offers a boost in terms of performance. It can access the
|
|
|
+ * underlying data structure directly and avoid superfluous checks.
|
|
|
*
|
|
|
- * In all other cases, modifying the storage iterated by the view in any way
|
|
|
- * invalidates all the iterators.
|
|
|
+ * @sa basic_view
|
|
|
*
|
|
|
* @tparam Get Type of storage iterated by the view.
|
|
|
*/
|