Split the FSM-transitions and put them in an unordered_map
[0ad.git] / source / network / FSM.h
blobf27d3d6a1b7b491b0a78fc205ec57be4f5aa52a4
1 /* Copyright (C) 2024 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
18 #ifndef FSM_H
19 #define FSM_H
21 #include <limits>
22 #include <set>
23 #include <unordered_map>
26 constexpr unsigned int FSM_INVALID_STATE{std::numeric_limits<unsigned int>::max()};
28 class CFsmEvent;
29 class CFsm;
31 using Action = bool(void* pContext, CFsmEvent* pEvent);
33 struct CallbackFunction
35 Action* pFunction{nullptr};
36 void* pContext{nullptr};
38 bool operator()(CFsmEvent& event) const
40 return !pFunction || pFunction(pContext, &event);
44 using StateSet = std::set<unsigned int>;
46 /**
47 * Represents a signal in the state machine that a change has occurred.
48 * The CFsmEvent objects are under the control of CFsm so
49 * they are created and deleted via CFsm.
51 class CFsmEvent
53 NONCOPYABLE(CFsmEvent);
54 public:
56 CFsmEvent(unsigned int type, void* pParam);
57 ~CFsmEvent();
59 unsigned int GetType() const
61 return m_Type;
64 void* GetParamRef()
66 return m_Param;
69 private:
70 unsigned int m_Type; // Event type
71 void* m_Param; // Event paramater
74 /**
75 * Manages states, events, actions and transitions
76 * between states. It provides an interface for advertising
77 * events and track the current state. The implementation is
78 * a Mealy state machine, so the system respond to events
79 * and execute some action.
81 * A Mealy state machine has behaviour associated with state
82 * transitions; Mealy machines are event driven where an
83 * event triggers a state transition.
85 class CFsm
87 NONCOPYABLE(CFsm);
88 public:
90 CFsm();
91 virtual ~CFsm();
93 /**
94 * Constructs the state machine. This method must be overriden so that
95 * connections are constructed for the particular state machine implemented.
97 virtual void Setup();
99 /**
100 * Clear event, transition lists and reset state machine.
102 void Shutdown();
105 * Adds the specified state to the internal list of states.
106 * @note If a state with the specified ID exists, the state is not added.
108 void AddState(unsigned int state);
111 * Adds a new transistion to the state machine.
113 void AddTransition(unsigned int state, unsigned int eventType, unsigned int nextState,
114 Action* pAction = nullptr, void* pContext = nullptr);
117 * Sets the initial state for FSM.
119 void SetFirstState(unsigned int firstState);
122 * Sets the current state and update the last state to the current state.
124 void SetCurrState(unsigned int state);
125 unsigned int GetCurrState() const
127 return m_CurrState;
130 void SetNextState(unsigned int nextState)
132 m_NextState = nextState;
135 unsigned int GetNextState() const
137 return m_NextState;
140 const StateSet& GetStates() const
142 return m_States;
146 * Updates the FSM and retrieves next state.
147 * @return whether the state was changed.
149 bool Update(unsigned int eventType, void* pEventData);
152 * Verifies whether the specified state is managed by the FSM.
154 bool IsValidState(unsigned int state) const;
157 * Tests whether the state machine has finished its work.
158 * @note This is state machine specific.
160 virtual bool IsDone() const;
162 private:
163 struct TransitionKey
165 using UnderlyingType = unsigned int;
166 UnderlyingType state;
167 UnderlyingType eventType;
169 struct Hash
171 size_t operator()(const TransitionKey& key) const noexcept
173 static_assert(sizeof(UnderlyingType) <= sizeof(size_t) / 2);
174 return (static_cast<size_t>(key.state) <<
175 ((sizeof(size_t) / 2) * std::numeric_limits<unsigned char>::digits)) +
176 static_cast<size_t>(key.eventType);
180 friend bool operator==(const TransitionKey& lhs, const TransitionKey& rhs) noexcept
182 return lhs.state == rhs.state && lhs.eventType == rhs.eventType;
186 struct Transition
188 CallbackFunction action;
189 unsigned int nextState;
192 using TransitionMap = std::unordered_map<TransitionKey, const Transition, TransitionKey::Hash>;
195 * Verifies whether state machine has already been updated.
197 bool IsFirstTime() const;
199 bool m_Done;
200 unsigned int m_FirstState;
201 unsigned int m_CurrState;
202 unsigned int m_NextState;
203 StateSet m_States;
204 TransitionMap m_Transitions;
207 #endif // FSM_H