You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
2.2KB

  1. #if!defined FINITESTATEMACHINE_HPP
  2. #define FINITESTATEMACHINE_HPP
  3. #include <map>
  4. #include <queue>
  5. #include <stack>
  6. #include <string>
  7. #include <functional>
  8. #include <memory>
  9. template <class K, class ... A>
  10. class FiniteStateMachine
  11. {
  12. public:
  13. class AState
  14. {
  15. protected:
  16. explicit AState(std::string&& name) :
  17. m_stateName(name)
  18. {
  19. }
  20. public:
  21. virtual ~AState() = default;
  22. std::string const& getName()const
  23. {
  24. return m_stateName;
  25. }
  26. virtual void beginState() = 0;
  27. virtual void stepState() = 0;
  28. virtual void endState() = 0;
  29. private:
  30. std::string const m_stateName;
  31. };
  32. using StatePointer = std::unique_ptr<AState>;
  33. using StateCreator = std::function<StatePointer(A&& ...)>;
  34. void registerStateCreator(K const& key, StateCreator&& creator);
  35. template <class State>
  36. void registerStateType(K const& key);
  37. AState& currentState()const;
  38. K const& currentStateKey()const;
  39. bool hasState()const;
  40. void push(K const& key, A&& ... args);
  41. void change(K const& key, A&& ... args);
  42. void pop();
  43. void clear();
  44. /*! Should be called at each step. */
  45. void step();
  46. private:
  47. using Event = std::function<void()>;
  48. struct StateHolder
  49. {
  50. StateHolder(StatePointer&& state, K const& key) :
  51. state(std::move(state)),
  52. key(key)
  53. {
  54. }
  55. StatePointer state;
  56. K const& key;
  57. };
  58. StatePointer createState(K const& key, A&& ... args);
  59. void processEvents();
  60. void pushEvent(Event&& event);
  61. void pushImp(K const& key, A&& ...args)
  62. {
  63. auto const creator = createState(key, std::forward<A>(args)...);
  64. auto state = createState(key, std::forward<A>(args)...);
  65. m_stack.emplace(std::move(state), key);
  66. m_stack.top().state->beginState();
  67. }
  68. void changeImp(K const& key, A&& ...args)
  69. {
  70. auto const creator = createState(key, std::forward<A>(args)...);
  71. auto state = createState(key, std::forward<A>(args)...);
  72. popImp();
  73. m_stack.emplace(std::move(state), key);
  74. m_stack.top().state->beginState();
  75. }
  76. void popImp()
  77. {
  78. if (!m_stack.empty())
  79. {
  80. m_stack.top().state->endState();
  81. m_stack.pop();
  82. }
  83. }
  84. void clearImp()
  85. {
  86. while (!m_stack.empty())
  87. {
  88. popImp();
  89. }
  90. }
  91. private:
  92. std::map<K, StateCreator> m_creators;
  93. std::stack<StateHolder> m_stack;
  94. std::queue<Event> m_eventQueue;
  95. };
  96. #include "FiniteStateMachine.hxx"
  97. #endif