176 static_assert(!std::is_empty_v<T>,
"It only makes sense to use page storage for data types with non-zero size");
179 using value_type = T;
180 using reference = T&;
181 using const_reference =
const T&;
183 using const_pointer =
const T*;
188 template <
bool IsFwd>
193 template <
bool IsFwd>
199 static constexpr uint32_t PageCapacity = PageData::PageCapacity;
206 if GAIA_LIKELY (m_pData !=
nullptr)
210 m_pData = mem::AllocHelper::alloc<PageData, Allocator>(1);
213 core::call_ctor_raw_n(data(), PageCapacity);
216 void dtr_data_inter(
uint32_t idx)
noexcept {
217 GAIA_ASSERT(!empty());
219 if constexpr (!mem::is_soa_layout_v<T>) {
220 auto* ptr = &data()[idx];
221 core::call_dtor(ptr);
224 m_pData->header.mask.set(idx,
false);
225 --m_pData->header.cnt;
228 void dtr_active_data()
noexcept {
229 if constexpr (!mem::is_soa_layout_v<T>) {
230 for (
auto i: m_pData->header.mask) {
231 auto* ptr = &data()[
i];
232 core::call_dtor(ptr);
238 if (m_pData ==
nullptr)
245 m_pData->~PageData();
246 mem::AllocHelper::free<Allocator>(m_pData);
255 if (other.m_pData ==
nullptr) {
260 m_pData->header.mask = other.m_pData->header.mask;
261 m_pData->header.cnt = other.m_pData->header.cnt;
264 for (
auto i: other.m_pData->header.mask)
265 add_data(
i, other.get_data(
i));
270 GAIA_ASSERT(core::addressof(other) !=
this);
273 if (other.m_pData ==
nullptr) {
279 if (m_pData !=
nullptr)
282 m_pData->header.mask = other.m_pData->header.mask;
283 m_pData->header.cnt = other.m_pData->header.cnt;
286 for (
auto i: other.m_pData->header.mask)
287 add_data(
i, other.get_data(
i));
294 m_pData = other.m_pData;
295 other.m_pData =
nullptr;
299 GAIA_ASSERT(core::addressof(other) !=
this);
303 m_pData = other.m_pData;
304 other.m_pData =
nullptr;
313 GAIA_CLANG_WARNING_PUSH()
315 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
317 GAIA_NODISCARD pointer data()
noexcept {
318 return GAIA_ACC((pointer)&m_pData->data[0]);
321 GAIA_NODISCARD const_pointer data()
const noexcept {
322 return GAIA_ACC((const_pointer)&m_pData->data[0]);
325 GAIA_NODISCARD
decltype(
auto) set_data(
size_type pos)
noexcept {
326 GAIA_ASSERT(m_pData->header.mask.test(pos));
327 return view_policy::set(
328 {GAIA_ACC((
typename view_policy::TargetCastType) & m_pData->data[0]), PageCapacity}, pos);
331 GAIA_NODISCARD
decltype(
auto)
operator[](
size_type pos)
noexcept {
332 GAIA_ASSERT(m_pData->header.mask.test(pos));
333 return view_policy::set(
334 {GAIA_ACC((
typename view_policy::TargetCastType) & m_pData->data[0]), PageCapacity}, pos);
337 GAIA_NODISCARD
decltype(
auto) get_data(
size_type pos)
const noexcept {
338 GAIA_ASSERT(m_pData->header.mask.test(pos));
339 return view_policy::get(
340 {GAIA_ACC((
typename view_policy::TargetCastType) & m_pData->data[0]), PageCapacity}, pos);
343 GAIA_NODISCARD
decltype(
auto)
operator[](
size_type pos)
const noexcept {
344 GAIA_ASSERT(m_pData->header.mask.test(pos));
345 return view_policy::get(
346 {GAIA_ACC((
typename view_policy::TargetCastType) & m_pData->data[0]), PageCapacity}, pos);
349 GAIA_CLANG_WARNING_POP()
353 ++m_pData->header.cnt;
356 decltype(
auto) add_data(
uint32_t idx,
const T& arg) {
357 m_pData->header.mask.set(idx);
359 if constexpr (mem::is_soa_layout_v<T>) {
362 auto* ptr = &set_data(idx);
363 core::call_ctor(ptr, arg);
364 return (reference)(*ptr);
368 decltype(
auto) add_data(
uint32_t idx, T&& arg) {
369 m_pData->header.mask.set(idx);
371 if constexpr (mem::is_soa_layout_v<T>) {
372 set_data(idx) = GAIA_MOV(arg);
374 auto* ptr = &set_data(idx);
375 core::call_ctor(ptr, GAIA_MOV(arg));
376 return (reference)(*ptr);
380 template <
typename...
Args>
382 m_pData->header.used.set(idx);
384 if constexpr (mem::is_soa_layout_v<T>) {
385 set_data(idx) = T(GAIA_FWD(
args)...);
387 auto* ptr = &set_data(idx);
388 core::call_ctor(ptr, GAIA_FWD(
args)...);
389 return (reference)(*ptr);
393 void del_data(
uint32_t idx)
noexcept {
397 if (m_pData->header.cnt == 0)
401 GAIA_NODISCARD
bool has_data(
uint32_t idx)
const noexcept {
402 return m_pData ? m_pData->header.mask.test(idx) :
false;
405 GAIA_NODISCARD
size_type size()
const noexcept {
406 return m_pData ? m_pData->header.cnt : 0;
409 GAIA_NODISCARD
bool empty()
const noexcept {
413 GAIA_NODISCARD
decltype(
auto) front()
noexcept {
414 GAIA_ASSERT(!empty());
415 if constexpr (mem::is_soa_layout_v<T>)
418 return (reference)*begin();
421 GAIA_NODISCARD
decltype(
auto) front()
const noexcept {
422 GAIA_ASSERT(!empty());
423 if constexpr (mem::is_soa_layout_v<T>)
426 return (const_reference)*begin();
429 GAIA_NODISCARD
decltype(
auto) back()
noexcept {
430 GAIA_ASSERT(!empty());
431 const auto idx = *m_pData->header.mask.rbegin();
432 if constexpr (mem::is_soa_layout_v<T>)
433 return set_data(idx);
435 return (reference)(set_data(idx));
438 GAIA_NODISCARD
decltype(
auto) back()
const noexcept {
439 GAIA_ASSERT(!empty());
440 const auto idx = *m_pData->header.mask.rbegin();
441 if constexpr (mem::is_soa_layout_v<T>)
442 return set_data(idx);
444 return (const_reference)set_data(idx);
447 static constexpr typename PageData::bit_set s_dummyBitSet{};
449 GAIA_NODISCARD
auto begin()
const noexcept {
450 if constexpr (mem::is_soa_layout_v<T>)
451 return iterator_soa((
mem_page*)
this, m_pData ? m_pData->header.mask.begin() : s_dummyBitSet.begin());
453 return iterator((
mem_page*)
this, m_pData ? m_pData->header.mask.begin() : s_dummyBitSet.begin());
456 GAIA_NODISCARD
auto end()
const noexcept {
457 if constexpr (mem::is_soa_layout_v<T>)
458 return iterator_soa((
mem_page*)
this, m_pData ? m_pData->header.mask.end() : s_dummyBitSet.end());
460 return iterator((
mem_page*)
this, m_pData ? m_pData->header.mask.end() : s_dummyBitSet.end());
463 GAIA_NODISCARD
auto rbegin()
const noexcept {
464 if constexpr (mem::is_soa_layout_v<T>)
466 (
mem_page*)
this, m_pData ? m_pData->header.mask.rbegin() : s_dummyBitSet.rbegin());
471 GAIA_NODISCARD
auto rend()
const noexcept {
472 if constexpr (mem::is_soa_layout_v<T>)
478 GAIA_NODISCARD
bool operator==(
const mem_page& other)
const noexcept {
480 GAIA_ASSERT(m_pData !=
nullptr);
481 GAIA_ASSERT(other.m_pData !=
nullptr);
483 if (m_pData->header.cnt != other.m_pData->header.cnt)
485 if (m_pData->header.mask != other.m_pData->header.mask)
487 for (
auto i: m_pData->header.mask)
488 if (!(get_data(
i) == other[
i]))
493 GAIA_NODISCARD
bool operator!=(
const mem_page& other)
const noexcept {
494 return !operator==(other);
840 using value_type = T;
841 using reference = T&;
842 using const_reference =
const T&;
844 using const_pointer =
const T*;
854 static constexpr uint32_t PageCapacity = page_type::PageCapacity;
867 constexpr static uint32_t PageMask = PageCapacity - 1;
868 constexpr static uint32_t ToPageIndex = core::count_bits(PageMask);
877 if (
pid >= m_pages.size())
878 m_pages.resize(
pid + 1);
888 m_pages = other.m_pages;
889 m_itemCnt = other.m_itemCnt;
893 GAIA_ASSERT(core::addressof(other) !=
this);
895 m_pages = other.m_pages;
896 m_itemCnt = other.m_itemCnt;
901 m_pages = GAIA_MOV(other.m_pages);
902 m_itemCnt = other.m_itemCnt;
908 GAIA_ASSERT(core::addressof(other) !=
this);
910 m_pages = GAIA_MOV(other.m_pages);
911 m_itemCnt = other.m_itemCnt;
920 GAIA_CLANG_WARNING_PUSH()
922 GAIA_CLANG_WARNING_DISABLE(
"-Wcast-align")
924 GAIA_NODISCARD
decltype(
auto)
operator[](
page_storage_id id)
noexcept {
925 GAIA_ASSERT(
has(
id));
929 return view_policy::set({(
typename view_policy::TargetCastType)
page.data(), PageCapacity},
did);
932 GAIA_NODISCARD
decltype(
auto)
operator[](
page_storage_id id)
const noexcept {
933 GAIA_ASSERT(
has(
id));
937 return view_policy::get({(
typename view_policy::TargetCastType)
page.data(), PageCapacity},
did);
940 GAIA_CLANG_WARNING_POP()
946 if (
pid >= m_pages.size())
950 const auto val = page_data_type::bit_set::BitCount;
951 return did < val && m_pages[
pid].has_data(
did);
956 GAIA_NODISCARD
bool has(
const T& arg)
const noexcept {
958 GAIA_ASSERT(
id != detail::InvalidPageStorageId);
965 template <
typename TType>
966 decltype(
auto)
add(TType&& arg) {
969 if constexpr (mem::is_soa_layout_v<TType>)
985 if constexpr (mem::is_soa_layout_v<TType>)
986 page.add_data(
did, GAIA_FWD(arg));
988 return page.add_data(
did, GAIA_FWD(arg));
995 GAIA_ASSERT(
has(
id));
1007 GAIA_ASSERT(!
empty());
1008 GAIA_ASSERT(
id != detail::InvalidPageStorageId);
1023 void del(
const T& arg)
noexcept {
1041 return m_itemCnt == 0;
1044 GAIA_NODISCARD
decltype(
auto) front()
noexcept {
1045 GAIA_ASSERT(!
empty());
1046 return (reference)*begin();
1049 GAIA_NODISCARD
decltype(
auto) front() const noexcept {
1050 GAIA_ASSERT(!
empty());
1051 return (const_reference)*begin();
1054 GAIA_NODISCARD
decltype(
auto) back() noexcept {
1055 GAIA_ASSERT(!
empty());
1056 return (reference)*rbegin();
1059 GAIA_NODISCARD
decltype(
auto) back() const noexcept {
1060 GAIA_ASSERT(!
empty());
1061 return (const_reference)*rbegin();
1064 GAIA_NODISCARD
auto begin() noexcept {
1065 GAIA_ASSERT(!
empty());
1066 return iterator(m_pages.data(), m_pages.data() + m_pages.size());
1069 GAIA_NODISCARD
auto begin() const noexcept {
1070 GAIA_ASSERT(!
empty());
1071 return const_iterator(m_pages.data(), m_pages.data() + m_pages.size());
1074 GAIA_NODISCARD
auto cbegin() const noexcept {
1075 GAIA_ASSERT(!
empty());
1076 return const_iterator(m_pages.data(), m_pages.data() + m_pages.size());
1079 GAIA_NODISCARD
auto end() noexcept {
1080 GAIA_ASSERT(!
empty());
1081 return iterator(m_pages.data() + m_pages.size());
1084 GAIA_NODISCARD
auto end() const noexcept {
1085 GAIA_ASSERT(!
empty());
1086 return const_iterator(m_pages.data() + m_pages.size());
1089 GAIA_NODISCARD
auto cend() const noexcept {
1090 GAIA_ASSERT(!
empty());
1091 return const_iterator(m_pages.data() + m_pages.size());
1094 GAIA_NODISCARD
auto rbegin() noexcept {
1095 GAIA_ASSERT(!
empty());
1096 return iterator_reverse(m_pages.data() + m_pages.size() - 1, m_pages.data() - 1);
1099 GAIA_NODISCARD
auto rbegin() const noexcept {
1100 GAIA_ASSERT(!
empty());
1101 return const_iterator_reverse(m_pages.data() + m_pages.size() - 1, m_pages.data() - 1);
1104 GAIA_NODISCARD
auto crbegin() const noexcept {
1105 GAIA_ASSERT(!
empty());
1106 return const_iterator_reverse(m_pages.data() + m_pages.size() - 1, m_pages.data() - 1);
1109 GAIA_NODISCARD
auto rend() noexcept {
1110 GAIA_ASSERT(!
empty());
1111 return iterator_reverse(m_pages.data() - 1);
1114 GAIA_NODISCARD
auto rend() const noexcept {
1115 GAIA_ASSERT(!
empty());
1116 return const_iterator_reverse(m_pages.data() - 1);
1119 GAIA_NODISCARD
auto crend() const noexcept {
1120 GAIA_ASSERT(!
empty());
1121 return const_iterator_reverse(m_pages.data() - 1);
1124 GAIA_NODISCARD
bool operator==(
const page_storage& other)
const noexcept {
1125 return m_pages == other.m_pages;
1128 GAIA_NODISCARD
bool operator!=(
const page_storage& other)
const noexcept {
1129 return !operator==(other);
Heap-allocated paged storage for elements of type T.
Definition paged_storage.h:838
decltype(auto) add(TType &&arg)
Inserts the item arg into the storage.
Definition paged_storage.h:966
void clear()
Clears the storage.
Definition paged_storage.h:1029
void del(const T &arg) noexcept
Removes the item arg from the storage.
Definition paged_storage.h:1023
decltype(auto) set(page_storage_id id)
Update the record at the index id.
Definition paged_storage.h:994
GAIA_NODISCARD size_type size() const noexcept
Returns the number of items inserted into the storage.
Definition paged_storage.h:1035
GAIA_NODISCARD bool empty() const noexcept
Checks if the storage is empty (no items inserted)
Definition paged_storage.h:1040
GAIA_NODISCARD bool has(const T &arg) const noexcept
Checks if an item arg exists within the storage.
Definition paged_storage.h:956
void del(page_storage_id id) noexcept
Removes the item at the index id from the storage.
Definition paged_storage.h:1006
GAIA_NODISCARD bool has(page_storage_id id) const noexcept
Checks if an item with a given page id exists.
Definition paged_storage.h:944
PageHeader header
Page header.
Definition paged_storage.h:169
mem::raw_data_holder< T, AllocatedBytes > data
Page data.
Definition paged_storage.h:171
Definition paged_storage.h:500