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 | |
16 | #include <boost/test/unit_test.hpp> |
17 | |
18 | namespace msm = boost::msm; |
19 | namespace mpl = boost::mpl; |
20 | using namespace boost::msm::front; |
21 | |
22 | namespace |
23 | { |
24 | // events |
25 | struct event1 {}; |
26 | struct event2 {}; |
27 | |
28 | |
29 | // front-end: define the FSM structure |
30 | struct my_machine_ : public msm::front::state_machine_def<my_machine_> |
31 | { |
32 | |
33 | my_machine_() |
34 | {} |
35 | |
36 | // The list of FSM states |
37 | struct State1 : public msm::front::state<> |
38 | { |
39 | template <class Event,class FSM> |
40 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
41 | template <class Event,class FSM> |
42 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
43 | int entry_counter=0; |
44 | int exit_counter=0; |
45 | }; |
46 | struct State2 : public msm::front::state<> |
47 | { |
48 | template <class Event,class FSM> |
49 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
50 | template <class Event,class FSM> |
51 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
52 | int entry_counter=0; |
53 | int exit_counter=0; |
54 | }; |
55 | struct State3 : public msm::front::state<> |
56 | { |
57 | template <class Event,class FSM> |
58 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
59 | template <class Event,class FSM> |
60 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
61 | int entry_counter=0; |
62 | int exit_counter=0; |
63 | }; |
64 | struct State4 : public msm::front::state<> |
65 | { |
66 | template <class Event,class FSM> |
67 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
68 | template <class Event,class FSM> |
69 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
70 | int entry_counter=0; |
71 | int exit_counter=0; |
72 | }; |
73 | struct State5 : public msm::front::state<> |
74 | { |
75 | template <class Event,class FSM> |
76 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
77 | template <class Event,class FSM> |
78 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
79 | int entry_counter=0; |
80 | int exit_counter=0; |
81 | }; |
82 | struct State6 : public msm::front::state<> |
83 | { |
84 | template <class Event,class FSM> |
85 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
86 | template <class Event,class FSM> |
87 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
88 | int entry_counter=0; |
89 | int exit_counter=0; |
90 | }; |
91 | struct State7 : public msm::front::state<> |
92 | { |
93 | template <class Event,class FSM> |
94 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
95 | template <class Event,class FSM> |
96 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
97 | int entry_counter=0; |
98 | int exit_counter=0; |
99 | }; |
100 | struct State8 : public msm::front::state<> |
101 | { |
102 | template <class Event,class FSM> |
103 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
104 | template <class Event,class FSM> |
105 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
106 | int entry_counter=0; |
107 | int exit_counter=0; |
108 | }; |
109 | struct State9 : public msm::front::state<> |
110 | { |
111 | template <class Event,class FSM> |
112 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
113 | template <class Event,class FSM> |
114 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
115 | int entry_counter=0; |
116 | int exit_counter=0; |
117 | }; |
118 | struct State10 : public msm::front::state<> |
119 | { |
120 | template <class Event,class FSM> |
121 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
122 | template <class Event,class FSM> |
123 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
124 | int entry_counter=0; |
125 | int exit_counter=0; |
126 | }; |
127 | struct State11 : public msm::front::state<> |
128 | { |
129 | template <class Event,class FSM> |
130 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
131 | template <class Event,class FSM> |
132 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
133 | int entry_counter=0; |
134 | int exit_counter=0; |
135 | }; |
136 | struct State12 : public msm::front::state<> |
137 | { |
138 | template <class Event,class FSM> |
139 | void on_entry(Event const&,FSM& ) {++entry_counter;} |
140 | template <class Event,class FSM> |
141 | void on_exit(Event const&,FSM& ) {++exit_counter;} |
142 | int entry_counter=0; |
143 | int exit_counter=0; |
144 | }; |
145 | |
146 | // the initial state of the player SM. Must be defined |
147 | typedef State1 initial_state; |
148 | |
149 | // transition actions |
150 | |
151 | // guard conditions |
152 | |
153 | typedef my_machine_ p; // makes transition table cleaner |
154 | |
155 | // Transition table for player |
156 | struct transition_table : mpl::vector< |
157 | // Start Event Next Action Guard |
158 | // +---------+-------------+---------+---------------------+----------------------+ |
159 | _row < State1 , event1 , State2 >, |
160 | _row < State2 , event1 , State3 >, |
161 | _row < State3 , event1 , State4 >, |
162 | _row < State4 , event1 , State5 >, |
163 | _row < State5 , event1 , State6 >, |
164 | _row < State6 , event1 , State7 >, |
165 | _row < State7 , event1 , State8 >, |
166 | _row < State8 , event1 , State9 >, |
167 | _row < State9 , event1 , State10 >, |
168 | _row < State10 , event1 , State11 >, |
169 | _row < State11 , event1 , State12 >, |
170 | |
171 | _row < State12 , event2 , State11 >, |
172 | _row < State11 , event2 , State10 >, |
173 | _row < State10 , event2 , State9 >, |
174 | _row < State9 , event2 , State8 >, |
175 | _row < State8 , event2 , State7 >, |
176 | _row < State7 , event2 , State6 >, |
177 | _row < State6 , event2 , State5 >, |
178 | _row < State5 , event2 , State4 >, |
179 | _row < State4 , event2 , State3 >, |
180 | _row < State3 , event2 , State2 >, |
181 | _row < State2 , event2 , State1 > |
182 | // +---------+-------------+---------+---------------------+----------------------+ |
183 | > {}; |
184 | // Replaces the default no-transition response. |
185 | template <class FSM,class Event> |
186 | void no_transition(Event const&, FSM&,int) |
187 | { |
188 | BOOST_FAIL("no_transition called!" ); |
189 | } |
190 | // init counters |
191 | template <class Event,class FSM> |
192 | void on_entry(Event const&,FSM&) |
193 | { |
194 | |
195 | } |
196 | }; |
197 | // Pick a back-end |
198 | typedef msm::back::state_machine<my_machine_> my_machine; |
199 | |
200 | |
201 | BOOST_AUTO_TEST_CASE( big_with_functors_test ) |
202 | { |
203 | my_machine p; |
204 | |
205 | // needed to start the highest-level SM. |
206 | p.start(); |
207 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active" ); //State1 |
208 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 0,"State1 exit not called correctly" ); |
209 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 1,"State1 entry not called correctly" ); |
210 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State5&>().exit_counter == 0,"State5 exit not called correctly" ); |
211 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State5&>().entry_counter == 0,"State5 entry not called correctly" ); |
212 | |
213 | p.process_event(evt: event1()); |
214 | p.process_event(evt: event1()); |
215 | p.process_event(evt: event1()); |
216 | p.process_event(evt: event1()); |
217 | p.process_event(evt: event1()); |
218 | p.process_event(evt: event1()); |
219 | p.process_event(evt: event1()); |
220 | p.process_event(evt: event1()); |
221 | p.process_event(evt: event1()); |
222 | p.process_event(evt: event1()); |
223 | p.process_event(evt: event1()); |
224 | |
225 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 11,"State12 should be active" ); //State12 |
226 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State12&>().exit_counter == 0,"State12 exit not called correctly" ); |
227 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State12&>().entry_counter == 1,"State12 entry not called correctly" ); |
228 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 1,"State2 exit not called correctly" ); |
229 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 1,"State2 entry not called correctly" ); |
230 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().exit_counter == 1,"State7 exit not called correctly" ); |
231 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().entry_counter == 1,"State7 entry not called correctly" ); |
232 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().exit_counter == 1,"State10 exit not called correctly" ); |
233 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().entry_counter == 1,"State10 entry not called correctly" ); |
234 | |
235 | |
236 | p.process_event(evt: event2()); |
237 | p.process_event(evt: event2()); |
238 | p.process_event(evt: event2()); |
239 | p.process_event(evt: event2()); |
240 | p.process_event(evt: event2()); |
241 | p.process_event(evt: event2()); |
242 | p.process_event(evt: event2()); |
243 | p.process_event(evt: event2()); |
244 | p.process_event(evt: event2()); |
245 | p.process_event(evt: event2()); |
246 | p.process_event(evt: event2()); |
247 | |
248 | BOOST_CHECK_MESSAGE(p.current_state()[0] == 0,"State1 should be active" ); //State1 |
249 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().exit_counter == 1,"State1 exit not called correctly" ); |
250 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State1&>().entry_counter == 2,"State1 entry not called correctly" ); |
251 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().exit_counter == 2,"State2 exit not called correctly" ); |
252 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State2&>().entry_counter == 2,"State2 entry not called correctly" ); |
253 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().exit_counter == 2,"State7 exit not called correctly" ); |
254 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State7&>().entry_counter == 2,"State7 entry not called correctly" ); |
255 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().exit_counter == 2,"State10 exit not called correctly" ); |
256 | BOOST_CHECK_MESSAGE(p.get_state<my_machine_::State10&>().entry_counter == 2,"State10 entry not called correctly" ); |
257 | |
258 | } |
259 | } |
260 | |
261 | |