2#ifndef LIBSBX_VIEW_HPP_
3#define LIBSBX_VIEW_HPP_
11#include <libsbx/utility/type_list.hpp>
13#include <libsbx/memory/concepts.hpp>
14#include <libsbx/memory/iterable_adaptor.hpp>
16#include <libsbx/ecs/detail/view_iterator.hpp>
22template<
typename Type,
bool IsChecked, std::
size_t Get, std::
size_t Exclude>
23requires (std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>)
26 template<
typename Return,
typename View,
typename Other, std::size_t... GetLhs, std::size_t... GetRhs>
27 friend auto view_pack(
const View&,
const Other&, std::index_sequence<GetLhs...>, std::index_sequence<GetRhs...>) -> Return;
31 using common_type = Type;
32 using entity_type =
typename Type::entity_type;
33 using size_type = std::size_t;
34 using difference_type = std::ptrdiff_t;
37 auto refresh()
noexcept ->
void {
38 auto position =
static_cast<size_type
>(_index != Get) * Get;
40 for (; position < Get && _pools[position] !=
nullptr; ++position) { }
42 if (position == Get) {
47 [[nodiscard]]
auto handle()
const noexcept ->
const common_type* {
48 return (_index != Get) ? _pools[_index] :
nullptr;
51 [[nodiscard]]
auto size_hint()
const noexcept -> size_type {
52 return (_index != Get) ? _offset() : size_type{};
55 [[nodiscard]]
auto begin()
const noexcept ->
iterator {
56 return (_index != Get) ?
iterator{_pools[_index]->end() -
static_cast<difference_type
>(_offset()), _pools, _filter, _index} :
iterator{};
59 [[nodiscard]]
auto end()
const noexcept ->
iterator {
60 return (_index != Get) ?
iterator{_pools[_index]->end(), _pools, _filter, _index} :
iterator{};
63 [[nodiscard]]
auto front()
const noexcept -> entity_type {
64 const auto it = begin();
65 return it != end() ? *it : null_entity;
68 [[nodiscard]]
auto back()
const noexcept -> entity_type {
70 auto it = _pools[_index]->rbegin();
71 const auto last = it +
static_cast<difference_type
>(_offset());
73 for (
const auto idx =
static_cast<difference_type
>(_index); it != last && !(detail::all_of(_pools.begin(), _pools.begin() + idx, *it) && detail::all_of(_pools.begin() + idx + 1, _pools.end(), *it)); ++it) { }
75 return it == last ? null_entity : *it;
81 [[nodiscard]]
auto find(
const entity_type entity)
const noexcept ->
iterator {
82 return contains(entity) ?
iterator{_pools[_index]->find(entity), _pools, _index} : end();
85 [[nodiscard]]
explicit operator bool()
const noexcept {
86 return (_index != Get);
89 [[nodiscard]]
auto contains(
const entity_type entity)
const noexcept ->
bool {
90 return (_index != Get) && detail::all_of(_pools.begin(), _pools.end(), entity) && _pools[_index]->_index(entity) < _offset();
99 basic_common_view(std::array<const common_type*, Get> pools, std::array<const common_type*, Exclude> filter) noexcept
103 _unchecked_refresh();
106 [[nodiscard]]
auto pool_at(
const size_type position)
const noexcept ->
const common_type* {
107 return _pools[position];
110 auto set_pool_at(
const size_type position,
const common_type* element)
noexcept ->
void {
111 utility::assert_that(element !=
nullptr,
"Unexpected element");
112 _pools[position] = element;
116 auto use(
const size_type position)
noexcept ->
void {
117 _index = (_index != Get) ? position : Get;
122 [[nodiscard]]
auto _offset()
const noexcept {
123 utility::assert_that(_index != Get,
"Invalid view");
124 return (_pools[_index]->policy() == deletion_policy::swap_only) ? _pools[_index]->free_list() : _pools[_index]->size();
127 auto _unchecked_refresh()
noexcept ->
void {
130 if constexpr (Get > 1u) {
131 for (
auto position = 1u; position < Get; ++position) {
132 if (_pools[position]->size() < _pools[_index]->size()) {
139 std::array<const common_type*, Get> _pools;
140 std::array<const common_type*, Exclude> _filter;
145template<
typename Type, deletion_policy Policy>
146requires (std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>)
151 using common_type = Type;
152 using entity_type =
typename common_type::entity_type;
153 using size_type = std::size_t;
154 using difference_type = std::ptrdiff_t;
155 using iterator = std::conditional_t<Policy == deletion_policy::in_place, detail::view_iterator<common_type, true, 1u, 0u>,
typename common_type::iterator>;
156 using reverse_iterator = std::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
158 [[nodiscard]]
auto handle()
const noexcept ->
const common_type* {
163 requires (Pol != deletion_policy::in_place)
164 [[nodiscard]]
auto size()
const noexcept -> size_type {
165 if constexpr (Policy == deletion_policy::swap_and_pop) {
166 return _leading ? _leading->size() : size_type{};
168 static_assert(Policy == deletion_policy::swap_only,
"Unexpected storage policy");
169 return _leading ? _leading->free_list() : size_type{};
174 requires (Pol == deletion_policy::in_place)
175 [[nodiscard]]
auto size_hint()
const noexcept -> size_type {
176 return _leading ? _leading->size() : size_type{};
180 requires (Pol != deletion_policy::in_place)
181 [[nodiscard]]
auto is_empty()
const noexcept ->
bool {
182 if constexpr (Policy == deletion_policy::swap_and_pop) {
183 return !_leading || _leading->is_empty();
185 static_assert(Policy == deletion_policy::swap_only,
"Unexpected storage policy");
186 return !_leading || (_leading->free_list() == 0u);
190 [[nodiscard]]
auto begin()
const noexcept -> iterator {
191 if constexpr (Policy == deletion_policy::swap_and_pop) {
192 return _leading ? _leading->begin() : iterator{};
193 }
else if constexpr (Policy == deletion_policy::swap_only) {
194 return _leading ? (_leading->end() -
static_cast<difference_type
>(_leading->free_list())) : iterator{};
196 static_assert(Policy == deletion_policy::in_place,
"Unexpected storage policy");
197 return _leading ? iterator{_leading->begin(), {_leading}, {}, 0u} : iterator{};
201 [[nodiscard]]
auto end()
const noexcept -> iterator {
202 if constexpr (Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
203 return _leading ? _leading->end() : iterator{};
205 static_assert(Policy == deletion_policy::in_place,
"Unexpected storage policy");
206 return _leading ? iterator{_leading->end(), {_leading}, {}, 0u} : iterator{};
211 requires (Pol != deletion_policy::in_place)
212 [[nodiscard]]
auto rbegin()
const noexcept -> reverse_iterator {
213 return _leading ? _leading->rbegin() : reverse_iterator{};
217 requires (Pol != deletion_policy::in_place)
218 [[nodiscard]]
auto rend()
const noexcept -> reverse_iterator {
219 if constexpr (Policy == deletion_policy::swap_and_pop) {
220 return _leading ? _leading->rend() : reverse_iterator{};
222 static_assert(Policy == deletion_policy::swap_only,
"Unexpected storage policy");
223 return _leading ? (_leading->rbegin() +
static_cast<difference_type
>(_leading->free_list())) : reverse_iterator{};
227 [[nodiscard]]
auto front()
const noexcept -> entity_type {
228 if constexpr (Policy == deletion_policy::swap_and_pop) {
229 return is_empty() ? null_entity : *_leading->begin();
230 }
else if constexpr (Policy == deletion_policy::swap_only) {
231 return is_empty() ? null_entity : *(_leading->end() -
static_cast<difference_type
>(_leading->free_list()));
233 static_assert(Policy == deletion_policy::in_place,
"Unexpected storage policy");
234 const auto it = begin();
236 return (it == end()) ? null_entity : *it;
240 [[nodiscard]]
auto back()
const noexcept -> entity_type {
241 if constexpr (Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) {
242 return is_empty() ? null_entity : *_leading->rbegin();
244 static_assert(Policy == deletion_policy::in_place,
"Unexpected storage policy");
247 auto it = _leading->rbegin();
248 const auto last = _leading->rend();
250 for(; (it != last) && (*it == tombstone_entity); ++it) { }
252 return it == last ? null_entity : *it;
259 [[nodiscard]]
auto find(
const entity_type entity)
const noexcept -> iterator {
260 if constexpr (Policy == deletion_policy::swap_and_pop) {
261 return _leading ? _leading->find(entity) : iterator{};
262 }
else if constexpr (Policy == deletion_policy::swap_only) {
263 const auto it = _leading ? _leading->find(entity) : iterator{};
264 return _leading && (
static_cast<size_type
>(it.index()) < _leading->free_list()) ? it : iterator{};
266 return _leading ? iterator{_leading->find(entity), {_leading}, {}, 0u} : iterator{};
270 [[nodiscard]]
explicit operator bool()
const noexcept {
271 return (_leading !=
nullptr);
274 [[nodiscard]]
auto contains(
const entity_type entity)
const noexcept ->
bool {
275 if constexpr (Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::in_place) {
276 return _leading && _leading->contains(entity);
278 static_assert(Policy == deletion_policy::swap_only,
"Unexpected storage policy");
279 return _leading && _leading->contains(entity) && (_leading->index(entity) < _leading->free_list());
289 utility::assert_that(_leading->policy() == Policy,
"Unexpected storage policy");
294 const common_type* _leading;
301template<
typename... Type>
303 explicit constexpr get_t() =
default;
306template<
typename... Type>
307inline constexpr get_t<Type...> get{};
309template<
typename... Type>
311 explicit constexpr exclude_t() =
default;
314template<
typename... Type>
315inline constexpr exclude_t<Type...> exclude{};
317template<
typename,
typename>
320template<
typename... Get,
typename... Exclude>
321requires (
sizeof...(Get) != 0u)
326 template<std::
size_t Index>
327 using element_at = utility::type_list_element_t<Index,
utility::type_list<Get..., Exclude...>>;
329 template<
typename Type>
330 inline static constexpr auto index_of = utility::type_list_index_v<std::remove_const_t<Type>,
utility::type_list<
typename Get::element_type...,
typename Exclude::element_type...>>;
334 using common_type =
typename base_type::common_type;
335 using entity_type =
typename base_type::entity_type;
336 using size_type =
typename base_type::size_type;
337 using difference_type = std::ptrdiff_t;
345 basic_view(Get&... pools, Exclude&... filter) noexcept
346 :
base_type{{&pools...}, {&filter...}} { }
348 basic_view(std::tuple<Get&...> pools, std::tuple<Exclude&...> filter = {})
noexcept
349 :
basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(pools, filter))} { }
351 template<
typename Type>
352 [[nodiscard]]
auto* storage()
const noexcept {
353 return storage<index_of<Type>>();
356 template<std::
size_t Index>
357 [[nodiscard]]
auto* storage()
const noexcept {
358 return static_cast<element_at<Index>*
>(
const_cast<utility::constness_as_t<common_type, element_at<Index>
>*>(base_type::pool_at(Index)));
361 template<
typename Type>
362 auto set_storage(Type& element)
noexcept ->
void {
363 set_storage<index_of<typename Type::element_type>>(element);
366 template<std::
size_t Index,
typename Type>
367 requires (std::is_convertible_v<Type&, element_at<Index>&>)
368 void set_storage(Type& element)
noexcept {
369 base_type::set_pool_at(Index, &element);
372 template<
typename Type,
typename... Other>
373 [[nodiscard]]
auto get(
const entity_type entity)
const ->
decltype(
auto) {
374 return get<index_of<Type>, index_of<Other>...>(entity);
377 template<std::size_t... Index>
378 [[nodiscard]]
auto get(
const entity_type entity)
const ->
decltype(
auto) {
379 if constexpr(
sizeof...(Index) == 0) {
380 return _get(entity, std::index_sequence_for<Get...>{});
381 }
else if constexpr(
sizeof...(Index) == 1) {
382 return (storage<Index>()->get(entity), ...);
384 return std::tuple_cat(storage<Index>()->get_as_tuple(entity)...);
388 [[nodiscard]]
auto each()
const noexcept ->
iterable {
389 return {base_type::begin(), base_type::end()};
394 template<std::size_t... Index>
395 [[nodiscard]]
auto _get(
const entity_type entity, std::index_sequence<Index...>)
const noexcept {
396 return std::tuple_cat(storage<Index>()->get_as_tuple(entity)...);
401template<
typename Get>
408 using common_type =
typename base_type::common_type;
409 using entity_type =
typename base_type::entity_type;
410 using size_type =
typename base_type::size_type;
411 using difference_type = std::ptrdiff_t;
412 using iterator =
typename base_type::iterator;
413 using reverse_iterator =
typename base_type::reverse_iterator;
414 using iterable = std::conditional_t<Get::storage_policy == deletion_policy::in_place, memory::iterable_adaptor<detail::extended_view_iterator<iterator, Get>>,
decltype(std::declval<Get>().each())>;
425 template<
typename Type =
typename Get::element_type>
426 requires (std::is_same_v<std::remove_const_t<Type>,
typename Get::element_type>)
427 [[nodiscard]]
auto* storage()
const noexcept {
431 template<std::
size_t Index>
432 requires (Index == 0u)
433 [[nodiscard]]
auto* storage()
const noexcept {
434 return static_cast<Get*
>(
const_cast<utility::constness_as_t<common_type, Get>*
>(base_type::handle()));
437 void set_storage(Get& element)
noexcept {
438 set_storage<0>(element);
441 template<std::
size_t Index>
442 requires (Index == 0u)
443 void set_storage(Get& element)
noexcept {
447 [[nodiscard]]
auto operator->()
const noexcept -> Get* {
451 [[nodiscard]]
auto operator[](
const entity_type entity)
const ->
decltype(
auto) {
452 return storage()->get(entity);
455 template<
typename Element>
456 requires (std::is_same_v<std::remove_const_t<Element>,
typename Get::element_type>)
457 [[nodiscard]]
auto get(
const entity_type entity)
const ->
decltype(
auto) {
458 return get<0>(entity);
461 template<std::size_t... Index>
462 [[nodiscard]]
auto get(
const entity_type entity)
const ->
decltype(
auto) {
463 if constexpr(
sizeof...(Index) == 0) {
464 return storage()->get_as_tuple(entity);
466 return storage<Index...>()->get(entity);
470 [[nodiscard]]
auto each()
const noexcept -> iterable {
471 if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
472 return base_type::handle() ? storage()->each() : iterable{};
474 static_assert(Get::storage_policy == deletion_policy::in_place,
"Unexpected storage policy");
475 return iterable{base_type::begin(), base_type::end()};
481template<
typename... Type>
484template<
typename... Get,
typename... Exclude>
485basic_view(std::tuple<Get&...>, std::tuple<Exclude&...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
Definition: view_iterator.hpp:137
Definition: view_iterator.hpp:58
Definition: iterable_adaptor.hpp:11
deletion_policy
Deletion behavior policy for sparse sets.
Definition: sparse_set.hpp:56
Definition: type_list.hpp:10