Class basic_view< Entity, exclude_t<>, Component >

Synopsis

#include <src/entt/entity/view.hpp>

template<typename Entity, typename Component>
class basic_view<Entity, exclude_t<>, Component> final

Description

Single component 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.

Important

Iterators aren't invalidated if:

  • New instances of the given component are created and assigned to entities.
  • The entity currently pointed is modified (as an example, the given component is removed from the entity to which the iterator points).
  • The entity currently pointed is destroyed.

In all other cases, modifying the pool iterated by the view in any way invalidates all the iterators and using them results in undefined behavior.

Note
Views share a reference to the underlying data structure of the registry that generated them. Therefore any change to the entities and to the components made by means of the registry are immediately reflected by views.
Warning
Lifetime of a view must not overcome that of the registry that generated it. In any other case, attempting to use a view results in undefined behavior.
Template Parameters

Entity - A valid entity type (see entt_traits for more details).

Component - Type of component iterated by the view.

Methods

backReturns the last entity of the view, if any.
basic_view overloadDefault constructor to use to create empty, invalid views.
basic_view overloadConstructs a single-type view from a storage class.
beginReturns an iterator to the first entity of the view.
containsChecks if a view contains an entity.
dataDirect access to the list of entities.
each overloadIterates entities and components and applies the given function object to them.
each overloadReturns an iterable object to use to visit the view.
emptyChecks whether a view is empty.
endReturns an iterator that is past the last entity of the view.
findFinds an entity.
frontReturns the first entity of the view, if any.
getReturns the component assigned to the given entity.
operator boolChecks if a view is properly initialized.
operator[]Returns the identifier that occupies the given position.
rawDirect access to the list of components.
rbeginReturns an iterator to the first entity of the reversed view.
rendReturns an iterator that is past the last entity of the reversed view.
sizeReturns the number of entities that have the given component.

Source

Lines 575-936 in src/entt/entity/view.hpp.

template<typename Entity, typename Component>
class basic_view<Entity, exclude_t<>, Component> final {
    using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;

    class iterable_view {
        friend class basic_view<Entity, exclude_t<>, Component>;

        template<typename... It>
        class iterable_view_iterator {
            friend class iterable_view;

            iterable_view_iterator() ENTT_NOEXCEPT
                : iterable_view_iterator{It{}...}
            {}

            template<typename... Discard>
            iterable_view_iterator(It... from, Discard...) ENTT_NOEXCEPT
                : it{from...}
            {}

        public:
            using difference_type = std::ptrdiff_t;
            using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_view>().get({})));
            using pointer = void;
            using reference = value_type;
            using iterator_category = std::input_iterator_tag;

            iterable_view_iterator & operator++() ENTT_NOEXCEPT {
                return (++std::get<It>(it), ...), *this;
            }

            iterable_view_iterator operator++(int) ENTT_NOEXCEPT {
                iterable_view_iterator orig = *this;
                return ++(*this), orig;
            }

            [[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
                return { *std::get<It>(it)... };
            }

            [[nodiscard]] bool operator==(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
                return std::get<0>(other.it) == std::get<0>(it);
            }

            [[nodiscard]] bool operator!=(const iterable_view_iterator &other) const ENTT_NOEXCEPT {
                return !(*this == other);
            }

        private:
            std::tuple<It...> it;
        };

        iterable_view(storage_type * const ref)
            : pool{ref}
        {}

    public:
        using iterator = std::conditional_t<
            std::is_same_v<typename storage_type::storage_category, empty_storage_tag>,
            iterable_view_iterator<typename basic_sparse_set<Entity>::iterator>,
            iterable_view_iterator<typename basic_sparse_set<Entity>::iterator, decltype(std::declval<storage_type>().begin())>
        >;
        using reverse_iterator = std::conditional_t<
            std::is_same_v<typename storage_type::storage_category, empty_storage_tag>,
            iterable_view_iterator<typename basic_sparse_set<Entity>::reverse_iterator>,
            iterable_view_iterator<typename basic_sparse_set<Entity>::reverse_iterator, decltype(std::declval<storage_type>().rbegin())>
        >;

        [[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
            return pool ? iterator{pool->basic_sparse_set<entity_type>::begin(), pool->begin()} : iterator{};
        }

        [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
            return pool ? iterator{pool->basic_sparse_set<entity_type>::end(), pool->end()} : iterator{};
        }

        [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
            return pool ? reverse_iterator{pool->basic_sparse_set<entity_type>::rbegin(), pool->rbegin()} : reverse_iterator{};
        }

        [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
            return pool ? reverse_iterator{pool->basic_sparse_set<entity_type>::rend(), pool->rend()} : reverse_iterator{};
        }

    private:
        storage_type * const pool;
    };

public:
    /*! @brief Type of component iterated by the view. */
    using raw_type = Component;
    /*! @brief Underlying entity identifier. */
    using entity_type = Entity;
    /*! @brief Unsigned integer type. */
    using size_type = std::size_t;
    /*! @brief Random access iterator type. */
    using iterator = typename basic_sparse_set<Entity>::iterator;
    /*! @brief Reversed iterator type. */
    using reverse_iterator = typename basic_sparse_set<Entity>::reverse_iterator;

    /*! @brief Default constructor to use to create empty, invalid views. */
    basic_view() ENTT_NOEXCEPT
        : pool{}
    {}

    /**
     * @brief Constructs a single-type view from a storage class.
     * @param ref The storage for the type to iterate.
     */
    basic_view(storage_type &ref) ENTT_NOEXCEPT
        : pool{&ref}
    {}

    /**
     * @brief Returns the number of entities that have the given component.
     * @return Number of entities that have the given component.
     */
    [[nodiscard]] size_type size() const ENTT_NOEXCEPT {
        return *this ? pool->size() : size_type{};
    }

