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