SimpleTutorialWithEumlTableTypeErasure.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include <iostream>
  2. // back-end
  3. #include <boost/msm/back/state_machine.hpp>
  4. //front-end
  5. #include <boost/msm/front/state_machine_def.hpp>
  6. #include <boost/msm/front/euml/euml.hpp>
  7. #include <boost/msm/event_traits.hpp>
  8. #include <boost/type_erasure/any.hpp>
  9. #include <boost/type_erasure/member.hpp>
  10. #include <boost/type_erasure/builtin.hpp>
  11. #include <boost/type_erasure/constructible.hpp>
  12. #include <boost/type_erasure/relaxed_match.hpp>
  13. #include <boost/type_erasure/any_cast.hpp>
  14. namespace msm = boost::msm;
  15. namespace mpl = boost::mpl;
  16. using namespace std;
  17. using namespace msm::front::euml;
  18. // entry/exit/action/guard logging functors
  19. #include "logging_functors.h"
  20. BOOST_TYPE_ERASURE_MEMBER((has_getNumber), getNumber, 0);
  21. //type erasure event
  22. typedef ::boost::mpl::vector<
  23. has_getNumber<int(), const boost::type_erasure::_self>,
  24. boost::type_erasure::relaxed_match,
  25. boost::type_erasure::copy_constructible<>,
  26. boost::type_erasure::typeid_<>
  27. > any_number_event_concept;
  28. struct any_number_event : boost::type_erasure::any<any_number_event_concept>,
  29. msm::front::euml::euml_event<any_number_event>
  30. {
  31. template <class U>
  32. any_number_event(U const& u): boost::type_erasure::any<any_number_event_concept> (u){}
  33. any_number_event(): boost::type_erasure::any<any_number_event_concept> (){}
  34. };
  35. namespace boost { namespace msm{
  36. template<>
  37. struct is_kleene_event< any_number_event >
  38. {
  39. typedef boost::mpl::true_ type;
  40. };
  41. }}
  42. namespace
  43. {
  44. // events
  45. struct play_impl : msm::front::euml::euml_event<play_impl> {int getNumber()const {return 0;}};
  46. struct end_pause_impl : msm::front::euml::euml_event<end_pause_impl>{int getNumber()const {return 1;}};
  47. struct stop_impl : msm::front::euml::euml_event<stop_impl>{int getNumber()const {return 2;}};
  48. struct pause_impl : msm::front::euml::euml_event<pause_impl>{int getNumber()const {return 3;}};
  49. struct open_close_impl : msm::front::euml::euml_event<open_close_impl>{int getNumber()const {return 4;}};
  50. struct cd_detected_impl : msm::front::euml::euml_event<cd_detected_impl>{int getNumber()const {return 5;}};
  51. // define some dummy instances for use in the transition table
  52. // it is also possible to default-construct them instead:
  53. // struct play {};
  54. // inside the table: play()
  55. play_impl play;
  56. end_pause_impl end_pause;
  57. stop_impl stop;
  58. pause_impl pause;
  59. open_close_impl open_close;
  60. cd_detected_impl cd_detected;
  61. any_number_event number_event;
  62. // The list of FSM states
  63. // they have to be declared outside of the front-end only to make VC happy :(
  64. // note: gcc would have no problem
  65. struct Empty_impl : public msm::front::state<> , public msm::front::euml::euml_state<Empty_impl>
  66. {
  67. // every (optional) entry/exit methods get the event passed.
  68. template <class Event,class FSM>
  69. void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
  70. template <class Event,class FSM>
  71. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
  72. };
  73. struct Open_impl : public msm::front::state<> , public msm::front::euml::euml_state<Open_impl>
  74. {
  75. template <class Event,class FSM>
  76. void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
  77. template <class Event,class FSM>
  78. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
  79. };
  80. struct Stopped_impl : public msm::front::state<> , public msm::front::euml::euml_state<Stopped_impl>
  81. {
  82. template <class Event,class FSM>
  83. void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
  84. template <class Event,class FSM>
  85. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
  86. };
  87. struct Playing_impl : public msm::front::state<> , public msm::front::euml::euml_state<Playing_impl>
  88. {
  89. template <class Event,class FSM>
  90. void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
  91. template <class Event,class FSM>
  92. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
  93. };
  94. // state not defining any entry or exit
  95. struct Paused_impl : public msm::front::state<> , public msm::front::euml::euml_state<Paused_impl>
  96. {
  97. };
  98. //to make the transition table more readable
  99. Empty_impl const Empty;
  100. Open_impl const Open;
  101. Stopped_impl const Stopped;
  102. Playing_impl const Playing;
  103. Paused_impl const Paused;
  104. BOOST_MSM_EUML_ACTION(pause_playback2)
  105. {
  106. template <class FSM,class EVT,class SourceState,class TargetState>
  107. void operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
  108. {
  109. cout << "player::pause_playback2" << endl;
  110. std::cout << "event type: " << typeid(EVT).name() << std::endl;
  111. std::cout << "event's number: " << evt.getNumber() << std::endl;
  112. }
  113. };
  114. // front-end: define the FSM structure
  115. struct player_ : public msm::front::state_machine_def<player_>
  116. {
  117. // the initial state of the player SM. Must be defined
  118. typedef Empty_impl initial_state;
  119. // Transition table for player
  120. // replaces the old transition table
  121. BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE((
  122. Stopped + play / start_playback == Playing ,
  123. Stopped + open_close / open_drawer == Open ,
  124. Stopped + stop == Stopped ,
  125. // +------------------------------------------------------------------------------+
  126. Open + open_close / close_drawer == Empty ,
  127. // +------------------------------------------------------------------------------+
  128. Empty + open_close / open_drawer == Open ,
  129. Empty + cd_detected /(store_cd_info,
  130. msm::front::euml::process_(play)) == Stopped ,
  131. // +------------------------------------------------------------------------------+
  132. Playing + stop / stop_playback == Stopped ,
  133. Playing + number_event / pause_playback == Paused ,
  134. Playing + open_close / stop_and_open == Open ,
  135. // +------------------------------------------------------------------------------+
  136. Paused + end_pause / resume_playback == Playing ,
  137. Paused + stop / stop_playback == Stopped ,
  138. Paused + open_close / stop_and_open == Open
  139. // +------------------------------------------------------------------------------+
  140. ),transition_table)
  141. // Replaces the default no-transition response.
  142. template <class FSM,class Event>
  143. void no_transition(Event const& e, FSM&,int state)
  144. {
  145. std::cout << "no transition from state " << state
  146. << " on event " << typeid(e).name() << std::endl;
  147. }
  148. };
  149. // Pick a back-end
  150. typedef msm::back::state_machine<player_> player;
  151. //
  152. // Testing utilities.
  153. //
  154. static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
  155. void pstate(player const& p)
  156. {
  157. std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
  158. }
  159. void test()
  160. {
  161. player p;
  162. // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
  163. p.start();
  164. // go to Open, call on_exit on Empty, then action, then on_entry on Open
  165. p.process_event(open_close); pstate(p);
  166. p.process_event(open_close); pstate(p);
  167. p.process_event(cd_detected); pstate(p);
  168. // at this point, Play is active
  169. p.process_event(pause); pstate(p);
  170. // go back to Playing
  171. p.process_event(end_pause); pstate(p);
  172. p.process_event(pause); pstate(p);
  173. p.process_event(stop); pstate(p);
  174. // event leading to the same state
  175. // no action method called as it is not present in the transition table
  176. p.process_event(stop); pstate(p);
  177. }
  178. }
  179. int main()
  180. {
  181. test();
  182. return 0;
  183. }