Skip to main content

CombinedStateToIdMapPair.ixx File

Combined policy mapping two state types to IDs using 2D indexing. More...

Included Headers

#include <vector> #include <span> #include <helios/helios_config.h> #include <cassert> #include <bit> #include <algorithm> #include <iterator> #include <helios.core.types> #include <helios.engine.mechanics.match.types> #include <helios.engine.state.types> #include <helios.engine.common.types.ViewportId> #include <helios.engine.state.StateToIdMap>

Namespaces Index

namespacehelios
namespaceengine

Main engine module aggregating core infrastructure and game systems. More...

namespacestate

Generic, template-based state management system. More...

Classes Index

classCombinedStateToIdMapPair<LState, RState, TId>

Maps combined state pairs directly to ID lists. More...

Description

Combined policy mapping two state types to IDs using 2D indexing.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file CombinedStateToIdMapPair.ixx
3 * @brief Combined policy mapping two state types to IDs using 2D indexing.
4 */
5module;
6
7#include <vector>
8#include <span>
9#include <helios/helios_config.h>
10#include <cassert>
11#include <bit>
12#include <algorithm>
13#include <iterator>
14#include <bit>
15
16export module helios.engine.state.CombinedStateToIdMapPair;
17
18import helios.engine.state.StateToIdMap;
19
20import helios.engine.state.types;
21import helios.engine.mechanics.match.types;
22
23import helios.engine.common.types.ViewportId;
24import helios.core.types;
25
27using namespace helios::engine::state::types;
29
30export namespace helios::engine::state {
31
32 /**
33 * @brief Maps combined state pairs directly to ID lists.
34 *
35 * @details Unlike StateToIdMapPair which stores IDs per state type
36 * and merges them at lookup time, this class uses a 2D matrix indexed
37 * by both state bit positions. This allows associating IDs with
38 * specific state combinations rather than individual states.
39 *
40 * The right state (RState) supports an "undefined" value (0) which
41 * maps to index 0, allowing fallback behavior when only the left
42 * state is defined.
43 *
44 * @tparam LState The left/primary state type.
45 * @tparam RState The right/secondary state type.
46 * @tparam TId The ID type to associate with state combinations.
47 *
48 * @see StateToIdMapPair
49 */
50 template<typename LState, typename RState, typename TId>
52
53 /**
54 * @brief 2D matrix of ID lists indexed by [LState][RState].
55 */
56 std::vector<std::vector<std::vector<TId>>> states_;
57
58 /**
59 * @brief Empty vector returned for invalid lookups.
60 */
61 const std::vector<TId> empty_;
62
63 /**
64 * @brief Whether the map is frozen.
65 */
66 bool frozen_ = false;
67
68 /**
69 * @brief Computes the index for a left state value.
70 *
71 * @param stateLft The left state (must be non-zero, power of 2).
72 *
73 * @return The bit position index.
74 */
75 [[nodiscard]] static constexpr size_t indexOf(const LState stateLft) {
76 const auto stL = static_cast<size_t>(std::to_underlying(stateLft));
77 assert(stL != 0 && "LState must be defined");
78
79 assert((std::to_underlying(stateLft) & (std::to_underlying(stateLft) -1)) == 0 && "LState must be a power of 2");
80
81 return std::countr_zero(std::to_underlying(stateLft));
82 }
83
84 /**
85 * @brief Computes the index for a right state value.
86 *
87 * @details Supports undefined (0) state which maps to index 0
88 * Non-zero states map to their bit position + 1
89 *
90 * @param stateRgt The right state (may be 0, otherwise power of 2).
91 *
92 * @return The index (0 for undefined, bit position + 1 otherwise).
93 */
94 [[nodiscard]] static constexpr size_t indexOf(const RState stateRgt) {
95
96 if (std::to_underlying(stateRgt) != 0 ) {
97 assert((std::to_underlying(stateRgt) & (std::to_underlying(stateRgt) -1)) == 0 && "RState must be a power of 2");
98 // undefined should map to 0, so 1 << 0 (bit count = 0) must map to 1
99 // (countr_zero counts the number of zeroes beginning at the lsb)
100 return std::countr_zero(std::to_underlying(stateRgt)) + 1;
101 }
102
103 return 0;
104 }
105
106 public:
107
108 /**
109 * @brief Adds an ID for a specific state combination.
110 *
111 * @param stateLft The left state (must be non-zero).
112 * @param stateRgt The right state (may be 0 for fallback).
113 * @param id The ID to associate with this combination.
114 *
115 * @return Reference to this map for chaining.
116 */
117 CombinedStateToIdMapPair& add(const LState stateLft, const RState stateRgt, const TId id) noexcept {
118
119 assert(!frozen_ && "Cannot add to a frozen map");
120
121 if (frozen_) {
122 return *this;
123 }
124
125 const auto stL = indexOf(stateLft);
126 const auto stR = indexOf(stateRgt);
127
128 if (states_.size() <= stL) {
129 states_.resize(stL + 1);
130 }
131 if (states_[stL].size() <= stR) {
132 states_[stL].resize(stR + 1);
133 }
134
135 states_[stL][stR].push_back(id);
136
137 return *this;
138 }
139
140 /**
141 * @brief Sorts and deduplicates all ID lists.
142 */
143 void finalize() {
144 for (auto& statesL : states_) {
145 for (auto& statesR : statesL) {
146 std::sort(statesR.begin(), statesR.end());
147 auto [first, last] = std::ranges::unique(statesR);
148 statesR.erase(first, last);
149 }
150 }
151 }
152
153 /**
154 * @brief Finalizes and prevents further modifications.
155 */
156 void freeze() {
157 finalize();
158 frozen_ = true;
159 }
160
161 /**
162 * @brief Checks if the map is frozen.
163 *
164 * @return True if frozen.
165 */
166 [[nodiscard]] bool isFrozen() const noexcept {
167 return frozen_;
168 }
169
170 /**
171 * @brief Returns IDs for a state combination.
172 *
173 * @details If the specific combination has no IDs, falls back to
174 * the IDs registered for the left state with undefined right state.
175 *
176 * @param stateLft The left state to query.
177 * @param stateRgt The right state to query.
178 *
179 * @return Span of IDs for the state combination.
180 */
181 [[nodiscard]] std::span<const TId> ids(const LState stateLft, const RState stateRgt) const noexcept {
182
183 assert(frozen_ && "Cannot return from a non-frozen map");
184
185 const auto stL = indexOf(stateLft);
186 const auto stR = indexOf(stateRgt);
187
188 if (states_.size() <= stL) {
189 return empty_;
190 }
191
192 if (states_[stL].size() <= stR || states_[stL][stR].empty()) {
193 if (!states_[stL].empty()) {
194 return states_[stL][0];
195 }
196 return empty_;
197 }
198
199 return states_[stL][stR];
200 }
201
202 };
203
204
205}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.