Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
ilist.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7#include "gaia/cnt/darray.h"
8#include "gaia/core/utility.h"
9
10namespace gaia {
11 namespace cnt {
12 struct ilist_item_base {};
13
14 struct ilist_item: public ilist_item_base {
15 struct ItemData {
17 uint32_t gen;
18 };
19
22 uint32_t idx;
25
26 ilist_item() = default;
27 ilist_item(uint32_t index, uint32_t generation): idx(index) {
28 data.gen = generation;
29 }
30
31 ilist_item(const ilist_item& other) {
32 idx = other.idx;
33 data.gen = other.data.gen;
34 }
35 ilist_item& operator=(const ilist_item& other) {
36 GAIA_ASSERT(core::addressof(other) != this);
37 idx = other.idx;
38 data.gen = other.data.gen;
39 return *this;
40 }
41
42 ilist_item(ilist_item&& other) {
43 idx = other.idx;
44 data.gen = other.data.gen;
45
46 other.idx = (uint32_t)-1;
47 other.data.gen = (uint32_t)-1;
48 }
49 ilist_item& operator=(ilist_item&& other) {
50 GAIA_ASSERT(core::addressof(other) != this);
51 idx = other.idx;
52 data.gen = other.data.gen;
53
54 other.idx = (uint32_t)-1;
55 other.data.gen = (uint32_t)-1;
56 return *this;
57 }
58 };
59
60 template <typename TListItem>
61 struct darray_ilist_storage: public cnt::darray<TListItem> {
62 void add_item(TListItem&& container) {
63 this->push_back(GAIA_MOV(container));
64 }
65
66 void del_item([[maybe_unused]] TListItem& container) {}
67 };
68
75 template <typename TListItem, typename TItemHandle, typename TInternalStorage = darray_ilist_storage<TListItem>>
76 struct ilist {
77 using internal_storage = TInternalStorage;
78
79 using value_type = TListItem;
80 using reference = TListItem&;
81 using const_reference = const TListItem&;
82 using pointer = TListItem*;
83 using const_pointer = const TListItem*;
84 using difference_type = typename internal_storage::difference_type;
85 using size_type = typename internal_storage::size_type;
86
87 // TODO: replace this iterator with a real list iterator
88 using iterator = typename internal_storage::iterator;
89 using const_iterator = typename internal_storage::const_iterator;
90 using iterator_category = typename internal_storage::iterator_category;
91
92 static_assert(std::is_base_of<ilist_item_base, TListItem>::value);
94 internal_storage m_items;
96 size_type m_nextFreeIdx = (size_type)-1;
98 size_type m_freeItems = 0;
99
100 GAIA_NODISCARD pointer data() noexcept {
101 return reinterpret_cast<pointer>(m_items.data());
102 }
103
104 GAIA_NODISCARD const_pointer data() const noexcept {
105 return reinterpret_cast<const_pointer>(m_items.data());
106 }
107
108 GAIA_NODISCARD reference operator[](size_type index) {
109 return m_items[index];
110 }
111 GAIA_NODISCARD const_reference operator[](size_type index) const {
112 return m_items[index];
113 }
114
115 void clear() {
116 m_items.clear();
117 m_nextFreeIdx = (size_type)-1;
118 m_freeItems = 0;
119 }
120
121 GAIA_NODISCARD size_type get_next_free_item() const noexcept {
122 return m_nextFreeIdx;
123 }
124
125 GAIA_NODISCARD size_type get_free_items() const noexcept {
126 return m_freeItems;
127 }
128
129 GAIA_NODISCARD size_type item_count() const noexcept {
130 return size() - m_freeItems;
131 }
132
133 GAIA_NODISCARD size_type size() const noexcept {
134 return (size_type)m_items.size();
135 }
136
137 GAIA_NODISCARD bool empty() const noexcept {
138 return size() == 0;
139 }
140
141 GAIA_NODISCARD size_type capacity() const noexcept {
142 return (size_type)m_items.capacity();
143 }
144
145 GAIA_NODISCARD iterator begin() noexcept {
146 return m_items.begin();
147 }
148
149 GAIA_NODISCARD const_iterator begin() const noexcept {
150 return m_items.begin();
151 }
152
153 GAIA_NODISCARD const_iterator cbegin() const noexcept {
154 return m_items.begin();
155 }
156
157 GAIA_NODISCARD iterator end() noexcept {
158 return m_items.end();
159 }
160
161 GAIA_NODISCARD const_iterator end() const noexcept {
162 return m_items.end();
163 }
164
165 GAIA_NODISCARD const_iterator cend() const noexcept {
166 return m_items.end();
167 }
168
169 void reserve(size_type cap) {
170 m_items.reserve(cap);
171 }
172
175 GAIA_NODISCARD TItemHandle alloc(void* ctx) {
176 if GAIA_UNLIKELY (m_freeItems == 0U) {
177 // We don't want to go out of range for new item
178 const auto itemCnt = (size_type)m_items.size();
179 GAIA_ASSERT(itemCnt < TItemHandle::IdMask && "Trying to allocate too many items!");
180
181 GAIA_GCC_WARNING_PUSH()
182 GAIA_CLANG_WARNING_PUSH()
183 GAIA_GCC_WARNING_DISABLE("-Wstringop-overflow");
184 GAIA_GCC_WARNING_DISABLE("-Wmissing-field-initializers");
185 GAIA_CLANG_WARNING_DISABLE("-Wmissing-field-initializers");
186 m_items.add_item(TListItem::create(itemCnt, 0U, ctx));
187 return TListItem::handle(m_items.back());
188 GAIA_GCC_WARNING_POP()
189 GAIA_CLANG_WARNING_POP()
190 }
191
192 // Make sure the list is not broken
193 GAIA_ASSERT(m_nextFreeIdx < (size_type)m_items.size() && "Item recycle list broken!");
194
195 --m_freeItems;
196 const auto index = m_nextFreeIdx;
197 auto& j = m_items[m_nextFreeIdx];
198 m_nextFreeIdx = j.idx;
199 j = TListItem::create(index, j.data.gen, ctx);
200 return TListItem::handle(j);
201 }
202
205 GAIA_NODISCARD TItemHandle alloc() {
206 if GAIA_UNLIKELY (m_freeItems == 0U) {
207 // We don't want to go out of range for new item
208 const auto itemCnt = (size_type)m_items.size();
209 GAIA_ASSERT(itemCnt < TItemHandle::IdMask && "Trying to allocate too many items!");
210
211 GAIA_GCC_WARNING_PUSH()
212 GAIA_CLANG_WARNING_PUSH()
213 GAIA_GCC_WARNING_DISABLE("-Wstringop-overflow");
214 GAIA_GCC_WARNING_DISABLE("-Wmissing-field-initializers");
215 GAIA_CLANG_WARNING_DISABLE("-Wmissing-field-initializers");
216 m_items.add_item(TListItem(itemCnt, 0U));
217 return {itemCnt, 0U};
218 GAIA_GCC_WARNING_POP()
219 GAIA_CLANG_WARNING_POP()
220 }
221
222 // Make sure the list is not broken
223 GAIA_ASSERT(m_nextFreeIdx < (size_type)m_items.size() && "Item recycle list broken!");
224
225 --m_freeItems;
226 const auto index = m_nextFreeIdx;
227 auto& j = m_items[m_nextFreeIdx];
228 m_nextFreeIdx = j.idx;
229 return {index, m_items[index].data.gen};
230 }
231
235 TListItem& free(TItemHandle handle) {
236 auto& item = m_items[handle.id()];
237 m_items.del_item(item);
238
239 // Update our implicit list
240 if GAIA_UNLIKELY (m_freeItems == 0)
241 item.idx = TItemHandle::IdMask;
242 else
243 item.idx = m_nextFreeIdx;
244 ++item.data.gen;
245
246 m_nextFreeIdx = handle.id();
247 ++m_freeItems;
248
249 return item;
250 }
251
253 void validate() const {
254 bool hasThingsToRemove = m_freeItems > 0;
255 if (!hasThingsToRemove)
256 return;
257
258 // If there's something to remove there has to be at least one entity left
259 GAIA_ASSERT(!m_items.empty());
260
261 auto freeItems = m_freeItems;
262 auto nextFreeItem = m_nextFreeIdx;
263 while (freeItems > 0) {
264 GAIA_ASSERT(nextFreeItem < m_items.size() && "Item recycle list broken!");
265
266 nextFreeItem = m_items[nextFreeItem].idx;
267 --freeItems;
268 }
269
270 // At this point the index of the last item in list should
271 // point to -1 because that's the tail of our implicit list.
272 GAIA_ASSERT(nextFreeItem == TItemHandle::IdMask);
273 }
274 };
275 } // namespace cnt
276} // namespace gaia
Array with variable size of elements of type.
Definition darray_impl.h:25
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition ilist.h:61
Definition ilist.h:15
uint32_t gen
Generation ID.
Definition ilist.h:17
Definition ilist.h:12
Definition ilist.h:14
uint32_t idx
Allocated items: Index in the list. Deleted items: Index of the next deleted item in the list.
Definition ilist.h:22
ItemData data
Item data.
Definition ilist.h:24
Implicit list. Rather than with pointers, items.
Definition ilist.h:76
TListItem & free(TItemHandle handle)
Invalidates handle. Every time an item is deallocated its generation is increased by one.
Definition ilist.h:235
size_type m_nextFreeIdx
Index of the next item to recycle.
Definition ilist.h:96
size_type m_freeItems
Number of items to recycle.
Definition ilist.h:98
void validate() const
Verifies that the implicit linked list is valid.
Definition ilist.h:253
GAIA_NODISCARD TItemHandle alloc()
Allocates a new item in the list.
Definition ilist.h:205
internal_storage m_items
Implicit list items.
Definition ilist.h:94
GAIA_NODISCARD TItemHandle alloc(void *ctx)
Allocates a new item in the list.
Definition ilist.h:175