SpFSM.h 7.6 KB

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