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
70 template<typename... Args>
71 [[maybe_unused]]
72 std::shared_ptr<Stored> add(const std::string& key, Args&&... args);
73
81 [[nodiscard]]
82 std::shared_ptr<Stored> get(const std::string& key) noexcept;
83
91 [[nodiscard]]
92 bool has(const std::string& key) noexcept;
93
101 void remove(const std::string& key);
102
108 void push(const std::string& key) noexcept;
109
113 void pop() noexcept;
114
118 void pop_all() noexcept;
119
125 [[nodiscard]]
126 std::shared_ptr<Stored> top() const noexcept;
127
131 virtual void update() = 0;
132
138 [[nodiscard]]
139 Stack& stack() noexcept;
140
146 [[nodiscard]]
147 Map& storage() noexcept;
148
149 protected:
154
159
160 private:
164 StateMachine(const StateMachine<Stored>&) = delete;
165
169 StateMachine<Stored>& operator=(const StateMachine<Stored>&) = delete;
170 };
171
172 template<std::derived_from<State> Stored>
173 StateMachine<Stored>::StateMachine() noexcept
174 {
175 }
176
177 template<std::derived_from<State> Stored>
179 {
180 this->m_stack = std::move(sm.m_stack);
181 this->m_storage = std::move(sm.m_storage);
182 }
183
184 template<std::derived_from<State> Stored>
186 {
187 if (this != &sm)
188 {
189 this->m_stack = std::move(sm.m_stack);
190 this->m_storage = std::move(sm.m_storage);
191 }
192
193 return *this;
194 }
195
196 template<std::derived_from<State> Stored>
198 {
199 pop_all();
200
201 m_stack.clear();
202 m_storage.clear();
203 }
204
205 template<std::derived_from<State> Stored>
206 template<typename... Args>
207 inline std::shared_ptr<Stored> StateMachine<Stored>::add(const std::string& key, Args&&... args)
208 {
209 const auto hash = math::fnv1a(key.c_str());
210
211 if (!m_storage.contains(hash))
212 {
213 m_storage[hash] = std::make_shared<Stored>(key, std::forward<Args>(args)...);
214 return m_storage[hash];
215 }
216 else
217 {
218 GALAXY_LOG(GALAXY_WARN, "Tried to create a scene with a duplicate key of '{0}'.", key);
219 return nullptr;
220 }
221 }
222
223 template<std::derived_from<State> Stored>
224 inline std::shared_ptr<Stored> StateMachine<Stored>::get(const std::string& key) noexcept
225 {
226 const auto hash = math::fnv1a(key.c_str());
227
228 if (m_storage.contains(hash))
229 {
230 return m_storage[hash];
231 }
232 else
233 {
234 GALAXY_LOG(GALAXY_WARN, "State '{0}' does not exist.", key);
235 return nullptr;
236 }
237 }
238
239 template<std::derived_from<State> Stored>
240 inline bool StateMachine<Stored>::has(const std::string& key) noexcept
241 {
242 const auto hash = math::fnv1a(key.c_str());
243 return m_storage.contains(hash);
244 }
245
246 template<std::derived_from<State> Stored>
247 inline void StateMachine<Stored>::remove(const std::string& key)
248 {
249 for (auto&& state : m_stack)
250 {
251 if (state->name() == key)
252 {
253 GALAXY_LOG(GALAXY_WARN, "Cant remove an active state.");
254 return;
255 }
256 }
257
258 const auto hash = math::fnv1a(key.c_str());
259 m_storage.erase(hash);
260 }
261
262 template<std::derived_from<State> Stored>
263 inline void StateMachine<Stored>::push(const std::string& key) noexcept
264 {
265 if (auto state = get(key))
266 {
267 m_stack.push_back(state);
268 m_stack.back()->on_push();
269 }
270 else
271 {
272 GALAXY_LOG(GALAXY_WARN, "Tried to push non-existent scene '{0}'.", key);
273 }
274 }
275
276 template<std::derived_from<State> Stored>
277 inline void StateMachine<Stored>::pop() noexcept
278 {
279 if (auto state = top())
280 {
281 state->on_pop();
282 m_stack.pop_back();
283 }
284
285 if (m_stack.size() > 0)
286 {
287 m_stack.back()->on_pop();
288 }
289 }
290
291 template<std::derived_from<State> Stored>
292 inline void StateMachine<Stored>::pop_all() noexcept
293 {
294 while (!m_stack.empty())
295 {
296 pop();
297 }
298 }
299
300 template<std::derived_from<State> Stored>
301 inline std::shared_ptr<Stored> StateMachine<Stored>::top() const noexcept
302 {
303 if (!m_stack.empty())
304 {
305 return m_stack.back();
306 }
307
308 return nullptr;
309 }
310
311 template<std::derived_from<State> Stored>
313 {
314 return m_stack;
315 }
316
317 template<std::derived_from<State> Stored>
319 {
320 return m_storage;
321 }
322} // namespace galaxy
323
324#endif
#define GALAXY_LOG(level, msg,...)
Definition Log.hpp:28
#define GALAXY_WARN
Definition Log.hpp:23
A finite state machine.
std::shared_ptr< Stored > add(const std::string &key, Args &&... args)
Add a new state.
Map & storage() noexcept
Get storage.
void pop() noexcept
Remove state on top of stack.
Map m_storage
State cache.
virtual void update()=0
Process events and updates.
void remove(const std::string &key)
Remove a specific state.
virtual ~StateMachine()
Destructor.
void pop_all() noexcept
Remove all states in stack.
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
Animated.cpp galaxy.
Definition Animated.cpp:16
STL namespace.