    /**
     * @brief Checks whether a view is empty.
     * @return True if the view is empty, false otherwise.
     */
    [[nodiscard]] bool empty() const ENTT_NOEXCEPT {
        return !*this || pool->empty();
    }

    /**
     * @brief Direct access to the list of components.
     *
     * The returned pointer is such that range `[raw(), raw() + size())` is
     * always a valid range, even if the container is empty.
     *
     * @return A pointer to the array of components.
     */
    [[nodiscard]] raw_type * raw() const ENTT_NOEXCEPT {
        return *this ? pool->raw() : nullptr;
    }

    /**
     * @brief Direct access to the list of entities.
     *
     * The returned pointer is such that range `[data(), data() + size())` is
     * always a valid range, even if the container is empty.
     *
     * @return A pointer to the array of entities.
     */
    [[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
        return *this ? pool->data() : nullptr;
    }

    /**
     * @brief Returns an iterator to the first entity of the view.
     *
     * The returned iterator points 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 ENTT_NOEXCEPT {
        return *this ? pool->basic_sparse_set<entity_type>::begin() : iterator{};
    }

    /**
     * @brief Returns an iterator that is past the last entity of the view.
     *
     * The returned iterator points to the entity following the last entity of
     * the view. Attempting to dereference the returned iterator results in
     * undefined behavior.
     *
     * @return An iterator to the entity following the last entity of the view.
     */
    [[nodiscard]] iterator end() const ENTT_NOEXCEPT {
        return *this ? pool->basic_sparse_set<entity_type>::end() : iterator{};
    }

    /**
     * @brief Returns an iterator to the first entity of the reversed view.
     *
     * The returned iterator points to the first entity of the reversed view. If
     * the view is empty, the returned iterator will be equal to `rend()`.
     *
     * @return An iterator to the first entity of the reversed view.
     */
    [[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
        return *this ? pool->basic_sparse_set<entity_type>::rbegin() : reverse_iterator{};
    }

    /**
     * @brief Returns an iterator that is past the last entity of the reversed
     * view.
     *
     * The returned iterator points to the entity following the last entity of
     * the reversed view. Attempting to dereference the returned iterator
     * results in undefined behavior.
     *
     * @return An iterator to the entity following the last entity of the
     * reversed view.
     */
    [[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
        return *this ? pool->basic_sparse_set<entity_type>::rend() : 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 {
        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 {
        const auto it = rbegin();
        return it != rend() ? *it : null;
    }

    /**
     * @brief Finds an entity.
     * @param entt A valid entity 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 {
        const auto it = *this ? pool->find(entt) : end();
        return it != end() && *it == entt ? it : end();
    }

    /**
     * @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 view is properly initialized.
     * @return True if the view is properly initialized, false otherwise.
     */
    [[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
        return pool != nullptr;
    }

    /**
     * @brief Checks if a view contains an entity.
     * @param entt A valid entity identifier.
     * @return True if the view contains the given entity, false otherwise.
     */
    [[nodiscard]] bool contains(const entity_type entt) const {
        return *this && pool->contains(entt);
    }

    /**
     * @brief Returns the component assigned to the given entity.
     *
     * Prefer this function instead of `registry::get` during iterations. It has
     * far better performance than its counterpart.
     *
     * @warning
     * Attempting to use an invalid component type results in a compilation
     * error. Attempting to use an entity that doesn't belong to the view
     * results in undefined behavior.
     *
     * @tparam Comp Types of components to get.
     * @param entt A valid entity identifier.
     * @return The component assigned to the entity.
     */
    template<typename... Comp>
    [[nodiscard]] decltype(auto) get(const entity_type entt) const {
        ENTT_ASSERT(contains(entt));

        if constexpr(sizeof...(Comp) == 0) {
            if constexpr(std::is_same_v<typename storage_type::storage_category, empty_storage_tag>) {
                return std::make_tuple();
            } else {
                return std::forward_as_tuple(pool->get(entt));
            }
        } else {
            static_assert(std::is_same_v<Comp..., Component>, "Invalid component type");
            return pool->get(entt);
        }
    }

    /**
     * @brief Iterates entities and components 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 reference to the component if it's a non-empty one.
     * The _constness_ of the component is as requested.<br/>
     * The signature of the function must be equivalent to one of the following
     * forms:
     *
     * @code{.cpp}
     * void(const entity_type, Component &);
     * void(Component &);
     * @endcode
     *
     * @note
     * Empty types aren't explicitly instantiated and therefore they are never
     * returned during iterations.
     *
     * @tparam Func Type of the function object to invoke.
     * @param func A valid function object.
     */
    template<typename Func>
    void each(Func func) const {
        if constexpr(std::is_same_v<typename storage_type::storage_category, empty_storage_tag>) {
            if constexpr(std::is_invocable_v<Func>) {
                for(auto pos = size(); pos; --pos) {
                    func();
                }
            } else {
                for(auto &&component: *this) {
                    func(component);
                }
            }
        } else {
            if constexpr(is_applicable_v<Func, decltype(*each().begin())>) {
                for(const auto pack: each()) {
                    std::apply(func, pack);
                }
            } else {
                if(*this) {
                    for(auto &&component: *pool) {
                        func(component);
                    }
                }
            }
        }
    }

    /**
     * @brief Returns an iterable object to use to _visit_ the view.
     *
     * The iterable object returns tuples that contain the current entity and a
     * reference to its component if it's a non-empty one. The _constness_ of
     * the component 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 view.
     */
    [[nodiscard]] iterable_view each() const ENTT_NOEXCEPT {
        return iterable_view{pool};
    }

private:
    storage_type * const pool;
};





Add Discussion

Log in to comment