SpFSM.h 7.3 KB

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