SimpleTutorialInternalFunctors.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Copyright 2010 Christophe Henry
  2. // henry UNDERSCORE christophe AT hotmail DOT com
  3. // This is an extended version of the state machine available in the boost::mpl library
  4. // Distributed under the same license as the original.
  5. // Copyright for the original version:
  6. // Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
  7. // under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. #include <iostream>
  11. // back-end
  12. #include <boost/msm/back/state_machine.hpp>
  13. //front-end
  14. #include <boost/msm/front/state_machine_def.hpp>
  15. #include <boost/msm/front/functor_row.hpp>
  16. #include <boost/msm/front/euml/common.hpp>
  17. // for And_ operator
  18. #include <boost/msm/front/euml/operator.hpp>
  19. using namespace std;
  20. namespace msm = boost::msm;
  21. using namespace msm::front;
  22. namespace mpl = boost::mpl;
  23. // for And_ operator
  24. using namespace msm::front::euml;
  25. namespace
  26. {
  27. // events
  28. struct play {};
  29. struct end_pause {};
  30. struct stop {};
  31. struct pause {};
  32. struct open_close {};
  33. // A "complicated" event type that carries some data.
  34. enum DiskTypeEnum
  35. {
  36. DISK_CD=0,
  37. DISK_DVD=1
  38. };
  39. struct cd_detected
  40. {
  41. cd_detected(std::string name, DiskTypeEnum diskType)
  42. : name(name),
  43. disc_type(diskType)
  44. {}
  45. std::string name;
  46. DiskTypeEnum disc_type;
  47. };
  48. // front-end: define the FSM structure
  49. struct player_ : public msm::front::state_machine_def<player_>
  50. {
  51. // The list of FSM states
  52. struct Empty : public msm::front::state<>
  53. {
  54. // every (optional) entry/exit methods get the event passed.
  55. template <class Event,class FSM>
  56. void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
  57. template <class Event,class FSM>
  58. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
  59. struct internal_guard_fct
  60. {
  61. template <class EVT,class FSM,class SourceState,class TargetState>
  62. bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
  63. {
  64. std::cout << "Empty::internal_transition_table guard\n";
  65. return false;
  66. }
  67. };
  68. struct internal_action_fct
  69. {
  70. template <class EVT,class FSM,class SourceState,class TargetState>
  71. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  72. {
  73. std::cout << "Empty::internal_transition_table action" << std::endl;
  74. }
  75. };
  76. // Transition table for Empty
  77. struct internal_transition_table : mpl::vector<
  78. // Start Event Next Action Guard
  79. Internal < cd_detected , internal_action_fct ,internal_guard_fct >
  80. // +---------+-------------+---------+---------------------+----------------------+
  81. > {};
  82. };
  83. struct Open : public msm::front::state<>
  84. {
  85. template <class Event,class FSM>
  86. void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
  87. template <class Event,class FSM>
  88. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
  89. };
  90. struct Stopped : public msm::front::state<>
  91. {
  92. template <class Event,class FSM>
  93. void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
  94. template <class Event,class FSM>
  95. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
  96. };
  97. struct Playing : public msm::front::state<>
  98. {
  99. template <class Event,class FSM>
  100. void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
  101. template <class Event,class FSM>
  102. void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
  103. };
  104. // state not defining any entry or exit
  105. struct Paused : public msm::front::state<>
  106. {
  107. };
  108. // the initial state of the player SM. Must be defined
  109. typedef Empty initial_state;
  110. // transition actions
  111. // as the functors are generic on events, fsm and source/target state,
  112. // you can reuse them in another machine if you wish
  113. struct TestFct
  114. {
  115. template <class EVT,class FSM,class SourceState,class TargetState>
  116. void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
  117. {
  118. cout << "transition with event:" << typeid(EVT).name() << endl;
  119. }
  120. };
  121. struct start_playback
  122. {
  123. template <class EVT,class FSM,class SourceState,class TargetState>
  124. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  125. {
  126. cout << "player::start_playback" << endl;
  127. }
  128. };
  129. struct open_drawer
  130. {
  131. template <class EVT,class FSM,class SourceState,class TargetState>
  132. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  133. {
  134. cout << "player::open_drawer" << endl;
  135. }
  136. };
  137. struct close_drawer
  138. {
  139. template <class EVT,class FSM,class SourceState,class TargetState>
  140. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  141. {
  142. cout << "player::close_drawer" << endl;
  143. }
  144. };
  145. struct store_cd_info
  146. {
  147. template <class EVT,class FSM,class SourceState,class TargetState>
  148. void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
  149. {
  150. cout << "player::store_cd_info" << endl;
  151. fsm.process_event(play());
  152. }
  153. };
  154. struct stop_playback
  155. {
  156. template <class EVT,class FSM,class SourceState,class TargetState>
  157. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  158. {
  159. cout << "player::stop_playback" << endl;
  160. }
  161. };
  162. struct pause_playback
  163. {
  164. template <class EVT,class FSM,class SourceState,class TargetState>
  165. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  166. {
  167. cout << "player::pause_playback" << endl;
  168. }
  169. };
  170. struct resume_playback
  171. {
  172. template <class EVT,class FSM,class SourceState,class TargetState>
  173. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  174. {
  175. cout << "player::resume_playback" << endl;
  176. }
  177. };
  178. struct stop_and_open
  179. {
  180. template <class EVT,class FSM,class SourceState,class TargetState>
  181. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  182. {
  183. cout << "player::stop_and_open" << endl;
  184. }
  185. };
  186. struct stopped_again
  187. {
  188. template <class EVT,class FSM,class SourceState,class TargetState>
  189. void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
  190. {
  191. cout << "player::stopped_again" << endl;
  192. }
  193. };
  194. // guard conditions
  195. struct DummyGuard
  196. {
  197. template <class EVT,class FSM,class SourceState,class TargetState>
  198. bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
  199. {
  200. return true;
  201. }
  202. };
  203. struct good_disk_format
  204. {
  205. template <class EVT,class FSM,class SourceState,class TargetState>
  206. bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
  207. {
  208. // to test a guard condition, let's say we understand only CDs, not DVD
  209. if (evt.disc_type != DISK_CD)
  210. {
  211. std::cout << "wrong disk, sorry" << std::endl;
  212. return false;
  213. }
  214. return true;
  215. }
  216. };
  217. struct always_true
  218. {
  219. template <class EVT,class FSM,class SourceState,class TargetState>
  220. bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
  221. {
  222. return true;
  223. }
  224. };
  225. struct internal_guard
  226. {
  227. template <class EVT,class FSM,class SourceState,class TargetState>
  228. bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
  229. {
  230. std::cout << "Empty::internal guard\n";
  231. return false;
  232. }
  233. };
  234. // Transition table for player
  235. struct transition_table : mpl::vector<
  236. // Start Event Next Action Guard
  237. // +---------+-------------+---------+---------------------------+----------------------+
  238. Row < Stopped , play , Playing , ActionSequence_
  239. <mpl::vector<
  240. TestFct,start_playback> >
  241. , DummyGuard >,
  242. Row < Stopped , open_close , Open , open_drawer , none >,
  243. Row < Stopped , stop , Stopped , none , none >,
  244. // +---------+-------------+---------+---------------------------+----------------------+
  245. Row < Open , open_close , Empty , close_drawer , none >,
  246. // +---------+-------------+---------+---------------------------+----------------------+
  247. Row < Empty , open_close , Open , open_drawer , none >,
  248. Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
  249. always_true> >,
  250. // internal transition inside the stt: none as Target
  251. Row < Empty , cd_detected , none , none , internal_guard >,
  252. // +---------+-------------+---------+---------------------------+----------------------+
  253. Row < Playing , stop , Stopped , stop_playback , none >,
  254. Row < Playing , pause , Paused , pause_playback , none >,
  255. Row < Playing , open_close , Open , stop_and_open , none >,
  256. // +---------+-------------+---------+---------------------------+----------------------+
  257. Row < Paused , end_pause , Playing , resume_playback , none >,
  258. Row < Paused , stop , Stopped , stop_playback , none >,
  259. Row < Paused , open_close , Open , stop_and_open , none >
  260. // +---------+-------------+---------+---------------------------+----------------------+
  261. > {};
  262. // Replaces the default no-transition response.
  263. template <class FSM,class Event>
  264. void no_transition(Event const& e, FSM&,int state)
  265. {
  266. std::cout << "no transition from state " << state
  267. << " on event " << typeid(e).name() << std::endl;
  268. }
  269. };
  270. // Pick a back-end
  271. typedef msm::back::state_machine<player_> player;
  272. //
  273. // Testing utilities.
  274. //
  275. static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
  276. void pstate(player const& p)
  277. {
  278. std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
  279. }
  280. void test()
  281. {
  282. player p;
  283. // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
  284. p.start();
  285. // go to Open, call on_exit on Empty, then action, then on_entry on Open
  286. p.process_event(open_close()); pstate(p);
  287. p.process_event(open_close()); pstate(p);
  288. // will be rejected, wrong disk type
  289. p.process_event(
  290. cd_detected("louie, louie",DISK_DVD)); pstate(p);
  291. p.process_event(
  292. cd_detected("louie, louie",DISK_CD)); pstate(p);
  293. // no need to call play() as the previous transition does it in its action method
  294. //p.process_event(play());
  295. // at this point, Play is active
  296. p.process_event(pause()); pstate(p);
  297. // go back to Playing
  298. p.process_event(end_pause()); pstate(p);
  299. p.process_event(pause()); pstate(p);
  300. p.process_event(stop()); pstate(p);
  301. // event leading to the same state
  302. // no action method called as it is not present in the transition table
  303. p.process_event(stop()); pstate(p);
  304. }
  305. }
  306. int main()
  307. {
  308. test();
  309. return 0;
  310. }