2#include "gaia/config/config.h"
5#include <initializer_list>
9#include "gaia/cnt/darray.h"
10#include "gaia/core/iterator.h"
11#include "gaia/core/utility.h"
12#include "gaia/mem/data_layout_policy.h"
13#include "gaia/mem/mem_utils.h"
17 using sparse_id = uint64_t;
20 using difference_type = uint32_t;
21 using size_type = uint32_t;
23 constexpr static sparse_id InvalidSparseId = (sparse_id)-1;
24 constexpr static size_type InvalidDenseId = BadIndex - 1;
26 template <
typename T, u
int32_t PageCapacity,
typename Allocator,
typename>
32 static sparse_id get(
const T& item)
noexcept {
36 "Sparse_storage items require a conversion function to be defined in gaia::cnt namespace");
37 return detail::InvalidSparseId;
41 template <
typename T, u
int32_t PageCapacity,
typename Allocator,
typename =
void>
47 using difference_type = detail::difference_type;
48 using size_type = detail::size_type;
52 static_assert((PageCapacity & (PageCapacity - 1)) == 0,
"PageCapacity of sparse_iterator must be a power of 2");
53 constexpr static sparse_id page_mask = PageCapacity - 1;
54 constexpr static sparse_id to_page_index = core::count_bits(page_mask);
64 reference operator*()
const {
65 const auto sid = *m_pDense;
66 const auto pid = uint32_t(sid >> to_page_index);
67 const auto did = uint32_t(sid & page_mask);
68 auto& page = m_pPages[pid];
69 return page.set_data(did);
71 pointer operator->()
const {
72 const auto sid = *m_pDense;
73 const auto pid = uint32_t(sid >> to_page_index);
74 const auto did = uint32_t(sid & page_mask);
75 auto& page = m_pPages[pid];
76 return &page.set_data(did);
78 iterator operator[](size_type offset)
const {
79 return {m_pDense + offset, m_pPages};
82 iterator& operator+=(size_type diff) {
86 iterator& operator-=(size_type diff) {
109 iterator operator+(size_type offset)
const {
110 return {m_pDense + offset, m_pPages};
112 iterator operator-(size_type offset)
const {
113 return {m_pDense - offset, m_pPages};
115 difference_type operator-(
const iterator& other)
const {
116 return (difference_type)(m_pDense - other.m_pDense);
119 GAIA_NODISCARD
bool operator==(
const iterator& other)
const {
120 return m_pDense == other.m_pDense;
122 GAIA_NODISCARD
bool operator!=(
const iterator& other)
const {
123 return m_pDense != other.m_pDense;
125 GAIA_NODISCARD
bool operator>(
const iterator& other)
const {
126 return m_pDense > other.m_pDense;
128 GAIA_NODISCARD
bool operator>=(
const iterator& other)
const {
129 return m_pDense >= other.m_pDense;
131 GAIA_NODISCARD
bool operator<(
const iterator& other)
const {
132 return m_pDense < other.m_pDense;
134 GAIA_NODISCARD
bool operator<=(
const iterator& other)
const {
135 return m_pDense <= other.m_pDense;
139 template <
typename T, u
int32_t PageCapacity,
typename Allocator,
typename =
void>
142 using value_type = T;
143 using pointer =
const T*;
144 using reference =
const T&;
145 using difference_type = detail::difference_type;
146 using size_type = detail::size_type;
150 static_assert((PageCapacity & (PageCapacity - 1)) == 0,
"PageCapacity of sparse_iterator must be a power of 2");
151 constexpr static sparse_id page_mask = PageCapacity - 1;
152 constexpr static sparse_id to_page_index = core::count_bits(page_mask);
156 const sparse_id* m_pDense;
162 reference operator*()
const {
163 const auto sid = *m_pDense;
164 const auto pid = uint32_t(sid >> to_page_index);
165 const auto did = uint32_t(sid & page_mask);
166 auto& page = m_pPages[pid];
167 return page.get_data(did);
169 pointer operator->()
const {
170 const auto sid = *m_pDense;
171 const auto pid = uint32_t(sid >> to_page_index);
172 const auto did = uint32_t(sid & page_mask);
173 auto& page = m_pPages[pid];
174 return &page.get_data(did);
176 iterator operator[](size_type offset)
const {
177 return {m_pDense + offset, m_pPages};
180 iterator& operator+=(size_type diff) {
184 iterator& operator-=(size_type diff) {
207 iterator operator+(size_type offset)
const {
208 return {m_pDense + offset, m_pPages};
210 iterator operator-(size_type offset)
const {
211 return {m_pDense - offset, m_pPages};
213 difference_type operator-(
const iterator& other)
const {
214 return (difference_type)(m_pDense - other.m_pDense);
217 GAIA_NODISCARD
bool operator==(
const iterator& other)
const {
218 return m_pDense == other.m_pDense;
220 GAIA_NODISCARD
bool operator!=(
const iterator& other)
const {
221 return m_pDense != other.m_pDense;
223 GAIA_NODISCARD
bool operator>(
const iterator& other)
const {
224 return m_pDense > other.m_pDense;
226 GAIA_NODISCARD
bool operator>=(
const iterator& other)
const {
227 return m_pDense >= other.m_pDense;
229 GAIA_NODISCARD
bool operator<(
const iterator& other)
const {
230 return m_pDense < other.m_pDense;
232 GAIA_NODISCARD
bool operator<=(
const iterator& other)
const {
233 return m_pDense <= other.m_pDense;
237 template <
typename T, u
int32_t PageCapacity,
typename Allocator>
238 struct sparse_iterator<T, PageCapacity, Allocator, std::enable_if_t<std::is_empty_v<T>>> {
240 using value_type = sparse_id;
243 using difference_type = detail::difference_type;
244 using size_type = detail::size_type;
248 static_assert((PageCapacity & (PageCapacity - 1)) == 0,
"PageCapacity of sparse_iterator must be a power of 2");
249 constexpr static sparse_id page_mask = PageCapacity - 1;
250 constexpr static sparse_id to_page_index = core::count_bits(page_mask);
254 value_type* m_pDense;
258 sparse_iterator(
const value_type* pDense): m_pDense(
const_cast<value_type*
>(pDense)) {}
260 value_type operator*()
const {
261 const auto sid = *m_pDense;
264 value_type operator->()
const {
265 const auto sid = *m_pDense;
268 iterator operator[](size_type offset)
const {
269 return {m_pDense + offset};
272 iterator& operator+=(size_type diff) {
276 iterator& operator-=(size_type diff) {
299 iterator operator+(size_type offset)
const {
300 return {m_pDense + offset};
302 iterator operator-(size_type offset)
const {
303 return {m_pDense - offset};
305 difference_type operator-(
const iterator& other)
const {
306 return (difference_type)(m_pDense - other.m_pDense);
309 GAIA_NODISCARD
bool operator==(
const iterator& other)
const {
310 return m_pDense == other.m_pDense;
312 GAIA_NODISCARD
bool operator!=(
const iterator& other)
const {
313 return m_pDense != other.m_pDense;
315 GAIA_NODISCARD
bool operator>(
const iterator& other)
const {
316 return m_pDense > other.m_pDense;
318 GAIA_NODISCARD
bool operator>=(
const iterator& other)
const {
319 return m_pDense >= other.m_pDense;
321 GAIA_NODISCARD
bool operator<(
const iterator& other)
const {
322 return m_pDense < other.m_pDense;
324 GAIA_NODISCARD
bool operator<=(
const iterator& other)
const {
325 return m_pDense <= other.m_pDense;
329 template <
typename T, u
int32_t PageCapacity,
typename Allocator>
332 using value_type = sparse_id;
335 using difference_type = detail::difference_type;
336 using size_type = detail::size_type;
340 static_assert((PageCapacity & (PageCapacity - 1)) == 0,
"PageCapacity of sparse_iterator must be a power of 2");
341 constexpr static sparse_id page_mask = PageCapacity - 1;
342 constexpr static sparse_id to_page_index = core::count_bits(page_mask);
346 value_type* m_pDense;
351 value_type operator*()
const {
352 const auto sid = *m_pDense;
355 value_type operator->()
const {
356 const auto sid = *m_pDense;
359 iterator operator[](size_type offset)
const {
360 return {m_pDense + offset};
363 iterator& operator+=(size_type diff) {
367 iterator& operator-=(size_type diff) {
390 iterator operator+(size_type offset)
const {
391 return {m_pDense + offset};
393 iterator operator-(size_type offset)
const {
394 return {m_pDense - offset};
396 difference_type operator-(
const iterator& other)
const {
397 return (difference_type)(m_pDense - other.m_pDense);
400 GAIA_NODISCARD
bool operator==(
const iterator& other)
const {
401 return m_pDense == other.m_pDense;
403 GAIA_NODISCARD
bool operator!=(
const iterator& other)
const {
404 return m_pDense != other.m_pDense;
406 GAIA_NODISCARD
bool operator>(
const iterator& other)
const {
407 return m_pDense > other.m_pDense;
409 GAIA_NODISCARD
bool operator>=(
const iterator& other)
const {
410 return m_pDense >= other.m_pDense;
412 GAIA_NODISCARD
bool operator<(
const iterator& other)
const {
413 return m_pDense < other.m_pDense;
415 GAIA_NODISCARD
bool operator<=(
const iterator& other)
const {
416 return m_pDense <= other.m_pDense;
421 template <
typename T, u
int32_t PageCapacity,
typename Allocator,
typename =
void>
424 using value_type = T;
425 using reference = T&;
426 using const_reference =
const T&;
428 using const_pointer =
const T*;
430 using difference_type = detail::difference_type;
431 using size_type = detail::size_type;
437 size_type* m_pSparse =
nullptr;
438 uint8_t* m_pData =
nullptr;
442 if (m_pSparse !=
nullptr)
447 m_pSparse = mem::AllocHelper::alloc<size_type>(
"SparsePage", PageCapacity);
448 GAIA_FOR(PageCapacity) m_pSparse[i] = detail::InvalidDenseId;
451 m_pData = view_policy::template alloc<Allocator>(PageCapacity);
454 void dtr_data_inter(uint32_t idx)
noexcept {
455 GAIA_ASSERT(!empty());
457 auto* ptr = &data()[idx];
458 core::call_dtor(ptr);
461 void dtr_active_data()
noexcept {
462 GAIA_ASSERT(m_pSparse !=
nullptr);
464 for (uint32_t i = 0; m_cnt != 0 && i != PageCapacity; ++i) {
465 if (m_pSparse[i] == detail::InvalidDenseId)
468 auto* ptr = &data()[i];
469 core::call_dtor(ptr);
474 if (m_pSparse ==
nullptr)
482 mem::AllocHelper::free(
"SparsePage", m_pSparse);
483 view_policy::template free<Allocator>(m_pData, m_cnt);
495 if (other.m_pSparse ==
nullptr) {
500 for (uint32_t i = 0; i < PageCapacity; ++i) {
502 m_pSparse[i] = other.m_pSparse[i];
503 if (other.m_pSparse[i] == detail::InvalidDenseId)
507 add_data(i, other.set_data(i));
515 GAIA_ASSERT(core::addressof(other) !=
this);
517 if (other.m_pSparse ==
nullptr) {
524 if (m_pSparse !=
nullptr)
528 for (uint32_t i = 0; i < PageCapacity; ++i) {
530 m_pSparse[i] = other.m_pSparse[i];
531 if (other.m_pSparse[i] == detail::InvalidDenseId)
535 add_data(i, other.get_data(i));
545 m_pSparse = other.m_pSparse;
546 m_pData = other.m_pData;
549 other.m_pSparse =
nullptr;
550 other.m_pData =
nullptr;
551 other.m_cnt = size_type(0);
555 GAIA_ASSERT(core::addressof(other) !=
this);
559 m_pSparse = other.m_pSparse;
560 m_pData = other.m_pData;
563 other.m_pSparse =
nullptr;
564 other.m_pData =
nullptr;
565 other.m_cnt = size_type(0);
574 GAIA_CLANG_WARNING_PUSH()
576 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
578 GAIA_NODISCARD pointer data()
noexcept {
579 return reinterpret_cast<pointer
>(m_pData);
582 GAIA_NODISCARD const_pointer data()
const noexcept {
583 return reinterpret_cast<const_pointer
>(m_pData);
586 GAIA_NODISCARD
auto& set_id(size_type pos)
noexcept {
587 return m_pSparse[pos];
590 GAIA_NODISCARD
auto get_id(size_type pos)
const noexcept {
591 return m_pSparse[pos];
594 GAIA_NODISCARD
decltype(
auto) set_data(size_type pos)
noexcept {
595 return view_policy::set({(
typename view_policy::TargetCastType)m_pData, PageCapacity}, pos);
598 GAIA_NODISCARD
decltype(
auto) get_data(size_type pos)
const noexcept {
599 return view_policy::get({(
typename view_policy::TargetCastType)m_pData, PageCapacity}, pos);
602 GAIA_CLANG_WARNING_POP()
604 GAIA_NODISCARD
bool allocated()
const noexcept {
605 return m_pSparse !=
nullptr;
613 decltype(
auto) add_data(uint32_t idx,
const T& arg) {
614 auto* ptr = &set_data(idx);
615 core::call_ctor(ptr, arg);
616 return (reference)(*ptr);
619 decltype(
auto) add_data(uint32_t idx, T&& arg) {
620 auto* ptr = &set_data(idx);
621 core::call_ctor(ptr, GAIA_MOV(arg));
622 return (reference)(*ptr);
625 void del_data(uint32_t idx)
noexcept {
628 GAIA_ASSERT(m_cnt > 0);
636 GAIA_NODISCARD size_type size()
const noexcept {
640 GAIA_NODISCARD
bool empty()
const noexcept {
644 GAIA_NODISCARD
decltype(
auto) front()
noexcept {
645 GAIA_ASSERT(!empty());
646 return (reference)*begin();
649 GAIA_NODISCARD
decltype(
auto) front()
const noexcept {
650 GAIA_ASSERT(!empty());
651 return (const_reference)*begin();
654 GAIA_NODISCARD
decltype(
auto) back()
noexcept {
655 GAIA_ASSERT(!empty());
656 return (reference)(set_data(m_cnt - 1));
659 GAIA_NODISCARD
decltype(
auto) back()
const noexcept {
660 GAIA_ASSERT(!empty());
661 return (const_reference)set_data(m_cnt - 1);
664 GAIA_NODISCARD
auto begin()
noexcept {
668 GAIA_NODISCARD
auto begin()
const noexcept {
672 GAIA_NODISCARD
auto cbegin()
const noexcept {
676 GAIA_NODISCARD
auto rbegin()
noexcept {
680 GAIA_NODISCARD
auto rbegin()
const noexcept {
684 GAIA_NODISCARD
auto crbegin()
const noexcept {
688 GAIA_NODISCARD
auto end()
noexcept {
692 GAIA_NODISCARD
auto end()
const noexcept {
696 GAIA_NODISCARD
auto cend()
const noexcept {
700 GAIA_NODISCARD
auto rend()
noexcept {
704 GAIA_NODISCARD
auto rend()
const noexcept {
708 GAIA_NODISCARD
auto crend()
const noexcept {
712 GAIA_NODISCARD
bool operator==(
const sparse_page& other)
const {
713 if (m_cnt != other.m_cnt)
715 const size_type n = size();
716 for (size_type i = 0; i < n; ++i)
717 if (!(get_data(i) == other[i]))
722 GAIA_NODISCARD
constexpr bool operator!=(
const sparse_page& other)
const {
723 return !operator==(other);
728 template <
typename T, u
int32_t PageCapacity,
typename Allocator>
729 class sparse_page<T, PageCapacity, Allocator, std::enable_if_t<std::is_empty_v<T>>> {
731 using value_type = T;
735 using const_pointer =
const T*;
737 using difference_type = detail::difference_type;
738 using size_type = detail::size_type;
744 size_type* m_pSparse =
nullptr;
748 if (m_pSparse ==
nullptr) {
751 m_pSparse = mem::AllocHelper::alloc<size_type>(
"SparsePage", PageCapacity);
752 GAIA_FOR(PageCapacity) m_pSparse[i] = detail::InvalidDenseId;
756 void dtr_data_inter([[maybe_unused]] uint32_t idx)
noexcept {
757 GAIA_ASSERT(!empty());
760 void dtr_active_data()
noexcept {
761 GAIA_ASSERT(m_pSparse !=
nullptr);
765 if (m_pSparse ==
nullptr)
769 mem::AllocHelper::free(
"SparsePage", m_pSparse);
780 if (other.m_pSparse ==
nullptr) {
783 for (uint32_t i = 0; i < PageCapacity; ++i) {
785 m_pSparse[i] = other.m_pSparse[i];
786 if (m_pSparse[i] == detail::InvalidDenseId)
795 GAIA_ASSERT(core::addressof(other) !=
this);
797 if (m_pSparse ==
nullptr && other.m_pSparse !=
nullptr)
801 if (other.m_pSparse ==
nullptr) {
805 if (m_pSparse !=
nullptr)
809 for (uint32_t i = 0; i < PageCapacity; ++i)
810 m_pSparse[i] = other.m_pSparse[i];
821 GAIA_ASSERT(m_pSparse ==
nullptr);
823 m_pSparse = other.m_pSparse;
826 other.m_pSparse =
nullptr;
827 other.m_cnt = size_type(0);
831 GAIA_ASSERT(core::addressof(other) !=
this);
835 m_pSparse = other.m_pSparse;
838 other.m_pSparse =
nullptr;
839 other.m_cnt = size_type(0);
848 GAIA_CLANG_WARNING_PUSH()
850 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
852 GAIA_NODISCARD pointer data()
noexcept {
853 return reinterpret_cast<pointer
>(m_pSparse);
856 GAIA_NODISCARD const_pointer data()
const noexcept {
857 return reinterpret_cast<const_pointer
>(m_pSparse);
860 GAIA_CLANG_WARNING_POP()
862 GAIA_NODISCARD
bool allocated()
const noexcept {
863 return m_pSparse !=
nullptr;
871 GAIA_NODISCARD
auto& set_id(size_type pos)
noexcept {
872 return m_pSparse[pos];
875 GAIA_NODISCARD
auto get_id(size_type pos)
const noexcept {
876 return m_pSparse[pos];
879 void del_id(uint32_t idx)
noexcept {
882 GAIA_ASSERT(m_cnt > 0);
890 GAIA_NODISCARD size_type size()
const noexcept {
894 GAIA_NODISCARD
bool empty()
const noexcept {
898 GAIA_NODISCARD
auto front()
const noexcept {
899 GAIA_ASSERT(!empty());
903 GAIA_NODISCARD
auto back()
const noexcept {
904 GAIA_ASSERT(!empty());
905 return get_id(m_cnt - 1);
908 GAIA_NODISCARD
auto begin()
noexcept {
912 GAIA_NODISCARD
auto begin()
const noexcept {
916 GAIA_NODISCARD
auto cbegin()
const noexcept {
920 GAIA_NODISCARD
auto rbegin()
noexcept {
924 GAIA_NODISCARD
auto rbegin()
const noexcept {
928 GAIA_NODISCARD
auto crbegin()
const noexcept {
932 GAIA_NODISCARD
auto end()
noexcept {
936 GAIA_NODISCARD
auto end()
const noexcept {
940 GAIA_NODISCARD
auto cend()
const noexcept {
944 GAIA_NODISCARD
auto rend()
noexcept {
948 GAIA_NODISCARD
auto rend()
const noexcept {
952 GAIA_NODISCARD
auto crend()
const noexcept {
956 GAIA_NODISCARD
bool operator==(
const sparse_page& other)
const {
957 if (m_cnt != other.m_cnt)
959 const size_type n = size();
960 for (size_type i = 0; i < n; ++i)
961 if (!(get_id(i) == other.get_id(i)))
966 GAIA_NODISCARD
constexpr bool operator!=(
const sparse_page& other)
const {
967 return !operator==(other);
979 using value_type = T;
980 using reference = T&;
981 using const_reference =
const T&;
983 using const_pointer =
const T*;
985 using difference_type = detail::difference_type;
986 using size_type = detail::size_type;
993 static_assert((PageCapacity & (PageCapacity - 1)) == 0,
"PageCapacity of sparse_storage must be a power of 2");
994 constexpr static sparse_id page_mask = PageCapacity - 1;
995 constexpr static sparse_id to_page_index = core::count_bits(page_mask);
1002 size_type m_cnt = size_type(0);
1004 void try_grow(uint32_t pid) {
1005 const auto required = m_cnt + 1;
1006 if (required > m_dense.capacity()) {
1007 auto cap = m_dense.capacity() == 0 ? size_type(16) : m_dense.capacity();
1008 while (cap < required)
1010 m_dense.reserve(cap);
1012 m_dense.resize(required);
1015 if (pid >= m_pages.size())
1016 m_pages.resize(pid + 1);
1025 GAIA_ASSERT(core::addressof(other) !=
this);
1027 m_dense = other.m_dense;
1028 m_pages = other.m_pages;
1029 m_cnt = other.m_cnt;
1033 GAIA_ASSERT(core::addressof(other) !=
this);
1035 m_dense = other.m_dense;
1036 m_pages = other.m_pages;
1037 m_cnt = other.m_cnt;
1045 GAIA_ASSERT(m_dense.data() ==
nullptr);
1047 m_dense = GAIA_MOV(other.m_dense);
1048 m_pages = GAIA_MOV(other.m_pages);
1049 m_cnt = other.m_cnt;
1053 other.m_cnt = size_type(0);
1057 GAIA_ASSERT(core::addressof(other) !=
this);
1059 m_dense = GAIA_MOV(other.m_dense);
1060 m_pages = GAIA_MOV(other.m_pages);
1061 m_cnt = other.m_cnt;
1065 other.m_cnt = size_type(0);
1072 GAIA_CLANG_WARNING_PUSH()
1074 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
1076 GAIA_NODISCARD
decltype(
auto)
operator[](sparse_id sid)
noexcept {
1077 GAIA_ASSERT(
has(sid));
1078 const auto pid = uint32_t(sid >> to_page_index);
1079 const auto did = uint32_t(sid & page_mask);
1081 auto& page = m_pages[pid];
1082 return view_policy::set({(
typename view_policy::TargetCastType)page.data(), PageCapacity}, did);
1085 GAIA_NODISCARD
decltype(
auto)
operator[](sparse_id sid)
const noexcept {
1086 GAIA_ASSERT(
has(sid));
1087 const auto pid = uint32_t(sid >> to_page_index);
1088 const auto did = uint32_t(sid & page_mask);
1090 auto& page = m_pages[pid];
1091 return view_policy::get({(
typename view_policy::TargetCastType)page.data(), PageCapacity}, did);
1094 GAIA_CLANG_WARNING_POP()
1097 GAIA_NODISCARD
bool has(sparse_id sid)
const {
1098 if (sid == detail::InvalidSparseId)
1101 const auto pid = uint32_t(sid >> to_page_index);
1102 if (pid >= m_pages.size())
1105 const auto did = uint32_t(sid & page_mask);
1106 const auto& page = m_pages[pid];
1109 if (!page.allocated())
1112 const auto id = page.get_id(did);
1113 return id != detail::InvalidDenseId;
1118 GAIA_NODISCARD
bool has(
const T& arg)
const {
1120 GAIA_ASSERT(sid != detail::InvalidSparseId);
1127 template <
typename TType>
1128 decltype(
auto)
add(TType&& arg) {
1131 const auto pid = uint32_t(sid >> to_page_index);
1132 const auto did = uint32_t(sid & page_mask);
1133 auto& page = m_pages[pid];
1134 return page.set_data(did);
1137 const auto pid = uint32_t(sid >> to_page_index);
1138 const auto did = uint32_t(sid & page_mask);
1141 m_dense[m_cnt] = sid;
1143 auto& page = m_pages[pid];
1144 page.set_id(did) = m_cnt++;
1145 return page.add_data(did, GAIA_FWD(arg));
1151 decltype(
auto)
set(sparse_id sid) {
1152 GAIA_ASSERT(
has(sid));
1154 const auto pid = uint32_t(sid >> to_page_index);
1155 const auto did = uint32_t(sid & page_mask);
1157 auto& page = m_pages[pid];
1158 return page.set_data(did);
1163 void del(sparse_id sid)
noexcept {
1164 GAIA_ASSERT(!
empty());
1165 GAIA_ASSERT(sid != detail::InvalidSparseId);
1170 const auto pid = uint32_t(sid >> to_page_index);
1171 const auto did = uint32_t(sid & page_mask);
1173 const auto sidPrev = std::as_const(m_dense)[m_cnt - 1];
1174 const auto pidPrev = uint32_t(sidPrev >> to_page_index);
1175 const auto didPrev = uint32_t(sidPrev & page_mask);
1177 auto& page = m_pages[pid];
1178 const auto id = page.get_id(did);
1180 auto& pagePrev = m_pages[pidPrev];
1181 pagePrev.set_id(didPrev) = id;
1182 page.set_id(did) = detail::InvalidDenseId;
1184 m_dense[id] = sidPrev;
1185 m_dense.resize(m_cnt - 1);
1187 GAIA_ASSERT(m_cnt > 0);
1193 void del(
const T& arg)
noexcept {
1206 GAIA_NODISCARD size_type
size() const noexcept {
1211 GAIA_NODISCARD
bool empty() const noexcept {
1215 GAIA_NODISCARD
decltype(
auto) front() noexcept {
1216 GAIA_ASSERT(!
empty());
1217 return (reference)*begin();
1220 GAIA_NODISCARD
decltype(
auto) front() const noexcept {
1221 GAIA_ASSERT(!
empty());
1222 return (const_reference)*begin();
1225 GAIA_NODISCARD
decltype(
auto) back() noexcept {
1226 GAIA_ASSERT(!
empty());
1228 const auto sid = m_dense[m_cnt - 1];
1229 const auto pid = uint32_t(sid >> to_page_index);
1230 const auto did = uint32_t(sid & page_mask);
1232 return (reference)m_pages[pid].set_data(did);
1235 GAIA_NODISCARD
decltype(
auto) back() const noexcept {
1236 GAIA_ASSERT(!
empty());
1238 const auto sid = m_dense[m_cnt - 1];
1239 const auto pid = uint32_t(sid >> to_page_index);
1240 const auto did = uint32_t(sid & page_mask);
1242 return (const_reference)m_pages[pid].get_data(did);
1245 GAIA_NODISCARD
auto begin() noexcept {
1246 GAIA_ASSERT(!
empty());
1248 return iterator(m_dense.data(), m_pages.data());
1251 GAIA_NODISCARD
auto begin() const noexcept {
1252 GAIA_ASSERT(!
empty());
1254 return const_iterator(m_dense.data(), m_pages.data());
1257 GAIA_NODISCARD
auto cbegin() const noexcept {
1258 GAIA_ASSERT(!
empty());
1260 return const_iterator(m_dense.data(), m_pages.data());
1263 GAIA_NODISCARD
auto end() noexcept {
1264 GAIA_ASSERT(!
empty());
1266 return iterator(m_dense.data() +
size(), m_pages.data());
1269 GAIA_NODISCARD
auto end() const noexcept {
1270 GAIA_ASSERT(!
empty());
1272 return const_iterator(m_dense.data() +
size(), m_pages.data());
1275 GAIA_NODISCARD
auto cend() const noexcept {
1276 GAIA_ASSERT(!
empty());
1278 return const_iterator(m_dense.data() +
size(), m_pages.data());
1281 GAIA_NODISCARD
bool operator==(
const sparse_storage& other)
const {
1283 if (m_cnt != other.m_cnt)
1289 if (m_dense != other.m_dense)
1295 const size_type n =
size();
1296 for (size_type i = 0, cnt = 0; i < n && cnt < m_cnt; ++i, ++cnt) {
1297 const auto sid = m_dense[i];
1298 const auto pid = uint32_t(sid >> to_page_index);
1299 const auto did = uint32_t(sid & page_mask);
1301 const auto& item0 = m_pages[pid].get_data(did);
1302 const auto& item1 = m_pages[pid].get_data(did);
1304 if (!(item0 == item1))
1310 GAIA_NODISCARD
constexpr bool operator!=(
const sparse_storage& other)
const {
1311 return !operator==(other);
1319 template <
typename T, u
int32_t PageCapacity,
typename Allocator>
1320 class sparse_storage<T, PageCapacity, Allocator, std::enable_if_t<std::is_empty_v<T>>> {
1322 using value_type = T;
1323 using reference = T&;
1324 using const_reference =
const T&;
1326 using const_pointer =
const T*;
1328 using difference_type = detail::difference_type;
1329 using size_type = detail::size_type;
1336 static_assert((PageCapacity & (PageCapacity - 1)) == 0,
"PageCapacity of sparse_storage must be a power of 2");
1337 constexpr static sparse_id page_mask = PageCapacity - 1;
1338 constexpr static sparse_id to_page_index = core::count_bits(page_mask);
1345 size_type m_cnt = size_type(0);
1347 void try_grow(uint32_t pid) {
1348 const auto required = m_cnt + 1;
1349 if (required > m_dense.capacity()) {
1350 auto cap = m_dense.capacity() == 0 ? size_type(16) : m_dense.capacity();
1351 while (cap < required)
1353 m_dense.reserve(cap);
1355 m_dense.resize(required);
1358 if (pid >= m_pages.size())
1359 m_pages.resize(pid + 1);
1368 GAIA_ASSERT(core::addressof(other) !=
this);
1370 m_dense = other.m_dense;
1371 m_pages = other.m_pages;
1372 m_cnt = other.m_cnt;
1376 GAIA_ASSERT(core::addressof(other) !=
this);
1378 m_dense = other.m_dense;
1379 m_pages = other.m_pages;
1380 m_cnt = other.m_cnt;
1388 GAIA_ASSERT(m_dense.data() ==
nullptr);
1390 m_dense = GAIA_MOV(other.m_dense);
1391 m_pages = GAIA_MOV(other.m_pages);
1392 m_cnt = other.m_cnt;
1396 other.m_cnt = size_type(0);
1400 GAIA_ASSERT(core::addressof(other) !=
this);
1402 m_dense = GAIA_MOV(other.m_dense);
1403 m_pages = GAIA_MOV(other.m_pages);
1404 m_cnt = other.m_cnt;
1408 other.m_cnt = size_type(0);
1416 GAIA_NODISCARD
bool has(sparse_id sid)
const {
1417 GAIA_ASSERT(sid != detail::InvalidSparseId);
1419 const auto pid = uint32_t(sid >> to_page_index);
1420 const auto did = uint32_t(sid & page_mask);
1421 return has_internal(pid, did);
1425 GAIA_NODISCARD
bool has_internal(uint32_t pid, uint32_t did)
const {
1426 if (pid >= m_pages.size())
1429 const auto& page = m_pages[pid];
1430 if (!page.allocated())
1433 const auto id = page.get_id(did);
1434 return id != detail::InvalidDenseId;
1441 GAIA_ASSERT(sid != detail::InvalidSparseId);
1443 const auto pid = uint32_t(sid >> to_page_index);
1444 const auto did = uint32_t(sid & page_mask);
1446 if (has_internal(pid, did))
1450 m_dense[m_cnt] = sid;
1452 auto& page = m_pages[pid];
1453 page.set_id(did) = m_cnt++;
1458 void del(sparse_id sid)
noexcept {
1459 GAIA_ASSERT(!
empty());
1460 GAIA_ASSERT(sid != detail::InvalidSparseId);
1462 const auto pid = uint32_t(sid >> to_page_index);
1463 const auto did = uint32_t(sid & page_mask);
1465 if (!has_internal(pid, did))
1468 const auto sidPrev = std::as_const(m_dense)[m_cnt - 1];
1469 const auto pidPrev = uint32_t(sidPrev >> to_page_index);
1470 const auto didPrev = uint32_t(sidPrev & page_mask);
1472 auto& page = m_pages[pid];
1473 const auto id = page.get_id(did);
1475 auto& pagePrev = m_pages[pidPrev];
1476 pagePrev.set_id(didPrev) = id;
1477 page.set_id(did) = detail::InvalidDenseId;
1478 m_dense[id] = sidPrev;
1479 m_dense.resize(m_cnt - 1);
1481 GAIA_ASSERT(m_cnt > 0);
1493 GAIA_NODISCARD size_type
size() const noexcept {
1498 GAIA_NODISCARD
bool empty() const noexcept {
1502 GAIA_NODISCARD
decltype(
auto) front() noexcept {
1503 GAIA_ASSERT(!
empty());
1504 return (reference)*begin();
1507 GAIA_NODISCARD
decltype(
auto) front() const noexcept {
1508 GAIA_ASSERT(!
empty());
1509 return (const_reference)*begin();
1512 GAIA_NODISCARD
decltype(
auto) back() noexcept {
1513 GAIA_ASSERT(!
empty());
1515 const auto sid = m_dense[m_cnt - 1];
1516 const auto pid = uint32_t(sid >> to_page_index);
1517 const auto did = uint32_t(sid & page_mask);
1519 return (reference)m_pages[pid].set_id(did);
1522 GAIA_NODISCARD
decltype(
auto) back() const noexcept {
1523 GAIA_ASSERT(!
empty());
1525 const auto sid = m_dense[m_cnt - 1];
1526 const auto pid = uint32_t(sid >> to_page_index);
1527 const auto did = uint32_t(sid & page_mask);
1529 return (const_reference)m_pages[pid].get_id(did);
1532 GAIA_NODISCARD
auto begin() noexcept {
1533 GAIA_ASSERT(!
empty());
1534 return iterator(m_dense.data());
1537 GAIA_NODISCARD
auto begin() const noexcept {
1538 GAIA_ASSERT(!
empty());
1539 return const_iterator(m_dense.data());
1542 GAIA_NODISCARD
auto cbegin() const noexcept {
1543 GAIA_ASSERT(!
empty());
1544 return const_iterator(m_dense.data());
1547 GAIA_NODISCARD
auto end() noexcept {
1548 GAIA_ASSERT(!
empty());
1549 return iterator(m_dense.data() +
size());
1552 GAIA_NODISCARD
auto end() const noexcept {
1553 GAIA_ASSERT(!
empty());
1554 return const_iterator(m_dense.data() +
size());
1557 GAIA_NODISCARD
auto cend() const noexcept {
1558 GAIA_ASSERT(!
empty());
1559 return const_iterator(m_dense.data() +
size());
1562 GAIA_NODISCARD
bool operator==(
const sparse_storage& other)
const {
1564 if (m_cnt != other.m_cnt)
1570 if (m_dense != other.m_dense)
1576 GAIA_NODISCARD
constexpr bool operator!=(
const sparse_storage& other)
const {
1577 return !operator==(other);
Array with variable size of elements of type.
Definition darray_impl.h:25
Sparse page. Specialized for zero-size.
Definition sparse_storage.h:729
Definition sparse_storage.h:422
void del(sparse_id sid) noexcept
Removes a sparse id from storage.
Definition sparse_storage.h:1458
GAIA_NODISCARD bool has(sparse_id sid) const
Checks if an item with a given sparse id.
Definition sparse_storage.h:1416
GAIA_NODISCARD bool empty() const noexcept
Checks if the storage is empty (no items inserted)
Definition sparse_storage.h:1498
void clear()
Clears the storage.
Definition sparse_storage.h:1486
void add(sparse_id sid)
Registers a new sparse id.
Definition sparse_storage.h:1440
GAIA_NODISCARD size_type size() const noexcept
Returns the number of items inserted into the storage.
Definition sparse_storage.h:1493
Array with variable size of elements of type.
Definition sparse_storage.h:977
GAIA_NODISCARD size_type size() const noexcept
Returns the number of items inserted into the storage.
Definition sparse_storage.h:1206
decltype(auto) set(sparse_id sid)
Update the record at the index sid.
Definition sparse_storage.h:1151
GAIA_NODISCARD bool empty() const noexcept
Checks if the storage is empty (no items inserted)
Definition sparse_storage.h:1211
GAIA_NODISCARD bool has(sparse_id sid) const
Checks if an item with a given sparse id.
Definition sparse_storage.h:1097
GAIA_NODISCARD bool has(const T &arg) const
Checks if an item arg exists within the storage.
Definition sparse_storage.h:1118
void del(sparse_id sid) noexcept
Removes the item at the index sid from the storage.
Definition sparse_storage.h:1163
void clear()
Clears the storage.
Definition sparse_storage.h:1199
decltype(auto) add(TType &&arg)
Inserts the item arg into the storage.
Definition sparse_storage.h:1128
void del(const T &arg) noexcept
Removes the item arg from the storage.
Definition sparse_storage.h:1193
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition sparse_storage.h:330
Definition sparse_storage.h:140
Definition sparse_storage.h:238
Definition sparse_storage.h:42
Definition sparse_storage.h:31
Definition mem_alloc.h:104
View policy for accessing and storing data in the AoS way. Good for random access and when accessing ...
Definition data_layout_policy.h:112