galaxy 1.0.0
Real-Time C++23 Game Programming Framework. Built on data-driven design principles and agile software engineering.
Loading...
Searching...
No Matches
StateMachine.hpp
Go to the documentation of this file.
1
7
8#ifndef GALAXY_STATE_STATEMACHINE_HPP_
9#define GALAXY_STATE_STATEMACHINE_HPP_
10
11#include <ankerl/unordered_dense.h>
12
13#include "galaxy/math/FNV1a.hpp"
16
17namespace galaxy
18{
26 template<std::derived_from<State> Stored>
28 {
32 using Stack = std::vector<std::shared_ptr<Stored>>;
33
37 using Map = ankerl::unordered_dense::map<std::uint64_t, std::shared_ptr<Stored>>;
38
39 public:
43 StateMachine() noexcept;
44
49
53 StateMachine<Stored>& operator=(StateMachine<Stored>&&);
54
58 virtual ~StateMachine();
59
71 template<typename Child = Stored, typename... Args>
72 [[maybe_unused]]
73 std::shared_ptr<Stored> add(const std::string& key, Args&&... args);
74
82 [[nodiscard]]
83 std::shared_ptr<Stored> get(const std::string& key) noexcept;
84
92 [[nodiscard]]
93 bool has(const std::string& key) noexcept;
94
102 void remove(const std::string& key);
103
109 void push(const std::string& key) noexcept;
110
114 void pop() noexcept;
115
119 void pop_all() noexcept;
120
126 [[nodiscard]]
127 std::shared_ptr<Stored> top() const noexcept;
128
134 [[nodiscard]]
135 Stack& stack() noexcept;
136
142 [[nodiscard]]
143 Map& storage() noexcept;
144
145 protected:
150
155
156 private:
160 StateMachine(const StateMachine<Stored>&) = delete;
161
165 StateMachine<Stored>& operator=(const StateMachine<Stored>&) = delete;
166 };
167
168 template<std::derived_from<State> Stored>
169 StateMachine<Stored>::StateMachine() noexcept
170 {
171 }
172
173 template<std::derived_from<State> Stored>
175 {
176 this->m_stack = std::move(sm.m_stack);
177 this->m_storage = std::move(sm.m_storage);
178 }
179
180 template<std::derived_from<State> Stored>
182 {
183 if (this != &sm)
184 {
185 this->m_stack = std::move(sm.m_stack);
186 this->m_storage = std::move(sm.m_storage);
187 }
188
189 return *this;
190 }
191
192 template<std::derived_from<State> Stored>
194 {
195 pop_all();
196
197 m_stack.clear();
198 m_storage.clear();
199 }
200
201 template<std::derived_from<State> Stored>
202 template<typename Child, typename... Args>
203 inline std::shared_ptr<Stored> StateMachine<Stored>::add(const std::string& key, Args&&... args)
204 {
205 const auto hash = math::fnv1a(key.c_str());
206
207 if (!m_storage.contains(hash))
208 {
209 m_storage[hash] = std::make_shared<Child>(key, std::forward<Args>(args)...);
210 return m_storage[hash];
211 }
212 else
213 {
214 GALAXY_LOG(GALAXY_WARN, "Tried to create a scene with a duplicate key of '{0}'.", key);
215 return nullptr;
216 }
217 }
218
219 template<std::derived_from<State> Stored>
220 inline std::shared_ptr<Stored> StateMachine<Stored>::get(const std::string& key) noexcept
221 {
222 const auto hash = math::fnv1a(key.c_str());
223
224 if (m_storage.contains(hash))
225 {
226 return m_storage[hash];
227 }
228 else
229 {
230 GALAXY_LOG(GALAXY_WARN, "State '{0}' does not exist.", key);
231 return nullptr;
232 }
233 }
234
235 template<std::derived_from<State> Stored>
236 inline bool StateMachine<Stored>::has(const std::string& key) noexcept
237 {
238 const auto hash = math::fnv1a(key.c_str());
239 return m_storage.contains(hash);
240 }
241
242 template<std::derived_from<State> Stored>
243 inline void StateMachine<Stored>::remove(const std::string& key)
244 {
245 for (auto&& state : m_stack)
246 {
247 if (state->name() == key)
248 {
249 GALAXY_LOG(GALAXY_WARN, "Cant remove an active state.");
250 return;
251 }
252 }
253
254 const auto hash = math::fnv1a(key.c_str());
255 m_storage.erase(hash);
256 }
257
258 template<std::derived_from<State> Stored>
259 inline void StateMachine<Stored>::push(const std::string& key) noexcept
260 {
261 if (auto state = get(key))
262 {
263 m_stack.push_back(state);
264 m_stack.back()->on_push();
265 }
266 else
267 {
268 GALAXY_LOG(GALAXY_WARN, "Tried to push non-existent scene '{0}'.", key);
269 }
270 }
271
272 template<std::derived_from<State> Stored>
273 inline void StateMachine<Stored>::pop() noexcept
274 {
275 if (auto state = top())
276 {
277 state->on_pop();
278 m_stack.pop_back();
279 }
280
281 if (m_stack.size() > 0)
282 {
283 m_stack.back()->on_pop();
284 }
285 }
286
287 template<std::derived_from<State> Stored>
288 inline void StateMachine<Stored>::pop_all() noexcept
289 {
290 while (!m_stack.empty())
291 {
292 pop();
293 }
294 }
295
296 template<std::derived_from<State> Stored>
297 inline std::shared_ptr<Stored> StateMachine<Stored>::top() const noexcept
298 {
299 if (!m_stack.empty())
300 {
301 return m_stack.back();
302 }
303
304 return nullptr;
305 }
306
307 template<std::derived_from<State> Stored>
309 {
310 return m_stack;
311 }
312
313 template<std::derived_from<State> Stored>
315 {
316 return m_storage;
317 }
318} // namespace galaxy
319
320#endif
#define GALAXY_LOG(level, msg,...)
Definition Log.hpp:29
#define GALAXY_WARN
Definition Log.hpp:24
A finite state machine.
Map & storage() noexcept
Get storage.
void pop() noexcept
Remove state on top of stack.
Map m_storage
State cache.
void remove(const std::string &key)
Remove a specific state.
virtual ~StateMachine()
Destructor.
void pop_all() noexcept
Remove all states in stack.
std::shared_ptr< Stored > add(const std::string &key, Args &&... args)
Add a new state.
ankerl::unordered_dense::map< std::uint64_t, std::shared_ptr< Stored > > Map
Use a dense map for storage.
bool has(const std::string &key) noexcept
Does a state exist.
StateMachine< Stored > & operator=(StateMachine< Stored > &&)
Move assignment operator.
StateMachine() noexcept
Constructor.
std::shared_ptr< Stored > get(const std::string &key) noexcept
Get a specific state.
std::vector< std::shared_ptr< Stored > > Stack
We specifically use a std::vector for our stack.
void push(const std::string &key) noexcept
Push a state onto the top of stack.
Stack m_stack
State stack.
Stack & stack() noexcept
Get stack.
std::shared_ptr< Stored > top() const noexcept
Get top state in stack.
A state to use in a finite state machine.
Definition State.hpp:19
constexpr bits fnv1a(const char *const str, const bits value=fnv_1a_params< bits >::offset) noexcept
Convert string to hash.
Definition FNV1a.hpp:64
Application.hpp galaxy.
STL namespace.