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 #ifndef BOOST_MSM_NONSTANDALONE_TEST
17 #define BOOST_TEST_MODULE MyTest
18 #endif
19 #include <boost/test/unit_test.hpp>
20 
21 namespace msm = boost::msm;
22 namespace mpl = boost::mpl;
23 
24 namespace
25 {
26     // events
27     struct play {};
28     struct end_pause {};
29     struct stop {};
30     struct pause {};
31     struct open_close {};
32 
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     {
cd_detected__anond3a7b6e30111::cd_detected41         cd_detected(std::string name, DiskTypeEnum diskType)
42             : name(name),
43             disc_type(diskType)
44         {}
45 
46         std::string name;
47         DiskTypeEnum disc_type;
48     };
49     struct SomeExternalContext
50     {
SomeExternalContext__anond3a7b6e30111::SomeExternalContext51         SomeExternalContext(int b):bla(b){}
52         int bla;
53     };
54     // front-end: define the FSM structure
55     struct player_ : public msm::front::state_machine_def<player_>
56     {
player___anond3a7b6e30111::player_57         player_(SomeExternalContext& context,int someint):
58         context_(context),
59         someint_(someint)
60         {}
61 
62         SomeExternalContext& context_;
63         int someint_;
64 
65         // The list of FSM states
66         struct Empty : public msm::front::state<>
67         {
68             template <class Event,class FSM>
on_entry__anond3a7b6e30111::player_::Empty69             void on_entry(Event const&,FSM& ) {++entry_counter;}
70             template <class Event,class FSM>
on_exit__anond3a7b6e30111::player_::Empty71             void on_exit(Event const&,FSM& ) {++exit_counter;}
72             int entry_counter;
73             int exit_counter;
74         };
75         struct Open : public msm::front::state<>
76         {
77             template <class Event,class FSM>
on_entry__anond3a7b6e30111::player_::Open78             void on_entry(Event const&,FSM& ) {++entry_counter;}
79             template <class Event,class FSM>
on_exit__anond3a7b6e30111::player_::Open80             void on_exit(Event const&,FSM& ) {++exit_counter;}
81             int entry_counter;
82             int exit_counter;
83         };
84 
85         // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
86         struct Stopped : public msm::front::state<>
87         {
88             template <class Event,class FSM>
on_entry__anond3a7b6e30111::player_::Stopped89             void on_entry(Event const&,FSM& ) {++entry_counter;}
90             template <class Event,class FSM>
on_exit__anond3a7b6e30111::player_::Stopped91             void on_exit(Event const&,FSM& ) {++exit_counter;}
92             int entry_counter;
93             int exit_counter;
94         };
95 
96         struct Playing : public msm::front::state<>
97         {
98             template <class Event,class FSM>
on_entry__anond3a7b6e30111::player_::Playing99             void on_entry(Event const&,FSM& ) {++entry_counter;}
100             template <class Event,class FSM>
on_exit__anond3a7b6e30111::player_::Playing101             void on_exit(Event const&,FSM& ) {++exit_counter;}
102             int entry_counter;
103             int exit_counter;
104         };
105 
106         // state not defining any entry or exit
107         struct Paused : public msm::front::state<>
108         {
109             template <class Event,class FSM>
on_entry__anond3a7b6e30111::player_::Paused110             void on_entry(Event const&,FSM& ) {++entry_counter;}
111             template <class Event,class FSM>
on_exit__anond3a7b6e30111::player_::Paused112             void on_exit(Event const&,FSM& ) {++exit_counter;}
113             int entry_counter;
114             int exit_counter;
115         };
116 
117         // the initial state of the player SM. Must be defined
118         typedef Empty initial_state;
119 
120         // transition actions
start_playback__anond3a7b6e30111::player_121         void start_playback(play const&)       {}
open_drawer__anond3a7b6e30111::player_122         void open_drawer(open_close const&)    {  }
store_cd_info__anond3a7b6e30111::player_123         void store_cd_info(cd_detected const&) {  }
stop_playback__anond3a7b6e30111::player_124         void stop_playback(stop const&)        {  }
pause_playback__anond3a7b6e30111::player_125         void pause_playback(pause const&)      {  }
resume_playback__anond3a7b6e30111::player_126         void resume_playback(end_pause const&)      {  }
stop_and_open__anond3a7b6e30111::player_127         void stop_and_open(open_close const&)  {  }
stopped_again__anond3a7b6e30111::player_128         void stopped_again(stop const&){}
129         // guard conditions
good_disk_format__anond3a7b6e30111::player_130         bool good_disk_format(cd_detected const& evt)
131         {
132             // to test a guard condition, let's say we understand only CDs, not DVD
133             if (evt.disc_type != DISK_CD)
134             {
135                 return false;
136             }
137             return true;
138         }
can_close_drawer__anond3a7b6e30111::player_139         bool can_close_drawer(open_close const&)
140         {
141             return true;
142         }
143 
144         typedef player_ p; // makes transition table cleaner
145 
146         // Transition table for player
147         struct transition_table : mpl::vector<
148             //    Start     Event         Next      Action               Guard
149             //  +---------+-------------+---------+---------------------+----------------------+
150           a_row < Stopped , play        , Playing , &p::start_playback                         >,
151           a_row < Stopped , open_close  , Open    , &p::open_drawer                            >,
152            _row < Stopped , stop        , Stopped                                              >,
153             //  +---------+-------------+---------+---------------------+----------------------+
154           g_row < Open    , open_close  , Empty   ,                      &p::can_close_drawer  >,
155             //  +---------+-------------+---------+---------------------+----------------------+
156           a_row < Empty   , open_close  , Open    , &p::open_drawer                            >,
157             row < Empty   , cd_detected , Stopped , &p::store_cd_info   ,&p::good_disk_format  >,
158             //  +---------+-------------+---------+---------------------+----------------------+
159           a_row < Playing , stop        , Stopped , &p::stop_playback                          >,
160           a_row < Playing , pause       , Paused  , &p::pause_playback                         >,
161           a_row < Playing , open_close  , Open    , &p::stop_and_open                          >,
162             //  +---------+-------------+---------+---------------------+----------------------+
163           a_row < Paused  , end_pause   , Playing , &p::resume_playback                        >,
164           a_row < Paused  , stop        , Stopped , &p::stop_playback                          >,
165           a_row < Paused  , open_close  , Open    , &p::stop_and_open                          >
166             //  +---------+-------------+---------+---------------------+----------------------+
167         > {};
168         // Replaces the default no-transition response.
169         template <class FSM,class Event>
no_transition__anond3a7b6e30111::player_170         void no_transition(Event const&, FSM&,int)
171         {
172             BOOST_FAIL("no_transition called!");
173         }
174         // init counters
175         template <class Event,class FSM>
on_entry__anond3a7b6e30111::player_176         void on_entry(Event const&,FSM& fsm)
177         {
178             fsm.template get_state<player_::Stopped&>().entry_counter=0;
179             fsm.template get_state<player_::Stopped&>().exit_counter=0;
180             fsm.template get_state<player_::Open&>().entry_counter=0;
181             fsm.template get_state<player_::Open&>().exit_counter=0;
182             fsm.template get_state<player_::Empty&>().entry_counter=0;
183             fsm.template get_state<player_::Empty&>().exit_counter=0;
184             fsm.template get_state<player_::Playing&>().entry_counter=0;
185             fsm.template get_state<player_::Playing&>().exit_counter=0;
186             fsm.template get_state<player_::Paused&>().entry_counter=0;
187             fsm.template get_state<player_::Paused&>().exit_counter=0;
188             fsm.context_ = 20;
189         }
190 
191     };
192     // Pick a back-end
193     typedef msm::back::state_machine<player_> player;
194 
195 //    static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
196 
197 
BOOST_AUTO_TEST_CASE(my_test)198     BOOST_AUTO_TEST_CASE( my_test )
199     {
200         SomeExternalContext ctx(3);
201         player p(boost::ref(ctx),5);
202         BOOST_CHECK_MESSAGE(p.context_.bla == 3,"wrong value passed");
203         BOOST_CHECK_MESSAGE(p.someint_ == 5,"wrong value passed");
204         ctx.bla = 10;
205         BOOST_CHECK_MESSAGE(p.context_.bla == 10,"error with reference");
206         p.start();
207         BOOST_CHECK_MESSAGE(p.context_.bla == 20,"error with fsm entry behavior");
208     }
209 }
210 
211