SpFSM.h 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. #ifndef __SPFSM_H
  2. #define __SPFSM_H
  3. #pragma once
  4. #include "SpBase.h"
  5. #include "ListEntry.h"
  6. #ifndef PARAM_SIZE_DEFINED
  7. #define PARAM_SIZE_DEFINED
  8. #ifdef _WIN32
  9. typedef int param_size_t;
  10. #else
  11. #if (defined(__x86_64__) || defined(__aarch64__))
  12. typedef intptr_t param_size_t;
  13. #elif defined(__i386__)
  14. typedef int param_size_t;
  15. #else
  16. typedef intptr_t param_size_t;
  17. #endif
  18. #endif //_WIN32
  19. #endif // !PARAM_SIZE_DEFINED
  20. /** finite state machine */
  21. enum FSMEventEnum
  22. {
  23. EVT_INTERNAL, // internal usage
  24. EVT_TIMER, // timer evt
  25. EVT_USER, // use defin Event must from here
  26. };
  27. #define FSM_STATE_INIT -1 // the initial state of the FSM
  28. #define FSM_STATE_EXIT -2 // the exit state of the FSM
  29. struct FSMEvent
  30. {
  31. int iEvt;
  32. param_size_t param1;
  33. param_size_t param2;
  34. FSMEvent(int evt)
  35. : m_ref_cnt(1)
  36. , iEvt(evt)
  37. ,param1(-1) /** NOTICES!! maybe make some noise for real online FSM [5/26/2020 Gifur] */
  38. ,param2(-1) /** NOTICES!! maybe make some noise for real online FSM [5/26/2020 Gifur] */
  39. , m_bHandled(FALSE)
  40. {
  41. m_entry.Flink = m_entry.Blink = &m_entry;
  42. }
  43. virtual ~FSMEvent() {}
  44. void IncRef() { InterlockedIncrement(&m_ref_cnt); }
  45. void DecRef() { if (0 == InterlockedDecrement(&m_ref_cnt)) {delete this;} }
  46. void SetHandled(BOOL bHandled = TRUE) { m_bHandled = bHandled; }
  47. BOOL IsHandled() { return m_bHandled; }
  48. virtual void OnUnhandled() {}
  49. private:
  50. BOOL m_bHandled;
  51. LONG m_ref_cnt;
  52. LIST_ENTRY m_entry;
  53. friend class FSMBase;
  54. };
  55. template<class T>
  56. struct FSMStateEntryT
  57. {
  58. int id;
  59. const char *pszName;
  60. void *pUserData;
  61. void (T::*pOnEntry)();
  62. void (T::*pOnExit)();
  63. unsigned int (T::*pOnEvent)(FSMEvent *e);
  64. };
  65. struct FSMRuleEntry
  66. {
  67. int src_state;
  68. int dst_state;
  69. int evt;
  70. unsigned int result_start;
  71. unsigned int result_end;
  72. };
  73. struct IFSMStateHooker
  74. {
  75. virtual void OnStateTrans(int iSrcState, int iDstState)=0;
  76. };
  77. class SPBASE_API FSMBase
  78. {
  79. public:
  80. FSMBase();
  81. virtual ~FSMBase();
  82. ErrorCodeEnum Init(CEntityBase *pEntity); // try start the state machine
  83. ErrorCodeEnum PostExitEvent(); // active close FSM, force it into FSM_STATE_EXIT, so OnExit() could be called
  84. CEntityBase *GetEntityBase() { return m_pEntity; }
  85. void PostEventLIFO(FSMEvent *e);
  86. void PostEventFIFO(FSMEvent *e);
  87. ErrorCodeEnum ScheduleTimer(int iTimerId, unsigned int timeout); // iTimerId user define, one shot timer
  88. ErrorCodeEnum CancelTimer(int iTimerId);
  89. void AddStateHooker(IFSMStateHooker *pHooker);
  90. void RemoveStateHooker(IFSMStateHooker *pHooker);
  91. virtual int GetInitState() = 0;
  92. virtual ErrorCodeEnum OnInit() { return Error_Succeed; }
  93. virtual ErrorCodeEnum OnExit() { return Error_Succeed; }
  94. virtual void OnStateEntry(int state)=0;
  95. virtual void OnStateExit(int state)=0;
  96. virtual unsigned int OnStateEvent(FSMEvent *e)=0;
  97. virtual int MatchRule(int state, int evt, unsigned int rc)=0;
  98. virtual BOOL FindStateEvent(int evt)=0;
  99. private:
  100. void Trans(int next);
  101. #ifdef _WIN32
  102. #if (!defined(SPABASE_LINKED_AS_STATIC_LIBRARY) && !defined(SPBASE_EXPORTS))
  103. private:
  104. #else
  105. public:
  106. #endif
  107. #else
  108. public:
  109. #endif //_WIN32
  110. void __ProcessEvent(FSMEvent *e);
  111. protected:
  112. int m_iState;
  113. CEntityBase *m_pEntity;
  114. private:
  115. void OnHook(int iSrcState, int iDstState);
  116. enum {MAX_HOOKER = 32};
  117. IFSMStateHooker *m_arrHookers[MAX_HOOKER];
  118. int m_iHookerCnt;
  119. void *m_strand; // make sure FSM event execute at one thread!!!
  120. LIST_ENTRY m_timerlist;
  121. LIST_ENTRY m_eventlist;
  122. LONG m_lInTrans;
  123. };
  124. template<class T>
  125. class FSMImpl : public FSMBase
  126. {
  127. public:
  128. virtual void OnStateEntry(int state)
  129. {
  130. T *pT = static_cast<T*>(this);
  131. #ifdef _WIN32
  132. T::FSMStateEntry* entry = pT->GetState(state);
  133. #else
  134. auto entry = pT->GetState(state);
  135. #endif //_WIN32
  136. if (entry->pOnEntry) {
  137. (pT->*(entry->pOnEntry))();
  138. }
  139. }
  140. virtual void OnStateExit(int state)
  141. {
  142. T *pT = static_cast<T*>(this);
  143. #ifdef _WIN32
  144. T::FSMStateEntry* entry = pT->GetState(state);
  145. #else
  146. auto entry = pT->GetState(state);
  147. #endif //_WIN32
  148. if (entry->pOnExit) {
  149. (pT->*(entry->pOnExit))();
  150. }
  151. }
  152. virtual unsigned int OnStateEvent(FSMEvent *e)
  153. {
  154. T *pT = static_cast<T*>(this);
  155. #ifdef _WIN32
  156. T::FSMStateEntry* entry = pT->GetCurrState();
  157. #else
  158. auto entry = pT->GetCurrState();
  159. #endif //_WIN32
  160. return (pT->*(entry->pOnEvent))(e);
  161. }
  162. virtual int MatchRule(int state, int evt, unsigned int rc)
  163. {
  164. T *pT = static_cast<T*>(this);
  165. int n = pT->GetRuleCount();
  166. for (int i = 0; i < n; ++i) {
  167. FSMRuleEntry *entry = pT->GetRule(i);
  168. if (state == entry->src_state) {
  169. if (evt == entry->evt) {
  170. if (rc >= entry->result_start && rc <= entry->result_end)
  171. return entry->dst_state;
  172. }
  173. }
  174. }
  175. return state; // no match
  176. }
  177. virtual BOOL FindStateEvent(int evt)
  178. {
  179. T *pT = static_cast<T*>(this);
  180. int n = pT->GetRuleCount();
  181. for (int i = 0; i < n; ++i) {
  182. FSMRuleEntry *entry = pT->GetRule(i);
  183. if (entry->src_state == m_iState && entry->evt == evt)
  184. return TRUE;
  185. }
  186. return FALSE;
  187. }
  188. const char *GetStateName(int iState)
  189. {
  190. if (iState == FSM_STATE_INIT) {
  191. return "State_Start";
  192. } else if (iState == FSM_STATE_EXIT) {
  193. return "State_End";
  194. } else {
  195. T *pT = static_cast<T*>(this);
  196. #ifdef _WIN32
  197. T::FSMStateEntry* entry = pT->GetState(iState);
  198. #else
  199. auto entry = pT->GetState(iState);
  200. #endif //_WIN32
  201. return entry ? entry->pszName : NULL;
  202. }
  203. }
  204. const char *GetCurrStateName()
  205. {
  206. return GetStateName(m_iState);
  207. }
  208. };
  209. #define BEGIN_FSM_STATE(cls) \
  210. public: \
  211. typedef FSMStateEntryT<cls> FSMStateEntry; \
  212. typedef cls FSM; \
  213. private: \
  214. FSMStateEntry *__EntryTable(int *iNum) { \
  215. static FSMStateEntry tables[] = {
  216. #define FSM_STATE_ENTRY(id, name, onentry, onexit, onevent) \
  217. {id, name, NULL, &FSM::onentry, &FSM::onexit, &FSM::onevent},
  218. #define END_FSM_STATE() \
  219. }; \
  220. static int sorted = 0; \
  221. if (!sorted) { \
  222. int n = sizeof(tables)/sizeof(tables[0]); \
  223. for (int i = 0; i < n-1; ++i) { \
  224. FSMStateEntry *t = &tables[i]; \
  225. if (t->id != i) { \
  226. int j; \
  227. for (j = i+1; j < n; ++j) { \
  228. FSMStateEntry *tt = &tables[j]; \
  229. if (tt->id == i) \
  230. break; \
  231. } \
  232. assert(j < n); \
  233. FSMStateEntry tentry; \
  234. memcpy(&tentry, t, sizeof(FSMStateEntry)); \
  235. memcpy(t, &tables[j], sizeof(FSMStateEntry)); \
  236. memcpy(&tables[j], &tentry, sizeof(FSMStateEntry)); \
  237. } \
  238. } \
  239. sorted++; \
  240. } \
  241. if (iNum) \
  242. *iNum = sizeof(tables)/sizeof(tables[0]); \
  243. return &tables[0]; \
  244. } \
  245. public: \
  246. FSMStateEntry *GetCurrState() \
  247. { \
  248. return GetState(m_iState); \
  249. } \
  250. FSMStateEntry *GetState(int iState) \
  251. { \
  252. int num; \
  253. FSMStateEntry *t = __EntryTable(&num); \
  254. assert(iState < num); \
  255. return t + iState; \
  256. } \
  257. int GetStateCount() \
  258. { \
  259. int num; \
  260. __EntryTable(&num); \
  261. return num; \
  262. }
  263. #define BEGIN_FSM_RULE(cls, init_state_id) \
  264. public: \
  265. virtual int GetInitState() { return init_state_id; } \
  266. private: \
  267. FSMRuleEntry *__RuleTable(int *iNum) { \
  268. static struct FSMRuleEntry table[] = {
  269. #define FSM_RULE_ENTRY(src_state_id, dst_state_id, evt_id, action_result) \
  270. {src_state_id, dst_state_id, evt_id, action_result, action_result},
  271. #define FSM_RULE_ENTRY_RANGE(src_state_id, dst_state_id, evt_id, action_result_start, action_result_end) \
  272. {src_state_id, dst_state_id, evt_id, action_result_start, action_result_end},
  273. #define FSM_RULE_ENTRY_ANY(src_state_id, dst_state_id, evt_id) \
  274. {src_state_id, dst_state_id, evt_id, 0, (unsigned int)-1},
  275. #define END_FSM_RULE() \
  276. }; \
  277. if (iNum) \
  278. *iNum = sizeof(table)/sizeof(table[0]); \
  279. return &table[0]; \
  280. } \
  281. public: \
  282. FSMRuleEntry * GetRule(int iRule) \
  283. { \
  284. int num; \
  285. FSMRuleEntry *t = __RuleTable(&num); \
  286. assert(iRule < num); \
  287. return t + iRule; \
  288. } \
  289. int GetRuleCount() \
  290. { \
  291. int num; \
  292. __RuleTable(&num); \
  293. return num; \
  294. }
  295. #endif // __SPFSM_H