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 11 #include <iostream> 12 // back-end 13 #include <boost/msm/back/state_machine.hpp> 14 //front-end 15 #include <boost/msm/front/state_machine_def.hpp> 16 // functors 17 #include <boost/msm/front/functor_row.hpp> 18 #include <boost/msm/front/euml/common.hpp> 19 // for And_ operator 20 #include <boost/msm/front/euml/operator.hpp> 21 22 #include <boost/test/unit_test.hpp> 23 24 using namespace std; 25 namespace msm = boost::msm; 26 namespace mpl = boost::mpl; 27 using namespace msm::front; 28 // for And_ operator 29 using namespace msm::front::euml; 30 31 namespace 32 { 33 // events 34 struct event1 {}; 35 struct event2 {}; 36 37 // front-end: define the FSM structure 38 struct my_machine_ : public msm::front::state_machine_def<my_machine_> 39 { 40 41 // The list of FSM states 42 struct State1 : public msm::front::state<> 43 { 44 template <class Event,class FSM> on_entry__anonab0116f90111::my_machine_::State145 void on_entry(Event const&,FSM& ) {++entry_counter;} 46 template <class Event,class FSM> on_exit__anonab0116f90111::my_machine_::State147 void on_exit(Event const&,FSM& ) {++exit_counter;} 48 int entry_counter; 49 int exit_counter; 50 }; 51 struct State2 : public msm::front::state<> 52 { 53 template <class Event,class FSM> on_entry__anonab0116f90111::my_machine_::State254 void on_entry(Event const&,FSM& ) {++entry_counter;} 55 template <class Event,class FSM> on_exit__anonab0116f90111::my_machine_::State256 void on_exit(Event const&,FSM& ) {++exit_counter;} 57 int entry_counter; 58 int exit_counter; 59 }; 60 61 struct State3 : public msm::front::state<> 62 { 63 template <class Event,class FSM> on_entry__anonab0116f90111::my_machine_::State364 void on_entry(Event const&,FSM& ) {++entry_counter;} 65 template <class Event,class FSM> on_exit__anonab0116f90111::my_machine_::State366 void on_exit(Event const&,FSM& ) {++exit_counter;} 67 int entry_counter; 68 int exit_counter; 69 }; 70 71 struct State1b : public msm::front::state<> 72 { 73 template <class Event,class FSM> on_entry__anonab0116f90111::my_machine_::State1b74 void on_entry(Event const&,FSM& ) {++entry_counter;} 75 template <class Event,class FSM> on_exit__anonab0116f90111::my_machine_::State1b76 void on_exit(Event const&,FSM& ) {++exit_counter;} 77 int entry_counter; 78 int exit_counter; 79 }; 80 struct State2b : public msm::front::state<> 81 { 82 template <class Event,class FSM> on_entry__anonab0116f90111::my_machine_::State2b83 void on_entry(Event const&,FSM& ) {++entry_counter;} 84 template <class Event,class FSM> on_exit__anonab0116f90111::my_machine_::State2b85 void on_exit(Event const&,FSM& ) {++exit_counter;} 86 int entry_counter; 87 int exit_counter; 88 }; 89 90 struct always_true 91 { 92 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonab0116f90111::my_machine_::always_true93 bool operator()(EVT const& ,FSM&,SourceState& ,TargetState& ) 94 { 95 return true; 96 } 97 }; 98 struct always_false 99 { 100 template <class EVT,class FSM,class SourceState,class TargetState> operator ()__anonab0116f90111::my_machine_::always_false101 bool operator()(EVT const& ,FSM&,SourceState& ,TargetState& ) 102 { 103 return false; 104 } 105 }; 106 107 // the initial state of the player SM. Must be defined 108 typedef boost::mpl::vector2<State1,State1b> initial_state; 109 110 // Transition table for player 111 struct transition_table : boost::mpl::vector< 112 // Start Event Next Action Guard 113 // +---------+-------------+---------+---------------------+----------------------+ 114 Row < State1 , event1 , State2 , none , always_true >, 115 Row < State2 , none , State3 >, 116 // +---------+-------------+---------+---------------------+----------------------+ 117 Row < State1b , event1 , State2b , none , always_false > 118 // +---------+-------------+---------+---------------------+----------------------+ 119 > {}; 120 // Replaces the default no-transition response. 121 template <class FSM,class Event> no_transition__anonab0116f90111::my_machine_122 void no_transition(Event const&, FSM&,int) 123 { 124 BOOST_FAIL("no_transition called!"); 125 } 126 // init counters 127 template <class Event,class FSM> on_entry__anonab0116f90111::my_machine_128 void on_entry(Event const&,FSM& fsm) 129 { 130 fsm.template get_state<my_machine_::State1&>().entry_counter=0; 131 fsm.template get_state<my_machine_::State1&>().exit_counter=0; 132 fsm.template get_state<my_machine_::State2&>().entry_counter=0; 133 fsm.template get_state<my_machine_::State2&>().exit_counter=0; 134 fsm.template get_state<my_machine_::State3&>().entry_counter=0; 135 fsm.template get_state<my_machine_::State3&>().exit_counter=0; 136 fsm.template get_state<my_machine_::State1b&>().entry_counter=0; 137 fsm.template get_state<my_machine_::State1b&>().exit_counter=0; 138 fsm.template get_state<my_machine_::State2b&>().entry_counter=0; 139 fsm.template get_state<my_machine_::State2b&>().exit_counter=0; 140 } 141 }; 142 // Pick a back-end 143 typedef msm::back::state_machine<my_machine_> my_machine; 144 BOOST_AUTO_TEST_CASE(my_test)145 BOOST_AUTO_TEST_CASE( my_test ) 146 { 147 my_machine p; 148 149 p.start(); 150 BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active"); 151 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State1b should be active"); 152 153 p.process_event(event1()); 154 BOOST_CHECK_MESSAGE(p.current_state()[0] == 3,"State3 should be active"); 155 BOOST_CHECK_MESSAGE(p.current_state()[1] == 2,"State1b should be active"); 156 157 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly"); 158 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly"); 159 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly"); 160 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly"); 161 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().exit_counter == 0,"State3 exit not called correctly"); 162 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State3&>().entry_counter == 1,"State3 entry not called correctly"); 163 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1b&>().entry_counter == 1,"State1b entry not called correctly"); 164 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1b&>().exit_counter == 0,"State1b exit not called correctly"); 165 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2b&>().entry_counter == 0,"State2b entry not called correctly"); 166 BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2b&>().exit_counter == 0,"State2b exit not called correctly"); 167 168 169 } 170 } 171 172 173