Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
nonfragmenting_relation_store.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5
6#include "gaia/cnt/darray.h"
7#include "gaia/cnt/map.h"
8#include "gaia/core/utility.h"
9#include "gaia/ecs/id.h"
10
11namespace gaia {
12 namespace ecs {
13 namespace detail {
16 private:
18 struct PairSourceRecord {
20 Entity target = EntityBad;
22 uint32_t targetIdx = BadIndex;
23 };
24
26 cnt::darray<Entity> srcToTgt;
28 cnt::darray<uint32_t> srcToTgtIdx;
32 uint32_t srcToTgtCnt = 0;
35
39 GAIA_NODISCARD uint32_t target_source_index(Entity source) const {
40 if GAIA_UNLIKELY (source.pair()) {
41 const auto it = pairSrcToTgt.find(EntityLookupKey(source));
42 return it != pairSrcToTgt.end() ? it->second.targetIdx : BadIndex;
43 }
44
45 return source.id() < srcToTgtIdx.size() ? srcToTgtIdx[source.id()] : BadIndex;
46 }
47
51 void set_target_source_index(Entity source, uint32_t index) {
52 if GAIA_UNLIKELY (source.pair()) {
53 const auto it = pairSrcToTgt.find(EntityLookupKey(source));
54 GAIA_ASSERT(it != pairSrcToTgt.end());
55 if (it != pairSrcToTgt.end())
56 it->second.targetIdx = index;
57 return;
58 }
59
60 GAIA_ASSERT(source.id() < srcToTgtIdx.size());
61 srcToTgtIdx[source.id()] = index;
62 }
63
64 public:
68 const auto required = (uint32_t)source.id() + 1;
69 if (srcToTgt.size() >= required)
70 return;
71
72 const auto oldSize = (uint32_t)srcToTgt.size();
73 auto newSize = oldSize == 0 ? 16U : oldSize;
74 while (newSize < required)
75 newSize *= 2U;
76
77 srcToTgt.resize(newSize, EntityBad);
78 srcToTgtIdx.resize(newSize, BadIndex);
79 }
80
84 const auto required = target.id() + 1;
85 if (tgtToSrc.size() >= required)
86 return;
87
88 const auto oldSize = (uint32_t)tgtToSrc.size();
89 auto newSize = oldSize == 0 ? 16U : oldSize;
90 while (newSize < required)
91 newSize *= 2U;
92
93 tgtToSrc.resize(newSize);
94 }
95
99 GAIA_NODISCARD Entity target(Entity source) const {
100 if GAIA_UNLIKELY (source.pair()) {
101 const auto it = pairSrcToTgt.find(EntityLookupKey(source));
102 return it != pairSrcToTgt.end() ? it->second.target : EntityBad;
103 }
104
105 if (source.id() >= srcToTgt.size())
106 return EntityBad;
107
108 return srcToTgt[source.id()];
109 }
110
114 GAIA_NODISCARD const cnt::darray<Entity>* sources(Entity target) const {
115 if (target.id() >= tgtToSrc.size())
116 return nullptr;
117
118 const auto& sources = tgtToSrc[target.id()];
119 return sources.empty() ? nullptr : &sources;
120 }
121
124 GAIA_NODISCARD uint32_t source_count() const {
125 return srcToTgtCnt;
126 }
127
131 out.reserve(out.size() + srcToTgtCnt);
132 GAIA_FOR((uint32_t)srcToTgt.size()) {
133 if (srcToTgt[i] == EntityBad)
134 continue;
135
136 out.push_back((EntityId)i);
137 }
138 }
139
143 const auto first = out.size();
144 out.reserve(first + (uint32_t)pairSrcToTgt.size());
145 for (const auto& pair: pairSrcToTgt)
146 out.push_back(pair.first.entity());
147
148 core::sort(out.begin() + first, out.end(), core::is_smaller<Entity>{});
149 }
150
155 GAIA_ASSERT(target.id() < tgtToSrc.size());
156 if (target.id() >= tgtToSrc.size())
157 return;
158
159 auto& sources = tgtToSrc[target.id()];
160 const auto idx = target_source_index(source);
161 GAIA_ASSERT(idx != BadIndex && idx < sources.size());
162 if (idx == BadIndex || idx >= sources.size())
163 return;
164
165 const auto lastIdx = (uint32_t)sources.size() - 1;
166 if (idx != lastIdx) {
167 const auto movedSource = sources[lastIdx];
168 sources[idx] = movedSource;
169 set_target_source_index(movedSource, idx);
170 }
171
173 }
174
179 GAIA_NODISCARD bool set(Entity source, Entity target) {
180 if GAIA_LIKELY (!source.pair())
182 const auto oldTarget = this->target(source);
183 if (oldTarget != EntityBad) {
184 if (oldTarget == target)
185 return false;
186
187 remove_target_source(oldTarget, source);
188 } else {
189 ++srcToTgtCnt;
190 }
191
193 auto& sources = tgtToSrc[target.id()];
194 const auto sourceIdx = (uint32_t)sources.size();
195 if GAIA_UNLIKELY (source.pair())
196 pairSrcToTgt[EntityLookupKey(source)] = PairSourceRecord{target, sourceIdx};
197 else {
198 srcToTgt[source.id()] = target;
199 srcToTgtIdx[source.id()] = sourceIdx;
200 }
201 sources.push_back(source);
202
203 return true;
204 }
205
210 GAIA_NODISCARD bool remove(Entity source, Entity target) {
211 const auto oldTarget = this->target(source);
212 if (oldTarget == EntityBad)
213 return false;
214 if (target != EntityBad && oldTarget != target)
215 return false;
216
217 remove_target_source(oldTarget, source);
218 if GAIA_UNLIKELY (source.pair())
219 pairSrcToTgt.erase(EntityLookupKey(source));
220 else {
221 srcToTgt[source.id()] = EntityBad;
222 srcToTgtIdx[source.id()] = BadIndex;
223 }
224 GAIA_ASSERT(srcToTgtCnt > 0);
225 --srcToTgtCnt;
226 return true;
227 }
228
231 GAIA_NODISCARD bool empty() const {
232 return srcToTgtCnt == 0;
233 }
234 };
235 } // namespace detail
236 } // namespace ecs
237} // namespace gaia
Array of elements of type.
Definition darray_ext_impl.h:31
void pop_back() noexcept
Removes the last element.
Definition darray_ext_impl.h:400
GAIA_NODISCARD size_type size() const noexcept
Returns the number of elements.
Definition darray_ext_impl.h:561
void reserve(size_type cap)
Ensures storage for at least the requested number of elements.
Definition darray_ext_impl.h:266
GAIA_NODISCARD auto begin() noexcept
Returns an iterator to the first element.
Definition darray_ext_impl.h:613
void push_back(const T &arg)
Appends an element.
Definition darray_ext_impl.h:360
GAIA_NODISCARD auto end() noexcept
Returns an iterator one past the last element.
Definition darray_ext_impl.h:649
void resize(size_type count, ResizePolicy policy=ResizePolicy::Exact)
Changes the number of elements.
Definition darray_ext_impl.h:289
iterator erase(iterator pos) noexcept
Removes the element at pos.
Definition darray_ext_impl.h:469
GAIA_NODISCARD bool empty() const noexcept
Checks whether the container has no elements.
Definition darray_ext_impl.h:567
Wrapper for two types forming a relationship pair. Depending on what types are used to form a pair it...
Definition id.h:197
Strict weak ordering functor using operator<.
Definition utility.h:1385
Hashmap lookup structure used for Entity.
Definition id.h:486
Identifier of an entity or component instance in the world. Packs the entity index,...
Definition id.h:231
GAIA_NODISCARD constexpr bool pair() const noexcept
Whether this id refers to a relationship pair.
Definition id.h:313
GAIA_NODISCARD constexpr auto id() const noexcept
Entity index in the entity array.
Definition id.h:295
Storage for exclusive relation pairs that do not fragment archetypes.
Definition nonfragmenting_relation_store.h:15
void collect_source_ids(cnt::darray< EntityId > &out) const
Appends ids of all bound source entities.
Definition nonfragmenting_relation_store.h:130
GAIA_NODISCARD bool remove(Entity source, Entity target)
Removes source from the store.
Definition nonfragmenting_relation_store.h:210
GAIA_NODISCARD const cnt::darray< Entity > * sources(Entity target) const
Returns sources currently bound to target.
Definition nonfragmenting_relation_store.h:114
GAIA_NODISCARD Entity target(Entity source) const
Returns the target currently bound to source.
Definition nonfragmenting_relation_store.h:99
GAIA_NODISCARD bool set(Entity source, Entity target)
Binds source to target.
Definition nonfragmenting_relation_store.h:179
void ensure_target_capacity(Entity target)
Ensures target-indexed storage can hold target.
Definition nonfragmenting_relation_store.h:83
void remove_target_source(Entity target, Entity source)
Removes source from the source bucket for target.
Definition nonfragmenting_relation_store.h:154
GAIA_NODISCARD uint32_t source_count() const
Returns the number of active source bindings.
Definition nonfragmenting_relation_store.h:124
GAIA_NODISCARD bool empty() const
Checks whether the store has no source bindings.
Definition nonfragmenting_relation_store.h:231
void collect_pair_sources(cnt::darray< Entity > &out) const
Appends all bound exact pair sources in deterministic entity order.
Definition nonfragmenting_relation_store.h:142
void ensure_source_capacity(Entity source)
Ensures source-indexed storage can hold source.
Definition nonfragmenting_relation_store.h:67