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.Entity> #include <helios.ecs.EntityManager> #include <helios.ecs.types.TypeDefs> #include <helios.ecs.SparseSet>

Namespaces Index

namespacehelios
namespaceecs

Classes Index

classPartialView<TEntityManager, std::tuple< TRequired... >, std::tuple< TOptional... >>
structIterator<TEntityManager, std::tuple< TRequired... >, 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.SparseSet;
14import helios.ecs.types.TypeDefs;
15import helios.ecs.EntityManager;
16import helios.ecs.Entity;
17import helios.ecs.types.EntityHandle;
18
19using namespace helios::ecs::types;
20export namespace helios::ecs {
21
52 template<typename TEntityManager, typename TRequiredComponents, typename TOptionalComponents>
54
63 template<typename TEntityManager, typename... TRequired>
64 using View = PartialView<TEntityManager, std::tuple<TRequired...>, std::tuple<>>;
65
66 template<typename TEntityManager, typename... TRequired, typename... TOptional>
67 class PartialView<TEntityManager, std::tuple<TRequired...>, std::tuple<TOptional...>> {
68
69 private:
70 TEntityManager* em_;
71
75 std::tuple<SparseSet<TRequired>*... > includeSets_;
76
77
78 std::tuple<SparseSet<TOptional>*... > optionalSets_;
79
85 std::vector<std::function<bool(EntityId)>> excludeChecks_;
86
90 bool filterEnabledOnly_ = false;
91
92
93 public:
100 explicit PartialView(TEntityManager* em) : em_(em) {
101 // Retrieve pointers to the specific component sets immediately.
102 includeSets_ = std::make_tuple(em_->template getSparseSet<TRequired>()...);
103 optionalSets_ = std::make_tuple(em_->template getSparseSet<TOptional>()...);
104 };
105
106 explicit PartialView(
107 TEntityManager* em,
108 std::tuple<SparseSet<TRequired>*...> includeSets,
109 std::vector<std::function<bool(EntityId)>> excludeChecks,
110 const bool filterEnabledOnly
111 ) : em_(em), includeSets_(includeSets), excludeChecks_(std::move(excludeChecks)), filterEnabledOnly_(filterEnabledOnly) {
112 static_assert(sizeof...(TOptional) == 0, "withOptional() should provide all optional components types in a single call.");
113 optionalSets_ = std::make_tuple(em_->template getSparseSet<TOptional>()...);
114 }
115
138 template<typename... TNewOptional>
139 PartialView<TEntityManager, std::tuple<TRequired...>, std::tuple<TNewOptional...>> withOptional() {
140 return PartialView<TEntityManager, std::tuple<TRequired...>, std::tuple<TNewOptional...>>(
141 em_, includeSets_, excludeChecks_, filterEnabledOnly_
142 );
143 }
144
164 template<typename T>
166 auto* set = em_->template getSparseSet<T>();
167
168 if (set) {
169 excludeChecks_.emplace_back([set](EntityId entityId) {
170 return set->contains(entityId);
171 });
172 }
173 return *this;
174 }
175
176 [[nodiscard]] bool empty() {
177 auto* leadSet = std::get<0>(includeSets_);
178 if (!leadSet) {
179 return true;
180 }
181 return begin() == end();
182 }
183
193 filterEnabledOnly_ = true;
194 return *this;
195 }
196
204 struct Iterator {
205
207
211 using LeadComponent = std::tuple_element_t<0, std::tuple<TRequired...>>;
212
217
221
225 Iterator() = default;
226
234 Iterator(LeadIterator current, LeadIterator end, const PartialView* view)
235 : current_(current), end_(end), view_(view) {}
236
248 [[nodiscard]] bool isValid() const {
249 if (current_ == end_) {
250 return true;
251 }
252
253 // 1 Get Entity ID (from the Lead Iterator)
254 EntityId entityId = current_.entityId();
255
256 if (!view_->em_->isValid(entityId)) {
257 return false;
258 }
259
260 // 2 INCLUDE CHECK (Do we have all other required components?)
261 // We iterate over the tuple of sets and check 'contains' for each.
262 const bool hasAllIncludes = std::apply([entityId](auto*... sets) {
263 return ((sets && sets->contains(entityId)) && ...);
264 }, view_->includeSets_);
265
266 if (!hasAllIncludes) {
267 return false;
268 }
269
270 // 3 EXCLUDE CHECK (Must NOT be present)
271 for (const auto& excludeCheck : view_->excludeChecks_) {
272 if (excludeCheck(entityId)) {
273 return false; // If check returns true (has component), the entity is invalid.
274 }
275 }
276
277 // 4 ENABLED CHECK (State)
278 if (view_->filterEnabledOnly_) {
279
280 // SFINAE Helper Lambda: Checks if .isEnabled() exists.
281 auto isComponentEnabled = [](const auto& comp) -> bool {
282 if constexpr (requires { comp.isEnabled(); }) {
283 return comp.isEnabled();
284 } else {
285 return true; // Assume enabled if method is missing.
286 }
287 };
288
289 // Check the Lead component (*current_ returns the component reference)
290 if (!isComponentEnabled(*current_)) {
291 return false;
292 }
293
294 // Check all other included components
295 const bool allEnabled = std::apply([&](auto*... sets) {
296 // sets->get(id) returns a pointer, *ptr gives the reference.
297 return (isComponentEnabled(*sets->get(entityId)) && ...);
298 }, view_->includeSets_);
299
300 if (!allEnabled) {
301 return false;
302 }
303 }
304
305 return true;
306 }
307
314 void advance() {
315 do {
316 ++current_;
317 } while (current_ != end_ && !isValid());
318 }
319
325 Iterator& operator++() noexcept {
326 advance();
327 return *this;
328 }
329
337 bool operator!=(const Iterator& other) const noexcept {
338 return current_ != other.current_;
339 }
340
355 [[nodiscard]] auto operator*() const {
356 EntityId entityId = current_.entityId();
357 auto handle = view_->em_->handle(entityId);
358
359
360 return std::tuple_cat(
361 std::make_tuple(Entity_type(handle, view_->em_)),
362 std::apply([entityId](auto*... sets) {
363 return std::make_tuple(sets->get(entityId)...);
364 }, view_->includeSets_),
365
366 std::apply([entityId, filterEnabledOnly = view_->filterEnabledOnly_](auto*... sets) {
367 return std::make_tuple(
368 ([filterEnabledOnly, entityId, &sets]() {
369 if (!sets || !sets->contains(entityId)) {
370 return nullptr;
371 }
372
373 auto* component = sets->get(entityId);
374
375 if constexpr (requires {component->isEnabled(); }) {
376 if (filterEnabledOnly && !component->isEnabled()) {
377 return nullptr;
378 }
379 }
380
381 return component;
382 }())...
383
384 );
385 }, view_->optionalSets_)
386
387 );
388 }
389
390 [[nodiscard]] bool operator==(const Iterator& other) const noexcept {
391 return current_ == other.current_;
392 }
393 };
394
403 [[nodiscard]] Iterator begin() {
404 auto* leadSet = std::get<0>(includeSets_);
405
406 if (!leadSet) {
407 return Iterator{};
408 }
409
410 Iterator it{leadSet->begin(), leadSet->end(), this};
411
412 if (!it.isValid()) {
413 it.advance();
414 }
415
416 return it;
417 }
418
424 [[nodiscard]] Iterator end() {
425 auto* leadSet = std::get<0>(includeSets_);
426
427 if (!leadSet) {
428 return Iterator{};
429 }
430
431 return Iterator{leadSet->end(), leadSet->end(), this};
432 }
433
434 };
435}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.