123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- #ifndef __SPFSM_H
- #define __SPFSM_H
- #pragma once
- #include "SpBase.h"
- #include "ListEntry.h"
- #ifndef PARAM_SIZE_DEFINED
- #define PARAM_SIZE_DEFINED
- #ifdef _WIN32
- typedef int param_size_t;
- #else
- #if (defined(__x86_64__) || defined(__aarch64__))
- typedef intptr_t param_size_t;
- #elif defined(__i386__)
- typedef int param_size_t;
- #else
- typedef intptr_t param_size_t;
- #endif
- #endif //_WIN32
- #endif // !PARAM_SIZE_DEFINED
- /** finite state machine */
- enum FSMEventEnum
- {
- EVT_INTERNAL, // internal usage
- EVT_TIMER, // timer evt
- EVT_MAINPAGE_DISPLAY, //the business main page display
- EVT_USER, // use defin Event must from here
- };
- #define FSM_STATE_INIT -1 // the initial state of the FSM
- #define FSM_STATE_EXIT -2 // the exit state of the FSM
- #define FSM_STATE_ERROR -3 // the error state of the FSM
- struct FSMEvent
- {
- int iEvt;
- param_size_t param1;
- param_size_t param2;
-
- FSMEvent(int evt)
- : m_ref_cnt(1)
- , iEvt(evt)
- ,param1(-1) /** NOTICES!! maybe make some noise for real online FSM [5/26/2020 Gifur] */
- ,param2(-1) /** NOTICES!! maybe make some noise for real online FSM [5/26/2020 Gifur] */
- , m_bHandled(FALSE)
- {
- m_entry.Flink = m_entry.Blink = &m_entry;
- }
-
- virtual ~FSMEvent() {}
- void IncRef() { InterlockedIncrement(&m_ref_cnt); }
- void DecRef() { if (0 == InterlockedDecrement(&m_ref_cnt)) {delete this;} }
-
- void SetHandled(BOOL bHandled = TRUE) { m_bHandled = bHandled; }
- BOOL IsHandled() { return m_bHandled; }
- virtual void OnUnhandled() {}
- private:
- BOOL m_bHandled;
- LONG m_ref_cnt;
- LIST_ENTRY m_entry;
- friend class FSMBase;
- };
- template<class T>
- struct FSMStateEntryT
- {
- int id;
- const char *pszName;
- void *pUserData;
- void (T::*pOnEntry)();
- void (T::*pOnExit)();
- unsigned int (T::*pOnEvent)(FSMEvent *e);
- };
- struct FSMRuleEntry
- {
- int src_state;
- int dst_state;
- int evt;
- unsigned int result_start;
- unsigned int result_end;
- };
- struct IFSMStateHooker
- {
- virtual void OnStateTrans(int iSrcState, int iDstState)=0;
- };
- class SPBASE_API FSMBase
- {
- public:
- FSMBase();
- virtual ~FSMBase();
- ErrorCodeEnum Init(CEntityBase *pEntity); // try start the state machine
- ErrorCodeEnum PostExitEvent(); // active close FSM, force it into FSM_STATE_EXIT, so OnExit() could be called
- CEntityBase *GetEntityBase() { return m_pEntity; }
- void PostEventLIFO(FSMEvent *e);
- void PostEventFIFO(FSMEvent *e);
- ErrorCodeEnum ScheduleTimer(int iTimerId, unsigned int timeout); // iTimerId user define, one shot timer
- ErrorCodeEnum CancelTimer(int iTimerId);
- void AddStateHooker(IFSMStateHooker *pHooker);
- void RemoveStateHooker(IFSMStateHooker *pHooker);
- virtual int GetInitState() = 0;
- virtual ErrorCodeEnum OnInit() { return Error_Succeed; }
- virtual ErrorCodeEnum OnExit() { return Error_Succeed; }
- virtual void OnStateEntry(int state)=0;
- virtual void OnStateExit(int state)=0;
- virtual unsigned int OnStateEvent(FSMEvent *e)=0;
- virtual int MatchRule(int state, int evt, unsigned int rc)=0;
- virtual BOOL FindStateEvent(int evt)=0;
- protected:
- const bool InNotInitState() const
- {
- return (m_iState == FSM_STATE_INIT || m_iState == FSM_STATE_EXIT || m_iState == FSM_STATE_ERROR);
- }
- private:
- void Trans(int next);
- #ifdef _WIN32
- #if (!defined(SPABASE_LINKED_AS_STATIC_LIBRARY) && !defined(SPBASE_EXPORTS))
- private:
- #else
- public:
- #endif
- #else
- public:
- #endif //_WIN32
- void __ProcessEvent(FSMEvent *e);
- protected:
- virtual void __PostInit() { }
- protected:
- int m_iState;
- CEntityBase *m_pEntity;
- private:
- void OnHook(int iSrcState, int iDstState);
- enum {MAX_HOOKER = 32};
- IFSMStateHooker *m_arrHookers[MAX_HOOKER];
- int m_iHookerCnt;
- void *m_strand; // make sure FSM event execute at one thread!!!
- LIST_ENTRY m_timerlist;
- LIST_ENTRY m_eventlist;
- LONG m_lInTrans;
- };
- template<class T>
- class FSMImpl : public FSMBase
- {
- public:
- virtual void OnStateEntry(int state)
- {
- T *pT = static_cast<T*>(this);
- #ifdef _WIN32
- T::FSMStateEntry* entry = pT->GetState(state);
- #else
- auto entry = pT->GetState(state);
- #endif //_WIN32
- if (entry->pOnEntry) {
- (pT->*(entry->pOnEntry))();
- }
- }
- virtual void OnStateExit(int state)
- {
- T *pT = static_cast<T*>(this);
- #ifdef _WIN32
- T::FSMStateEntry* entry = pT->GetState(state);
- #else
- auto entry = pT->GetState(state);
- #endif //_WIN32
- if (entry->pOnExit) {
- (pT->*(entry->pOnExit))();
- }
- }
- virtual unsigned int OnStateEvent(FSMEvent *e)
- {
- T *pT = static_cast<T*>(this);
- #ifdef _WIN32
- T::FSMStateEntry* entry = pT->GetCurrState();
- #else
- auto entry = pT->GetCurrState();
- #endif //_WIN32
- return (pT->*(entry->pOnEvent))(e);
- }
- virtual int MatchRule(int state, int evt, unsigned int rc)
- {
- T *pT = static_cast<T*>(this);
- int n = pT->GetRuleCount();
- for (int i = 0; i < n; ++i) {
- FSMRuleEntry *entry = pT->GetRule(i);
- if (state == entry->src_state) {
- if (evt == entry->evt) {
- if (rc >= entry->result_start && rc <= entry->result_end)
- return entry->dst_state;
- }
- }
- }
- return state; // no match
- }
- virtual BOOL FindStateEvent(int evt)
- {
- T *pT = static_cast<T*>(this);
- int n = pT->GetRuleCount();
- for (int i = 0; i < n; ++i) {
- FSMRuleEntry *entry = pT->GetRule(i);
- if (entry->src_state == m_iState && entry->evt == evt)
- return TRUE;
- }
- return FALSE;
- }
- const char *GetStateName(int iState)
- {
- if (iState == FSM_STATE_INIT) {
- return "State_Start";
- } else if (iState == FSM_STATE_EXIT) {
- return "State_End";
- } else if (iState == FSM_STATE_ERROR) {
- return "State_Error";
- }
- else {
- T *pT = static_cast<T*>(this);
- #ifdef _WIN32
- T::FSMStateEntry* entry = pT->GetState(iState);
- #else
- auto entry = pT->GetState(iState);
- #endif //_WIN32
- return entry ? entry->pszName : NULL;
- }
- }
- const char *GetCurrStateName()
- {
- return GetStateName(m_iState);
- }
- };
- #define BEGIN_FSM_STATE(cls) \
- public: \
- typedef FSMStateEntryT<cls> FSMStateEntry; \
- typedef cls FSM; \
- private: \
- FSMStateEntry *__EntryTable(int *iNum) { \
- static FSMStateEntry tables[] = {
- #define FSM_STATE_ENTRY(id, name, onentry, onexit, onevent) \
- {id, name, NULL, &FSM::onentry, &FSM::onexit, &FSM::onevent},
- #define END_FSM_STATE() \
- }; \
- static int sorted = 0; \
- if (!sorted) { \
- int n = sizeof(tables)/sizeof(tables[0]); \
- for (int i = 0; i < n-1; ++i) { \
- FSMStateEntry *t = &tables[i]; \
- if (t->id != i) { \
- int j; \
- for (j = i+1; j < n; ++j) { \
- FSMStateEntry *tt = &tables[j]; \
- if (tt->id == i) \
- break; \
- } \
- assert(j < n); \
- FSMStateEntry tentry; \
- memcpy(&tentry, t, sizeof(FSMStateEntry)); \
- memcpy(t, &tables[j], sizeof(FSMStateEntry)); \
- memcpy(&tables[j], &tentry, sizeof(FSMStateEntry)); \
- } \
- } \
- sorted++; \
- } \
- if (iNum) \
- *iNum = sizeof(tables)/sizeof(tables[0]); \
- return &tables[0]; \
- } \
- public: \
- FSMStateEntry *GetCurrState() \
- { \
- return GetState(m_iState); \
- } \
- FSMStateEntry *GetState(int iState) \
- { \
- int num; \
- FSMStateEntry *t = __EntryTable(&num); \
- assert(iState < num); \
- return t + iState; \
- } \
- int GetStateCount() \
- { \
- int num; \
- __EntryTable(&num); \
- return num; \
- }
- #define BEGIN_FSM_RULE(cls, init_state_id) \
- public: \
- virtual int GetInitState() { return init_state_id; } \
- private: \
- FSMRuleEntry *__RuleTable(int *iNum) { \
- static struct FSMRuleEntry table[] = {
- #define FSM_RULE_ENTRY(src_state_id, dst_state_id, evt_id, action_result) \
- {src_state_id, dst_state_id, evt_id, action_result, action_result},
- #define FSM_RULE_ENTRY_RANGE(src_state_id, dst_state_id, evt_id, action_result_start, action_result_end) \
- {src_state_id, dst_state_id, evt_id, action_result_start, action_result_end},
- #define FSM_RULE_ENTRY_ANY(src_state_id, dst_state_id, evt_id) \
- {src_state_id, dst_state_id, evt_id, 0, (unsigned int)-1},
- #define END_FSM_RULE() \
- }; \
- if (iNum) \
- *iNum = sizeof(table)/sizeof(table[0]); \
- return &table[0]; \
- } \
- public: \
- FSMRuleEntry * GetRule(int iRule) \
- { \
- int num; \
- FSMRuleEntry *t = __RuleTable(&num); \
- assert(iRule < num); \
- return t + iRule; \
- } \
- int GetRuleCount() \
- { \
- int num; \
- __RuleTable(&num); \
- return num; \
- }
- #endif // __SPFSM_H
|