1#ifndef ENTT_ENTITY_VIEW_HPP
2#define ENTT_ENTITY_VIEW_HPP
10#include "../config/config.h"
11#include "../core/iterator.hpp"
12#include "../core/type_traits.hpp"
21template<
typename Type>
22const Type *view_placeholder() {
23 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>,
"Unexpected type");
24 static const Type placeholder{};
28template<
typename It,
typename Entity>
29[[nodiscard]]
bool all_of(It first,
const It last,
const Entity
entt)
noexcept {
30 for(; (first != last) && (*first)->contains(
entt); ++first) {}
34template<
typename It,
typename Entity>
35[[nodiscard]]
bool none_of(It first,
const It last,
const Entity
entt)
noexcept {
36 for(; (first != last) && !(*first)->contains(
entt); ++first) {}
41[[nodiscard]]
bool fully_initialized(It first,
const It last)
noexcept {
42 for(
const auto *placeholder = view_placeholder<std::remove_const_t<std::remove_pointer_t<
typename std::iterator_traits<It>::value_type>>>(); (first != last) && *first != placeholder; ++first) {}
46template<
typename Result,
typename View,
typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
47[[nodiscard]] Result view_pack(
const View &view,
const Other &other, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>) {
50 elem.pools = {
view.template storage<GLhs>()..., other.template storage<GRhs>()...};
51 elem.filter = {
view.template
storage<
sizeof...(GLhs) + ELhs>()..., other.template
storage<
sizeof...(GRhs) + ERhs>()...};
56template<
typename Type, std::
size_t Get, std::
size_t Exclude>
57class view_iterator final {
58 template<
typename,
typename...>
59 friend class extended_view_iterator;
61 using iterator_type =
typename Type::const_iterator;
62 using iterator_traits = std::iterator_traits<iterator_type>;
64 [[nodiscard]]
bool valid(
const typename iterator_traits::value_type
entt)
const noexcept {
65 return ((Get != 1u) || (
entt != tombstone))
66 && internal::all_of(pools.begin(), pools.begin() + index,
entt) && internal::all_of(pools.begin() + index + 1, pools.end(),
entt)
67 && internal::none_of(filter.begin(), filter.end(),
entt);
71 for(
constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {}
75 using value_type =
typename iterator_traits::value_type;
76 using pointer =
typename iterator_traits::pointer;
77 using reference =
typename iterator_traits::reference;
78 using difference_type =
typename iterator_traits::difference_type;
79 using iterator_category = std::forward_iterator_tag;
81 constexpr view_iterator() noexcept
87 view_iterator(iterator_type first, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl,
const std::size_t idx) noexcept
95 view_iterator &operator++() noexcept {
101 view_iterator operator++(
int)
noexcept {
102 view_iterator orig = *
this;
103 return ++(*this), orig;
106 [[nodiscard]] pointer operator->() const noexcept {
110 [[nodiscard]] reference operator*() const noexcept {
111 return *operator->();
114 template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
115 friend constexpr bool operator==(
const view_iterator<LhsType, LhsArgs...> &,
const view_iterator<RhsType, RhsArgs...> &)
noexcept;
119 std::array<const Type *, Get> pools;
120 std::array<const Type *, Exclude> filter;
124template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
125[[nodiscard]]
constexpr bool operator==(
const view_iterator<LhsType, LhsArgs...> &lhs,
const view_iterator<RhsType, RhsArgs...> &rhs)
noexcept {
126 return lhs.it == rhs.it;
129template<
typename LhsType,
auto... LhsArgs,
typename RhsType,
auto... RhsArgs>
130[[nodiscard]]
constexpr bool operator!=(
const view_iterator<LhsType, LhsArgs...> &lhs,
const view_iterator<RhsType, RhsArgs...> &rhs)
noexcept {
131 return !(lhs == rhs);
134template<
typename It,
typename... Get>
135class extended_view_iterator final {
136 template<std::size_t... Index>
137 [[nodiscard]]
auto dereference(std::index_sequence<Index...>)
const noexcept {
138 return std::tuple_cat(std::make_tuple(*it),
static_cast<Get *
>(
const_cast<constness_as_t<typename Get::base_type, Get> *
>(std::get<Index>(it.pools)))->get_as_tuple(*it)...);
142 using iterator_type = It;
143 using value_type =
decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Get>().get_as_tuple({})...));
144 using pointer = input_iterator_pointer<value_type>;
145 using reference = value_type;
146 using difference_type = std::ptrdiff_t;
147 using iterator_category = std::input_iterator_tag;
148 using iterator_concept = std::forward_iterator_tag;
150 constexpr extended_view_iterator()
153 extended_view_iterator(iterator_type from)
156 extended_view_iterator &operator++() noexcept {
160 extended_view_iterator operator++(
int)
noexcept {
161 extended_view_iterator orig = *
this;
162 return ++(*this), orig;
165 [[nodiscard]] reference operator*() const noexcept {
166 return dereference(std::index_sequence_for<Get...>{});
169 [[nodiscard]] pointer operator->() const noexcept {
173 [[nodiscard]]
constexpr iterator_type base() const noexcept {
177 template<
typename... Lhs,
typename... Rhs>
178 friend bool constexpr operator==(
const extended_view_iterator<Lhs...> &,
const extended_view_iterator<Rhs...> &)
noexcept;
184template<
typename... Lhs,
typename... Rhs>
185[[nodiscard]]
constexpr bool operator==(
const extended_view_iterator<Lhs...> &lhs,
const extended_view_iterator<Rhs...> &rhs)
noexcept {
186 return lhs.it == rhs.it;
189template<
typename... Lhs,
typename... Rhs>
190[[nodiscard]]
constexpr bool operator!=(
const extended_view_iterator<Lhs...> &lhs,
const extended_view_iterator<Rhs...> &rhs)
noexcept {
191 return !(lhs == rhs);
215template<
typename,
typename,
typename>
225template<
typename Type, std::
size_t Get, std::
size_t Exclude>
227 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>,
"Unexpected type");
230 friend Return internal::view_pack(
const View &,
const Other &, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>);
232 [[
nodiscard]]
auto offset()
const noexcept {
233 ENTT_ASSERT(index !=
Get,
"Invalid view");
237 void unchecked_refresh()
noexcept {
240 if constexpr(
Get > 1u) {
242 if(pools[
pos]->size() < pools[index]->size()) {
253 filter[
pos] = internal::view_placeholder<Type>();
273 if(
const auto idx =
pos -
Get; filter[
idx] != internal::view_placeholder<Type>()) {
281 ENTT_ASSERT(
elem !=
nullptr,
"Unexpected element");
292 return internal::none_of(filter.begin(), filter.end(),
entt);
295 void use(
const std::size_t
pos)
noexcept {
308 using iterator = internal::view_iterator<common_type, Get, Exclude>;
325 return (index !=
Get) ? pools[index] :
nullptr;
344 return (index !=
Get) ?
iterator{pools[index]->end() -
static_cast<typename iterator::difference_type
>(offset()), pools, filter, index} :
iterator{};
372 auto it = pools[index]->rbegin();
373 const auto last =
it +
static_cast<typename iterator::difference_type
>(offset());
396 return (index !=
Get) && internal::fully_initialized(filter.begin(), filter.end());
405 return (index !=
Get)
406 && internal::all_of(pools.begin(), pools.end(),
entt)
407 && internal::none_of(filter.begin(), filter.end(),
entt)
408 && pools[index]->index(
entt) < offset();
412 std::array<const common_type *, Get> pools{};
413 std::array<const common_type *, Exclude> filter{};
431 :
public basic_common_view<std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>, sizeof...(Get), sizeof...(Exclude)> {
434 template<
typename Type>
437 template<std::size_t...
Index>
442 template<std::size_t
Curr, std::size_t
Other,
typename...
Args>
443 [[
nodiscard]]
auto dispatch_get(
const std::tuple<typename base_type::entity_type, Args...> &
curr)
const {
445 return std::forward_as_tuple(std::get<Args>(
curr)...);
451 template<std::size_t
Curr,
typename Func, std::size_t...
Index>
452 void each(Func &func, std::index_sequence<Index...>)
const {
457 if constexpr(
is_applicable_v<Func,
decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
466 template<
typename Func, std::size_t...
Index>
467 void pick_and_each(Func &func, std::index_sequence<Index...> seq)
const {
468 if(
const auto *
view = base_type::handle();
view !=
nullptr) {
503 basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...>
excl = {})
noexcept
510 template<
typename Type>
519 template<std::
size_t Index>
521 base_type::use(
Index);
529 template<
typename Type>
539 template<std::
size_t Index>
550 template<
typename Type>
561 template<std::
size_t Index,
typename Type>
583 template<
typename Type,
typename...
Other>
594 template<std::size_t...
Index>
596 if constexpr(
sizeof...(Index) == 0) {
597 return get(
entt, std::index_sequence_for<Get...>{});
598 }
else if constexpr(
sizeof...(Index) == 1) {
620 template<
typename Func>
622 pick_and_each(func, std::index_sequence_for<Get...>{});
635 return iterable{base_type::begin(), base_type::end()};
648 *
this,
other, std::index_sequence_for<
Get...>{}, std::index_sequence_for<
Exclude...>{}, std::index_sequence_for<
OGet...>{}, std::index_sequence_for<
OExclude...>{});
658template<
typename Type, deletion_policy Policy>
660 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>,
"Unexpected type");
668 ENTT_ASSERT(leading->policy() ==
Policy,
"Unexpected storage policy");
680 using iterator = std::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, 1u, 0u>,
typename common_type::iterator>;
682 using reverse_iterator = std::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
700 return leading ? leading->size() :
size_type{};
703 return leading ? leading->free_list() :
size_type{};
714 return leading ? leading->size() :
size_type{};
725 return !leading || leading->empty();
728 return !leading || (leading->free_list() == 0
u);
741 return leading ? leading->begin() :
iterator{};
743 return leading ? (leading->end() - leading->free_list()) :
iterator{};
756 return leading ? leading->end() :
iterator{};
789 return leading ? (leading->rbegin() + leading->free_list()) :
reverse_iterator{};
800 return empty() ?
null : *leading->begin();
802 return empty() ?
null : *(leading->end() - leading->free_list());
817 return empty() ?
null : *leading->rbegin();
822 auto it = leading->rbegin();
823 const auto last = leading->rend();
845 const auto it = leading ? leading->find(
entt) :
typename common_type::iterator{};
855 return (leading !=
nullptr);
865 return leading && leading->contains(
entt);
868 return leading && leading->contains(
entt) && (leading->index(
entt) < leading->free_list());
886template<
typename Get>
903 using iterable = std::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>,
decltype(std::declval<Get>().each())>;
921 basic_view(std::tuple<Get &> value, std::tuple<> = {})
noexcept
929 template<
typename Type =
typename Get::element_type>
931 static_assert(std::is_same_v<std::remove_const_t<Type>,
typename Get::element_type>,
"Invalid element type");
940 template<std::
size_t Index>
942 static_assert(
Index == 0
u,
"Index out of bounds");
959 template<std::
size_t Index>
961 static_assert(
Index == 0
u,
"Index out of bounds");
988 template<
typename Elem>
990 static_assert(std::is_same_v<std::remove_const_t<Elem>,
typename Get::element_type>,
"Invalid element type");
1000 template<std::size_t...
Index>
1002 if constexpr(
sizeof...(Index) == 0) {
1024 template<
typename Func>
1026 if constexpr(
is_applicable_v<Func,
decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
1027 for(
const auto pack: each()) {
1028 std::apply(func,
pack);
1031 if constexpr(std::is_void_v<typename Get::value_type>) {
1036 if(
const auto len = base_type::size();
len != 0
u) {
1037 for(
auto last =
storage()->end(), first = last -
len; first != last; ++first) {
1045 for(
const auto pack: each()) {
1046 std::apply([&func](
const auto,
auto &&...
elem) { func(std::forward<
decltype(
elem)>(
elem)...); },
pack);
1065 return iterable{base_type::begin(), base_type::end()};
1079 *
this,
other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<
OGet...>{}, std::index_sequence_for<
OExclude...>{});
1088template<
typename... Type>
1096template<
typename...
Get,
typename...
Exclude>
Basic storage view implementation.
size_type size_hint() const noexcept
Estimates the number of entities iterated by the view.
void refresh() noexcept
Updates the internal leading view if required.
Type common_type
Common type among all storage types.
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
entity_type back() const noexcept
Returns the last entity of the view, if any.
entity_type front() const noexcept
Returns the first entity of the view, if any.
std::size_t size_type
Unsigned integer type.
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
iterator find(const entity_type entt) const noexcept
Finds an entity.
internal::view_iterator< common_type, Get, Exclude > iterator
Forward iterator type.
typename Type::entity_type entity_type
Underlying entity identifier.
Basic storage view implementation.
entity_type front() const noexcept
Returns the first entity of the view, if any.
std::enable_if_t< Pol !=deletion_policy::in_place, bool > empty() const noexcept
Checks whether a view is empty.
std::conditional_t< Policy==deletion_policy::in_place, void, typename common_type::reverse_iterator > reverse_iterator
Reverse iterator type.
entity_type back() const noexcept
Returns the last entity of the view, if any.
bool contains(const entity_type entt) const noexcept
Checks if a view contains an entity.
std::enable_if_t< Pol !=deletion_policy::in_place, reverse_iterator > rend() const noexcept
Returns an iterator that is past the last entity of the reversed view.
iterator end() const noexcept
Returns an iterator that is past the last entity of the view.
std::conditional_t< Policy==deletion_policy::in_place, internal::view_iterator< common_type, 1u, 0u >, typename common_type::iterator > iterator
Random access iterator type.
std::enable_if_t< Pol==deletion_policy::in_place, size_type > size_hint() const noexcept
Estimates the number of entities iterated by the view.
std::enable_if_t< Pol !=deletion_policy::in_place, reverse_iterator > rbegin() const noexcept
Returns an iterator to the first entity of the reversed view.
std::enable_if_t< Pol !=deletion_policy::in_place, size_type > size() const noexcept
Returns the number of entities that have the given element.
std::size_t size_type
Unsigned integer type.
typename common_type::entity_type entity_type
Underlying entity identifier.
iterator begin() const noexcept
Returns an iterator to the first entity of the view.
const common_type * handle() const noexcept
Returns the leading storage of a view, if any.
Type common_type
Common type among all storage types.
iterator find(const entity_type entt) const noexcept
Finds an entity.
const value_type & get(const entity_type entt) const noexcept
Returns the object assigned to an entity.
basic_view(std::tuple< Get & > value, std::tuple<>={}) noexcept
Constructs a view from a storage class.
typename base_type::entity_type entity_type
Underlying entity identifier.
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
basic_view(Get &value) noexcept
Constructs a view from a storage class.
void storage(Get &elem) noexcept
Assigns a storage to a view.
Get * operator->() const noexcept
Returns a pointer to the underlying storage.
typename base_type::common_type common_type
Common type among all storage types.
typename base_type::reverse_iterator reverse_iterator
Reverse iterator type.
typename base_type::iterator iterator
Random access iterator type.
auto * storage() const noexcept
Returns the storage for a given element type, if any.
basic_view() noexcept
Default constructor to use to create empty, invalid views.
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
void storage(Get &elem) noexcept
Assigns a storage to a view.
typename base_type::size_type size_type
Unsigned integer type.
std::conditional_t< Get::storage_policy==deletion_policy::in_place, iterable_adaptor< internal::extended_view_iterator< iterator, Get > >, decltype(std::declval< Get >().each())> iterable
Iterable view type.
decltype(auto) get(const entity_type entt) const
Returns the element assigned to the given entity.
typename base_type::entity_type entity_type
Underlying entity identifier.
typename base_type::common_type common_type
Common type among all storage types.
basic_view() noexcept
Default constructor to use to create empty, invalid views.
void each(Func func) const
Iterates entities and elements and applies the given function object to them.
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
void storage(Type &elem) noexcept
Assigns a storage to a view.
void storage(Type &elem) noexcept
Assigns a storage to a view.
auto operator|(const basic_view< get_t< OGet... >, exclude_t< OExclude... > > &other) const noexcept
Combines two views in a more specific one.
typename base_type::iterator iterator
Forward iterator type.
iterable each() const noexcept
Returns an iterable object to use to visit a view.
decltype(auto) get(const entity_type entt) const
Returns the elements assigned to the given entity.
void use() noexcept
Forces a view to use a given element to drive iterations.
basic_view(std::tuple< Get &... > value, std::tuple< Exclude &... > excl={}) noexcept
Constructs a view from a set of storage classes.
basic_view(Get &...value, Exclude &...excl) noexcept
Constructs a view from a set of storage classes.
auto * storage() const noexcept
Returns the storage for a given element type, if any.
typename base_type::size_type size_type
Unsigned integer type.
basic_view(Type &...storage) -> basic_view< get_t< Type... >, exclude_t<> >
Deduction guide.
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
constexpr null_t null
Compile-time constant for null entities.
basic_view< type_list_transform_t< Get, storage_for >, type_list_transform_t< Exclude, storage_for > > view
Alias declaration for the most common use case.
constexpr bool is_applicable_v
Helper variable template.
constexpr tombstone_t tombstone
Compile-time constant for tombstone entities.
constexpr get_t< Type... > get
Variable template for lists of observed elements.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
deletion_policy
Storage deletion policy.
@ swap_only
Swap-only deletion policy.
@ swap_and_pop
Swap-and-pop deletion policy.
@ in_place
In-place deletion policy.
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
basic_storage< Type > storage
Alias declaration for the most common use case.
Alias for exclusion lists.
Alias for lists of observed elements.
Utility class to create an iterable object from a pair of iterators.
A class to use to push around lists of types, nothing more.