Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
access_policy.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <helios/ecs/query/details/traits.hpp>
8
9#include <algorithm>
10#include <span>
11#include <string_view>
12#include <utility>
13#include <vector>
14
15namespace helios::ecs {
16
17namespace details {
18
19/**
20 * @brief Checks if two sorted ranges have any common elements.
21 * @details Uses a merge-like algorithm for O(n + m) complexity.
22 * @param lhs The first sorted range
23 * @param rhs The second sorted range
24 * @return True if there are any common elements, false otherwise
25 */
26[[nodiscard]] constexpr bool HasIntersection(
27 std::span<const ComponentTypeId> lhs,
28 std::span<const ComponentTypeId> rhs) noexcept {
29 auto it1 = lhs.begin();
30 auto it2 = rhs.begin();
31
32 while (it1 != lhs.end() && it2 != rhs.end()) {
33 if (*it1 < *it2) {
34 ++it1;
35 } else if (*it2 < *it1) {
36 ++it2;
37 } else {
38 return true;
39 }
40 }
41
42 return false;
43}
44
45/**
46 * @brief Checks if any element from one range exists in another sorted range.
47 * @details For each element in lhs, performs binary search in rhs.
48 * @param lhs The first sorted range
49 * @param rhs The second sorted range
50 * @return True if there are any common elements, false otherwise
51 */
52[[nodiscard]] constexpr bool HasIntersectionBinarySearch(
53 std::span<const ResourceTypeId> lhs,
54 std::span<const ResourceTypeId> rhs) noexcept {
55 if (lhs.size() > rhs.size()) {
56 std::swap(lhs, rhs);
57 }
58
59 const auto binary_search = [rhs](const auto& item) {
60 return std::ranges::binary_search(rhs, item);
61 };
62 return std::ranges::any_of(lhs, binary_search);
63}
64
65} // namespace details
66
67/**
68 * @brief Describes a single component access conflict between two policies.
69 * @details `lhs` is the component type as seen from this policy's side;
70 * `rhs` is the same component type as seen from the other policy's side
71 * (they always refer to the same component — the type that is in conflict).
72 * `lhs_writes` / `rhs_writes` indicate which side holds write access,
73 * allowing callers to determine the exact conflict kind:
74 * - write–write : both true
75 * - write–read : lhs_writes=true, rhs_writes=false
76 * - read–write : lhs_writes=false, rhs_writes=true
77 */
79 ComponentTypeId lhs; ///< Component type from this policy
80 ComponentTypeId rhs; ///< Same component type from the other policy
81 bool lhs_writes = false; ///< True if this policy writes the component
82 bool rhs_writes = false; ///< True if the other policy writes the component
83
84 [[nodiscard]] constexpr bool operator==(
85 const ComponentConflictInfo&) const noexcept = default;
86};
87
88/**
89 * @brief Describes a single resource access conflict between two policies.
90 * @details `lhs` is the resource type as seen from this policy's side;
91 * `rhs` is the same resource type from the other policy.
92 * `lhs_writes` / `rhs_writes` indicate which side holds write access.
93 * At least one of `lhs_writes` / `rhs_writes` is always true in a conflict
94 * (read–read is never a conflict).
95 */
97 ResourceTypeId lhs; ///< Resource type from this policy
98 ResourceTypeId rhs; ///< Same resource type from the other policy
99 bool lhs_writes = false; ///< True if this policy writes the resource
100 bool rhs_writes = false; ///< True if the other policy writes the resource
101
102 [[nodiscard]] constexpr bool operator==(
103 const ResourceConflictInfo&) const noexcept = default;
104};
105
106/**
107 * @brief Stores data access requirements for a system at compile time.
108 * @details Components and resources are each kept in two flat sorted sets
109 * (read / write), deduped across all `Query` / `ReadResources` /
110 * `WriteResources` declarations. This mirrors how resources have always been
111 * stored and removes the per-query descriptor indirection.
112 *
113 * `AccessPolicy` is used to:
114 * - Enable automatic scheduling and conflict detection
115 *
116 * It is compile-time scheduling metadata only. Runtime access validation is
117 * not implemented yet.
118 */
120public:
121 constexpr AccessPolicy() noexcept = default;
122 constexpr AccessPolicy(const AccessPolicy&) = default;
123 constexpr AccessPolicy(AccessPolicy&&) noexcept = default;
124 constexpr ~AccessPolicy() = default;
125
126 constexpr AccessPolicy& operator=(const AccessPolicy&) = default;
127 constexpr AccessPolicy& operator=(AccessPolicy&&) noexcept = default;
128
129 /**
130 * @brief Merges data access declarations from another policy.
131 * @details Performs set-union merge for component and resource read/write
132 * sets while keeping them sorted and deduplicated.
133 * @param other Source policy to merge from
134 */
135 constexpr void Merge(const AccessPolicy& other);
136
137 /**
138 * @brief Merges data access declarations from another policy.
139 * @details Performs set-union merge for component and resource read/write
140 * sets while keeping them sorted and deduplicated.
141 * @param other Source policy to merge from
142 */
143 constexpr void Merge(AccessPolicy&& other);
144
145 /**
146 * @brief Returns all component conflicts between this policy and another.
147 * @details Each entry in the returned vector describes one conflicting
148 * component type and which side(s) write it. The same component type appears
149 * at most once in the result.
150 * @param other Other access policy to inspect
151 * @return Vector of `ComponentConflictInfo`, empty when no conflicts exist
152 */
153 [[nodiscard]] constexpr auto GetQueryConflictsWith(
154 const AccessPolicy& other) const -> std::vector<ComponentConflictInfo>;
155
156 /**
157 * @brief Returns all resource conflicts between this policy and another.
158 * @details Each entry describes one conflicting resource type and which
159 * side(s) write it. The same resource type appears at most once.
160 * @param other Other access policy to inspect
161 * @return Vector of `ResourceConflictInfo`, empty when no conflicts exist
162 */
163 [[nodiscard]] constexpr auto GetResourceConflictsWith(
164 const AccessPolicy& other) const -> std::vector<ResourceConflictInfo>;
165
166 /**
167 * @brief Checks if this policy conflicts with another policy at all.
168 * @details Shorthand for `HasQueryConflictWith || HasResourceConflictWith`.
169 * @param other Other access policy to check against
170 * @return True if any conflict exists, false otherwise
171 */
172 [[nodiscard]] constexpr bool ConflictsWith(
173 const AccessPolicy& other) const noexcept {
174 return HasQueryConflictWith(other) || HasResourceConflictWith(other);
175 }
176
177 /**
178 * @brief Checks if this policy has a component access conflict with another.
179 * @details Conflict exists when:
180 * - Both policies write the same component (write–write), or
181 * - One writes a component the other reads (write–read / read–write).
182 * @param other Other access policy to check against
183 * @return True if a component conflict exists, false otherwise
184 */
185 [[nodiscard]] constexpr bool HasQueryConflictWith(
186 const AccessPolicy& other) const noexcept;
187
188 /**
189 * @brief Checks if this policy has a resource access conflict with another.
190 * @details Conflict exists when both policies access the same resource and at
191 * least one of them writes it.
192 * @param other Other access policy to check against
193 * @return True if a resource conflict exists, false otherwise
194 */
195 [[nodiscard]] constexpr bool HasResourceConflictWith(
196 const AccessPolicy& other) const noexcept;
197
198 /**
199 * @brief Checks if this policy declares any component access.
200 * @return True if any read or write component has been declared
201 */
202 [[nodiscard]] constexpr bool HasComponents() const noexcept {
203 return !read_components_.empty() || !write_components_.empty();
204 }
205
206 /**
207 * @brief Checks if this policy declares any resource access.
208 * @return True if any read or write resource has been declared
209 */
210 [[nodiscard]] constexpr bool HasResources() const noexcept {
211 return !read_resources_.empty() || !write_resources_.empty();
212 }
213
214 /**
215 * @brief Checks if this policy declares read access to a component.
216 * @param type_index Component type index to look up
217 * @return True if the component is in the read set
218 */
219 [[nodiscard]] constexpr bool HasReadComponent(
220 ComponentTypeIndex type_index) const noexcept;
221
222 /**
223 * @brief Checks if this policy declares write access to a component.
224 * @param type_index Component type index to look up
225 * @return True if the component is in the write set
226 */
227 [[nodiscard]] constexpr bool HasWriteComponent(
228 ComponentTypeIndex type_index) const noexcept;
229
230 /**
231 * @brief Checks if this policy declares read access to a resource.
232 * @param type_index Resource type index to look up
233 * @return True if the resource is in the read set
234 */
235 [[nodiscard]] constexpr bool HasReadResource(
236 ResourceTypeIndex type_index) const noexcept;
237
238 /**
239 * @brief Checks if this policy declares write access to a resource.
240 * @param type_index Resource type index to look up
241 * @return True if the resource is in the write set
242 */
243 [[nodiscard]] constexpr bool HasWriteResource(
244 ResourceTypeIndex type_index) const noexcept;
245
246 /**
247 * @brief Returns all component types declared for reading (sorted).
248 * @return A `std::span` view of the read component types
249 */
250 [[nodiscard]] constexpr auto GetReadComponents() const noexcept
251 -> std::span<const ComponentTypeId> {
252 return read_components_;
253 }
254
255 /**
256 * @brief Returns all component types declared for writing (sorted).
257 * @return A `std::span` view of the write component types
258 */
259 [[nodiscard]] constexpr auto GetWriteComponents() const noexcept
260 -> std::span<const ComponentTypeId> {
261 return write_components_;
262 }
263
264 /**
265 * @brief Returns all resource types declared for reading (sorted).
266 * @return A `std::span` view of the read resource types
267 */
268 [[nodiscard]] constexpr auto GetReadResources() const noexcept
269 -> std::span<const ResourceTypeId> {
270 return read_resources_;
271 }
272
273 /**
274 * @brief Returns all resource types declared for writing (sorted).
275 * @return A `std::span` view of the write resource types
276 */
277 [[nodiscard]] constexpr auto GetWriteResources() const noexcept
278 -> std::span<const ResourceTypeId> {
279 return write_resources_;
280 }
281
282private:
283 constexpr AccessPolicy(std::vector<ComponentTypeId>&& read_components,
284 std::vector<ComponentTypeId>&& write_components,
285 std::vector<ResourceTypeId>&& read_resources,
286 std::vector<ResourceTypeId>&& write_resources) noexcept
287 : read_components_(std::move(read_components)),
288 write_components_(std::move(write_components)),
289 read_resources_(std::move(read_resources)),
290 write_resources_(std::move(write_resources)) {}
291
292 std::vector<ComponentTypeId> read_components_; // Sorted, deduped
293 std::vector<ComponentTypeId> write_components_; // Sorted, deduped
294
295 std::vector<ResourceTypeId> read_resources_; // Sorted, deduped
296 std::vector<ResourceTypeId> write_resources_; // Sorted, deduped
297
299};
300
301constexpr void AccessPolicy::Merge(const AccessPolicy& other) {
302 std::vector<ComponentTypeId> merged_read_components;
303 std::vector<ComponentTypeId> merged_write_components;
304 std::vector<ResourceTypeId> merged_read_resources;
305 std::vector<ResourceTypeId> merged_write_resources;
306
307 merged_read_components.reserve(read_components_.size() +
308 other.read_components_.size());
309 merged_write_components.reserve(write_components_.size() +
310 other.write_components_.size());
311 merged_read_resources.reserve(read_resources_.size() +
312 other.read_resources_.size());
313 merged_write_resources.reserve(write_resources_.size() +
314 other.write_resources_.size());
315
316 std::ranges::set_union(read_components_, other.read_components_,
317 std::back_inserter(merged_read_components));
318 std::ranges::set_union(write_components_, other.write_components_,
319 std::back_inserter(merged_write_components));
320 std::ranges::set_union(read_resources_, other.read_resources_,
321 std::back_inserter(merged_read_resources));
322 std::ranges::set_union(write_resources_, other.write_resources_,
323 std::back_inserter(merged_write_resources));
324
325 read_components_ = std::move(merged_read_components);
326 write_components_ = std::move(merged_write_components);
327 read_resources_ = std::move(merged_read_resources);
328 write_resources_ = std::move(merged_write_resources);
329}
330
331constexpr void AccessPolicy::Merge(AccessPolicy&& other) {
332 Merge(static_cast<const AccessPolicy&>(other));
333}
334
336 const AccessPolicy& other) const -> std::vector<ComponentConflictInfo> {
337 std::vector<ComponentConflictInfo> result;
338
339 // Helper: add a conflict entry for a matching component, avoiding duplicates.
340 // `lhs_type_id` is from this policy's set; `rhs_type_id` from other's set.
341 const auto emit = [&result](const ComponentTypeId& lhs_type_id,
342 const ComponentTypeId& rhs_type_id,
343 bool lhs_writes, bool rhs_writes) {
344 // Same component always appears at most once in the result.
345 const auto already_recorded =
346 [&lhs_type_id](const ComponentConflictInfo& conflict) {
347 return conflict.lhs == lhs_type_id;
348 };
349 if (!std::ranges::any_of(result, already_recorded)) {
350 result.emplace_back(lhs_type_id, rhs_type_id, lhs_writes, rhs_writes);
351 }
352 };
353
354 // Walk sorted pairs with a merge-like scan for O(n + m) per pass.
355 const auto collect = [&emit](std::span<const ComponentTypeId> lhs_set,
356 std::span<const ComponentTypeId> rhs_set,
357 bool lhs_writes, bool rhs_writes) {
358 auto it1 = lhs_set.begin();
359 auto it2 = rhs_set.begin();
360 while (it1 != lhs_set.end() && it2 != rhs_set.end()) {
361 if (*it1 < *it2) {
362 ++it1;
363 } else if (*it2 < *it1) {
364 ++it2;
365 } else {
366 emit(*it1, *it2, lhs_writes, rhs_writes);
367 ++it1;
368 ++it2;
369 }
370 }
371 };
372
373 // write–write
374 collect(write_components_, other.write_components_, true, true);
375 // my write vs other read
376 collect(write_components_, other.read_components_, true, false);
377 // my read vs other write
378 collect(read_components_, other.write_components_, false, true);
379
380 return result;
381}
382
384 const AccessPolicy& other) const -> std::vector<ResourceConflictInfo> {
385 std::vector<ResourceConflictInfo> result;
386
387 // Helper: record a conflict, avoiding duplicate entries for the same
388 // resource.
389 const auto emit = [&result](const ResourceTypeId& lhs_type_id,
390 const ResourceTypeId& rhs_type_id,
391 bool lhs_writes, bool rhs_writes) {
392 const auto already_recorded =
393 [&lhs_type_id](const ResourceConflictInfo& conflict) {
394 return conflict.lhs == lhs_type_id;
395 };
396 if (!std::ranges::any_of(result, already_recorded)) {
397 result.emplace_back(lhs_type_id, rhs_type_id, lhs_writes, rhs_writes);
398 }
399 };
400
401 // Sorted scan for the two component sets; binary-search scan for
402 // resources (matching the existing HasIntersectionBinarySearch strategy).
403 const auto collect = [&emit](std::span<const ResourceTypeId> lhs_set,
404 std::span<const ResourceTypeId> rhs_set,
405 bool lhs_writes, bool rhs_writes) {
406 for (const auto& lhs_id : lhs_set) {
407 if (std::ranges::binary_search(rhs_set, lhs_id)) {
408 // Recover the matching rhs entry for symmetry in the descriptor.
409 const auto it = std::ranges::lower_bound(rhs_set, lhs_id);
410 emit(lhs_id, *it, lhs_writes, rhs_writes);
411 }
412 }
413 };
414
415 // write–write
416 collect(write_resources_, other.write_resources_, true, true);
417 // my write vs other read
418 collect(write_resources_, other.read_resources_, true, false);
419 // my read vs other write
420 collect(read_resources_, other.write_resources_, false, true);
421
422 return result;
423}
424
426 const AccessPolicy& other) const noexcept {
427 if (!HasComponents() || !other.HasComponents()) {
428 return false;
429 }
430
431 // write–write
432 if (!write_components_.empty() && !other.write_components_.empty() &&
433 details::HasIntersection(write_components_, other.write_components_)) {
434 return true;
435 }
436
437 // my write vs other read
438 if (!write_components_.empty() && !other.read_components_.empty() &&
439 details::HasIntersection(write_components_, other.read_components_)) {
440 return true;
441 }
442
443 // my read vs other write
444 if (!read_components_.empty() && !other.write_components_.empty() &&
445 details::HasIntersection(read_components_, other.write_components_)) {
446 return true;
447 }
448
449 return false;
450}
451
453 const AccessPolicy& other) const noexcept {
454 if (!HasResources() || !other.HasResources()) {
455 return false;
456 }
457
458 // write–write
459 if (!write_resources_.empty() && !other.write_resources_.empty() &&
461 other.write_resources_)) {
462 return true;
463 }
464
465 // my write vs other read
466 if (!write_resources_.empty() && !other.read_resources_.empty() &&
468 other.read_resources_)) {
469 return true;
470 }
471
472 // my read vs other write
473 if (!read_resources_.empty() && !other.write_resources_.empty() &&
475 other.write_resources_)) {
476 return true;
477 }
478
479 return false;
480}
481
483 ComponentTypeIndex type_index) const noexcept {
484 const auto matches = [type_index](const ComponentTypeId& id) {
485 return id == type_index;
486 };
487 return std::ranges::any_of(read_components_, matches);
488}
489
491 ComponentTypeIndex type_index) const noexcept {
492 const auto matches = [type_index](const ComponentTypeId& id) {
493 return id == type_index;
494 };
495 return std::ranges::any_of(write_components_, matches);
496}
497
499 ResourceTypeIndex type_index) const noexcept {
500 const auto matches = [type_index](const ResourceTypeId& id) {
501 return id == type_index;
502 };
503 return std::ranges::any_of(read_resources_, matches);
504}
505
507 ResourceTypeIndex type_index) const noexcept {
508 const auto matches = [type_index](const ResourceTypeId& id) {
509 return id == type_index;
510 };
511 return std::ranges::any_of(write_resources_, matches);
512}
513
514/**
515 * @brief Fluent builder for constructing an `AccessPolicy`.
516 * @details Accumulates component and resource access declarations across any
517 * number of `Query`, `ReadResources`, and `WriteResources` calls.
518 * Duplicate entries are silently ignored; all sets are kept sorted.
519 *
520 * @code
521 * helios::ecs::AccessPolicyBuilder()
522 * .Query<const Transform&, const Velocity&>()
523 * .Query<Gravity, Health*>()
524 * .ReadResources<Camera, RenderSettings>()
525 * .WriteResources<RenderQueue>()
526 * .Build();
527 * @endcode
528 */
530public:
531 constexpr AccessPolicyBuilder() noexcept = default;
532 constexpr AccessPolicyBuilder(const AccessPolicyBuilder&) = default;
533 constexpr AccessPolicyBuilder(AccessPolicyBuilder&&) noexcept = default;
534 constexpr ~AccessPolicyBuilder() = default;
535
536 constexpr AccessPolicyBuilder& operator=(const AccessPolicyBuilder&) =
537 default;
538 constexpr AccessPolicyBuilder& operator=(AccessPolicyBuilder&&) noexcept =
539 default;
540
541 /**
542 * @brief Builds and returns the accumulated `AccessPolicy`.
543 * @return The accumulated `AccessPolicy`
544 */
545 constexpr AccessPolicy Build() noexcept {
546 return {std::move(read_components_), std::move(write_components_),
547 std::move(read_resources_), std::move(write_resources_)};
548 }
549
550 /**
551 * @brief Declares a query over component types.
552 * @details Component accesses are merged into the policy-wide flat read /
553 * write sets. Duplicates are silently ignored (a component already declared
554 * for writing is not re-added if the same type appears again as a write in a
555 * later `Query` call).
556 *
557 * Access classification:
558 * - `const T&`, `const T*`, `const T`, `T` (value copy) → read
559 * - `T&`, `T&&`, `T*` → write
560 *
561 * Tag components (empty types) are excluded from conflict tracking.
562 *
563 * @tparam Components Component access types
564 * @return `*this` for method chaining
565 */
566 template <typename... Components>
567 requires details::UniqueComponentAccess<Components...> &&
569 ...)
570 constexpr auto Query(this auto&& self)
571 -> decltype(std::forward<decltype(self)>(self));
572
573 /**
574 * @brief Declares read-only access to resource types.
575 * @details Thread-safe resources are silently ignored.
576 * @tparam Resources Resource types to read
577 * @return `*this` for method chaining
578 */
579 template <ResourceTrait... Resources>
580 requires utils::UniqueTypes<Resources...>
581 constexpr auto ReadResources(this auto&& self)
582 -> decltype(std::forward<decltype(self)>(self));
583
584 /**
585 * @brief Declares write access to resource types.
586 * @details Thread-safe resources are silently ignored.
587 * @tparam Resources Resource types to write
588 * @return `*this` for method chaining
589 */
590 template <ResourceTrait... Resources>
591 requires utils::UniqueTypes<Resources...>
592 constexpr auto WriteResources(this auto&& self)
593 -> decltype(std::forward<decltype(self)>(self));
594
595private:
596 static constexpr void InsertSorted(std::vector<utils::TypeId>& vec,
597 const utils::TypeId& type_id);
598
599 std::vector<ComponentTypeId> read_components_; ///< Sorted, deduped
600 std::vector<ComponentTypeId> write_components_; ///< Sorted, deduped
601 std::vector<ResourceTypeId> read_resources_; ///< Sorted, deduped
602 std::vector<ResourceTypeId> write_resources_; ///< Sorted, deduped
603};
604
605template <typename... Components>
606 requires details::UniqueComponentAccess<Components...> &&
607 (ComponentTrait<details::ComponentTypeExtractor_t<Components>> &&
608 ...)
609constexpr auto AccessPolicyBuilder::Query(this auto&& self)
610 -> decltype(std::forward<decltype(self)>(self)) {
611 (
612 [&self]() {
613 using RawComponent = details::ComponentTypeExtractor_t<Components>;
614
615 // Tag components have no data to conflict on.
616 if constexpr (TagComponentTrait<RawComponent>) {
617 return;
618 } else if constexpr (details::kIsConstAccess<Components>) {
619 self.InsertSorted(self.read_components_,
621 } else {
622 self.InsertSorted(self.write_components_,
624 }
625 }(),
626 ...);
627
628 return std::forward<decltype(self)>(self);
629}
630
631template <ResourceTrait... Resources>
632 requires utils::UniqueTypes<Resources...>
633constexpr auto AccessPolicyBuilder::ReadResources(this auto&& self)
634 -> decltype(std::forward<decltype(self)>(self)) {
635 (
636 [&self]() {
637 if constexpr (!IsResourceThreadSafe<Resources>()) {
638 self.InsertSorted(self.read_resources_,
640 }
641 }(),
642 ...);
643
644 return std::forward<decltype(self)>(self);
645}
646
647template <ResourceTrait... Resources>
648 requires utils::UniqueTypes<Resources...>
649constexpr auto AccessPolicyBuilder::WriteResources(this auto&& self)
650 -> decltype(std::forward<decltype(self)>(self)) {
651 (
652 [&self]() {
653 if constexpr (!IsResourceThreadSafe<Resources>()) {
654 self.InsertSorted(self.write_resources_,
656 }
657 }(),
658 ...);
659
660 return std::forward<decltype(self)>(self);
661}
662
663constexpr void AccessPolicyBuilder::InsertSorted(
664 std::vector<utils::TypeId>& vec, const utils::TypeId& type_id) {
665 const auto cmp = [](const utils::TypeId& lhs, const utils::TypeId& rhs) {
666 return lhs < rhs;
667 };
668 const auto pos = std::ranges::lower_bound(vec, type_id, cmp);
669 if (pos == vec.end() || *pos != type_id) {
670 vec.insert(pos, type_id);
671 }
672}
673
674} // namespace helios::ecs
constexpr AccessPolicy Build() noexcept
Builds and returns the accumulated AccessPolicy.
constexpr auto ReadResources(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Declares read-only access to resource types.
constexpr auto Query(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Declares a query over component types.
constexpr auto WriteResources(this auto &&self) -> decltype(std::forward< decltype(self)>(self))
Declares write access to resource types.
constexpr AccessPolicyBuilder() noexcept=default
Stores data access requirements for a system at compile time.
constexpr AccessPolicy() noexcept=default
constexpr auto GetQueryConflictsWith(const AccessPolicy &other) const -> std::vector< ComponentConflictInfo >
Returns all component conflicts between this policy and another.
constexpr auto GetReadResources() const noexcept -> std::span< const ResourceTypeId >
Returns all resource types declared for reading (sorted).
constexpr void Merge(const AccessPolicy &other)
Merges data access declarations from another policy.
constexpr bool HasComponents() const noexcept
Checks if this policy declares any component access.
constexpr bool ConflictsWith(const AccessPolicy &other) const noexcept
Checks if this policy conflicts with another policy at all.
constexpr auto GetReadComponents() const noexcept -> std::span< const ComponentTypeId >
Returns all component types declared for reading (sorted).
constexpr auto GetResourceConflictsWith(const AccessPolicy &other) const -> std::vector< ResourceConflictInfo >
Returns all resource conflicts between this policy and another.
constexpr bool HasResources() const noexcept
Checks if this policy declares any resource access.
constexpr bool HasReadComponent(ComponentTypeIndex type_index) const noexcept
Checks if this policy declares read access to a component.
constexpr bool HasResourceConflictWith(const AccessPolicy &other) const noexcept
Checks if this policy has a resource access conflict with another.
constexpr bool HasReadResource(ResourceTypeIndex type_index) const noexcept
Checks if this policy declares read access to a resource.
constexpr auto GetWriteComponents() const noexcept -> std::span< const ComponentTypeId >
Returns all component types declared for writing (sorted).
constexpr auto GetWriteResources() const noexcept -> std::span< const ResourceTypeId >
Returns all resource types declared for writing (sorted).
constexpr bool HasWriteComponent(ComponentTypeIndex type_index) const noexcept
Checks if this policy declares write access to a component.
constexpr bool HasQueryConflictWith(const AccessPolicy &other) const noexcept
Checks if this policy has a component access conflict with another.
constexpr bool HasWriteResource(ResourceTypeIndex type_index) const noexcept
Checks if this policy declares write access to a resource.
static constexpr TypeId From() noexcept
Constructs a TypeId from a type T.
Concept to check if a type can be used as a component.
Definition component.hpp:31
Concept for valid resource types.
Definition resource.hpp:25
Concept to check if the type is considered a tag component.
Definition component.hpp:43
Concept that checks if all types in a pack are unique (after removing cv/ref qualifiers).
constexpr bool HasIntersection(std::span< const ComponentTypeId > lhs, std::span< const ComponentTypeId > rhs) noexcept
Checks if two sorted ranges have any common elements.
constexpr bool HasIntersectionBinarySearch(std::span< const ResourceTypeId > lhs, std::span< const ResourceTypeId > rhs) noexcept
Checks if any element from one range exists in another sorted range.
utils::TypeId ResourceTypeId
Type id for resources.
Definition resource.hpp:17
BasicQuery< World, std::pmr::polymorphic_allocator<>, Args... > Query
Alias for BasicQuery bound to World with a PMR allocator.
Definition query.hpp:2264
utils::TypeIndex ResourceTypeIndex
Type index for resources.
Definition resource.hpp:14
utils::TypeId ComponentTypeId
Type id for components.
Definition component.hpp:17
utils::TypeIndex ComponentTypeIndex
Type index for components.
Definition component.hpp:14
consteval bool IsResourceThreadSafe() noexcept
Checks if a resource type is thread-safe.
Definition resource.hpp:119
STL namespace.
Describes a single component access conflict between two policies.
ComponentTypeId lhs
Component type from this policy.
ComponentTypeId rhs
Same component type from the other policy.
bool lhs_writes
True if this policy writes the component.
bool rhs_writes
True if the other policy writes the component.
constexpr bool operator==(const ComponentConflictInfo &) const noexcept=default
Describes a single resource access conflict between two policies.
constexpr bool operator==(const ResourceConflictInfo &) const noexcept=default
ResourceTypeId lhs
Resource type from this policy.
bool rhs_writes
True if the other policy writes the resource.
ResourceTypeId rhs
Same resource type from the other policy.
bool lhs_writes
True if this policy writes the resource.