Skip to main content

View.ixx File

Lightweight view for iterating entities with specific components. More...

Included Headers

#include <tuple> #include <vector> #include <functional> #include <helios.ecs.types.EntityHandle> #include <helios.ecs.concepts.Traits> #include <helios.ecs.Entity> #include <helios.ecs.EntityManager> #include <helios.ecs.types.TypeDefs> #include <helios.ecs.SparseSet> #include <helios.ecs.components>

Namespaces Index

namespacehelios
namespaceecs

Classes Index

classPartialView<TEntityManager, std::tuple< TRequired... >, std::tuple< TDirty... >, std::tuple< TOptional... >>
structIterator<TEntityManager, std::tuple< TRequired... >, std::tuple< TDirty... >, std::tuple< TOptional... > >::Iterator

Forward iterator for View traversal. More...

Description

Lightweight view for iterating entities with specific components.

File Listing

The file content with the documentation metadata removed is:

1
5module;
6
7#include <tuple>
8#include <vector>
9#include <functional>
10
11export module helios.ecs.View;
12
13import helios.ecs.components;
14import helios.ecs.SparseSet;
15import helios.ecs.types.TypeDefs;
16import helios.ecs.EntityManager;
17import helios.ecs.Entity;
18import helios.ecs.concepts.Traits;
19import helios.ecs.types.EntityHandle;
20
21using namespace helios::ecs::types;
22using namespace helios::ecs::components;
24export namespace helios::ecs {
25
57 template<typename TEntityManager, typename TRequiredComponents, typename TDirtyComponents, typename TOptionalComponents>
59
68 template<typename TEntityManager, typename... TRequired>
69 using View = PartialView<TEntityManager, std::tuple<TRequired...>, std::tuple<>, std::tuple<>>;
70
71 template<typename TEntityManager, typename... TRequired, typename... TDirty, typename... TOptional>
72 class PartialView<TEntityManager, std::tuple<TRequired...>, std::tuple<TDirty...>, std::tuple<TOptional...>> {
73
74 private:
75 TEntityManager* em_;
76
80 std::tuple<SparseSet<TRequired>*... > includeSets_;
81
85 std::tuple<SparseSet<TOptional>*... > optionalSets_;
86
90 std::tuple<SparseSet<DirtyComponentSpec<TDirty>>*... > anyDirtySets_;
91
92
98 std::vector<std::function<bool(EntityId)>> excludeChecks_;
99
104
108 bool filterActiveOnly_ = false;
109
110 public:
116 explicit PartialView(TEntityManager* em)
117 requires (sizeof...(TOptional) == 0 && sizeof...(TDirty) == 0)
118 : em_(em) {
119 // Retrieve pointers to the specific component sets immediately.
120 includeSets_ = std::make_tuple(em_->template sparseSet<TRequired>()...);
121 };
122
123
133 explicit PartialView(
134 TEntityManager* em,
135 std::tuple<SparseSet<TRequired>*...> includeSets,
136 std::vector<std::function<bool(EntityId)>> excludeChecks,
137 const bool filterActiveOnly,
139 ) : em_(em),
140 includeSets_(std::move(includeSets)),
141 excludeChecks_(std::move(excludeChecks)),
142 filterActiveOnly_(filterActiveOnly),
143 activeSet_(activeSet),
144
145 optionalSets_(std::make_tuple(em_->template sparseSet<TOptional>()...)),
146 anyDirtySets_(std::make_tuple(em_->template sparseSet<DirtyComponentSpec<TDirty>>()...))
147 {}
148
171 template<typename... TNewOptional>
173 requires (sizeof...(TOptional) == 0)
174 {
175 return PartialView<
176 TEntityManager,
177 std::tuple<TRequired...>,
178 std::tuple<TDirty...>,
179 std::tuple<TNewOptional...>>(
180 em_,
181 includeSets_,
182 excludeChecks_,
183 filterActiveOnly_,
184 activeSet_,
185 anyDirtySets_
186 );
187 }
188
194 template<typename... TNewDirty>
195 auto whereAnyDirty() requires (sizeof...(TOptional) == 0 && sizeof...(TDirty) == 0) {
196
197 return PartialView<
198 TEntityManager,
199 std::tuple<TRequired...>,
200 std::tuple<TNewDirty...>,
201 std::tuple<>
202 >(
203 em_,
204 includeSets_,
205 excludeChecks_,
206 filterActiveOnly_,
207 activeSet_
208 );
209
210 }
211
231 template<typename T>
233 auto* set = em_->template sparseSet<T>();
234
235 if (set) {
236 excludeChecks_.emplace_back([set](EntityId entityId) {
237 return set->contains(entityId);
238 });
239 }
240 return *this;
241 }
242
248 [[nodiscard]] bool empty() {
249 auto* leadSet = std::get<0>(includeSets_);
250 if (!leadSet) {
251 return true;
252 }
253 return begin() == end();
254 }
255
262 activeSet_ = em_->template sparseSet<Active<typename TEntityManager::Handle_type>>();
263 filterActiveOnly_ = true;
264 return *this;
265 }
266
274 struct Iterator {
275
277
281 using LeadComponent = std::tuple_element_t<0, std::tuple<TRequired...>>;
282
287
291
295 Iterator() = default;
296
304 Iterator(LeadIterator current, LeadIterator end, const PartialView* view)
305 : current_(current), end_(end), view_(view) {}
306
317 [[nodiscard]] bool isValid() const {
318 if (current_ == end_) {
319 return true;
320 }
321
322 // 1 Get Entity ID (from the Lead Iterator)
323 EntityId entityId = current_.entityId();
324
325 if (!view_->em_->isValid(entityId)) {
326 return false;
327 }
328
329 // 2 INCLUDE CHECK (Do we have all other required components?)
330 // We iterate over the tuple of sets and check 'contains' for each.
331 const bool hasAllIncludes = std::apply([entityId](auto*... sets) {
332 return ((sets && sets->contains(entityId)) && ...);
333 }, view_->includeSets_);
334
335 if (view_->filterActiveOnly_ && (!view_->activeSet_ || !view_->activeSet_->contains(entityId))) {
336 return false;
337 }
338
339 if (!hasAllIncludes) {
340 return false;
341 }
342
343 // dirty check
344 if constexpr (sizeof...(TDirty) > 0) {
345 const bool hasAnyDirtyIncludes = std::apply([entityId](auto*... sets) {
346 return ((sets && sets->contains(entityId)) || ...);
347 }, view_->anyDirtySets_);
348
349 if (!hasAnyDirtyIncludes) {
350 return false;
351 }
352 }
353
354 // 3 EXCLUDE CHECK (Must NOT be present)
355 for (const auto& excludeCheck : view_->excludeChecks_) {
356 if (excludeCheck(entityId)) {
357 return false; // If check returns true (has component), the entity is invalid.
358 }
359 }
360
361
362 return true;
363 }
364
371 void advance() {
372 do {
373 ++current_;
374 } while (current_ != end_ && !isValid());
375 }
376
382 Iterator& operator++() noexcept {
383 advance();
384 return *this;
385 }
386
394 bool operator!=(const Iterator& other) const noexcept {
395 return current_ != other.current_;
396 }
397
411 [[nodiscard]] auto operator*() const {
412 EntityId entityId = current_.entityId();
413 auto handle = view_->em_->handle(entityId);
414
415
416 return std::tuple_cat(
417 std::make_tuple(Entity_type(handle, view_->em_)),
418 std::apply([entityId](auto*... sets) {
419 return std::make_tuple(sets->get(entityId)...);
420 }, view_->includeSets_),
421
422 std::apply([
423 entityId
424 ](auto*... sets) {
425 return std::make_tuple(
426 ([entityId, &sets]() {
427 if (!sets || !sets->contains(entityId)) {
428 return nullptr;
429 }
430
431 return sets->get(entityId);
432 }())...
433
434 );
435 }, view_->optionalSets_)
436
437 );
438 }
439
440 [[nodiscard]] bool operator==(const Iterator& other) const noexcept {
441 return current_ == other.current_;
442 }
443 };
444
453 [[nodiscard]] Iterator begin() {
454 auto* leadSet = std::get<0>(includeSets_);
455
456 if (!leadSet) {
457 return Iterator{};
458 }
459
460 Iterator it{leadSet->begin(), leadSet->end(), this};
461
462 if (!it.isValid()) {
463 it.advance();
464 }
465
466 return it;
467 }
468
474 [[nodiscard]] Iterator end() {
475 auto* leadSet = std::get<0>(includeSets_);
476
477 if (!leadSet) {
478 return Iterator{};
479 }
480
481 return Iterator{leadSet->end(), leadSet->end(), this};
482 }
483
484 };
485}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.