3 Copyright David Abrahams 2003-2004
4 Copyright Aleksey Gurtovoy 2003-2004
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE_1_0.txt or copy at
8 http://www.boost.org/LICENSE_1_0.txt)
10 This file was automatically extracted from the source of
11 "C++ Template Metaprogramming", by David Abrahams and
14 It was built successfully with GCC 3.4.2 on Windows using
15 the following command:
17 g++ -I..\..\boost_1_32_0 -o%TEMP%\metaprogram-chapter11-example16.exe example16.cpp
21 #include <boost/mpl/fold.hpp>
22 #include <boost/mpl/filter_view.hpp>
23 #include <boost/type_traits/is_same.hpp>
26 #include <boost/mpl/vector.hpp>
28 #include <boost/mpl/placeholders.hpp>
29 #include <boost/mpl/assert.hpp>
30 #include <boost/static_assert.hpp>
31 namespace mpl
= boost::mpl
;
32 using namespace mpl::placeholders
;
40 struct event_dispatcher
42 typedef typename
Transition::fsm_t fsm_t
;
43 typedef typename
Transition::event event
;
46 fsm_t
& fsm
, int state
, event
const& e
)
48 if (state
== Transition::current_state
)
50 Transition::execute(fsm
, e
);
51 return Transition::next_state
;
53 else // move on to the next node in the chain.
55 return Next::dispatch(fsm
, state
, e
);
62 template <class Derived
> class state_machine
;
64 struct default_event_dispatcher
66 template<class FSM
, class Event
>
68 state_machine
<FSM
>& m
, int state
, Event
const& e
)
70 return m
.call_no_transition(state
, e
);
75 template<class Table
, class Event
>
76 struct generate_dispatcher
;
78 template<class Derived
>
87 , void (Derived::*action
)(Event
const&)
91 // for later use by our metaprogram
92 static int const current_state
= CurrentState
;
93 static int const next_state
= NextState
;
95 typedef Derived fsm_t
;
97 // do the transition action.
98 static void execute(Derived
& fsm
, Event
const& e
)
105 friend class default_event_dispatcher
;
107 template <class Event
>
108 int call_no_transition(int state
, Event
const& e
)
110 return static_cast<Derived
*>(this) // CRTP downcast
111 ->no_transition(state
, e
);
116 template<class Event
>
117 int process_event(Event
const& evt
)
119 // generate the dispatcher type.
120 typedef typename generate_dispatcher
<
121 typename
Derived::transition_table
, Event
124 // dispatch the event.
125 this->state
= dispatcher::dispatch(
126 *static_cast<Derived
*>(this) // CRTP downcast
131 // return the new state
138 : state(Derived::initial_state
)
148 template <class Event
>
149 int no_transition(int state
, Event
const& e
)
159 // get the Event associated with a transition.
160 template <class Transition
>
161 struct transition_event
163 typedef typename
Transition::event type
;
166 template<class Table
, class Event
>
167 struct generate_dispatcher
169 mpl::filter_view
< // select rows triggered by Event
171 , boost::is_same
<Event
, transition_event
<_1
> >
173 , default_event_dispatcher
174 , event_dispatcher
<_2
,_1
>
181 struct open_close
{};
183 cd_detected(char const*, std::vector
<std::clock_t> const&) {}
185 #ifdef __GNUC__ // in which pause seems to have a predefined meaning
186 # define pause pause_
192 // concrete FSM implementation
193 class player
: public state_machine
<player
>
196 // the list of FSM states
198 Empty
, Open
, Stopped
, Playing
, Paused
199 , initial_state
= Empty
204 public: // Codewarrior bug workaround. Tested at 0x3202
207 void start_playback(play
const&);
208 void open_drawer(open_close
const&);
209 void close_drawer(open_close
const&);
210 void store_cd_info(cd_detected
const&);
211 void stop_playback(stop
const&);
212 void pause_playback(pause
const&);
213 void resume_playback(play
const&);
214 void stop_and_open(open_close
const&);
220 friend class state_machine
<player
>;
221 typedef player p
; // makes transition table cleaner
224 struct transition_table
: mpl::vector11
<
226 // Start Event Next Action
227 // +---------+-------------+---------+---------------------+
228 row
< Stopped
, play
, Playing
, &p::start_playback
>,
229 row
< Stopped
, open_close
, Open
, &p::open_drawer
>,
230 // +---------+-------------+---------+---------------------+
231 row
< Open
, open_close
, Empty
, &p::close_drawer
>,
232 // +---------+-------------+---------+---------------------+
233 row
< Empty
, open_close
, Open
, &p::open_drawer
>,
234 row
< Empty
, cd_detected
, Stopped
, &p::store_cd_info
>,
235 // +---------+-------------+---------+---------------------+
236 row
< Playing
, stop
, Stopped
, &p::stop_playback
>,
237 row
< Playing
, pause
, Paused
, &p::pause_playback
>,
238 row
< Playing
, open_close
, Open
, &p::stop_and_open
>,
239 // +---------+-------------+---------+---------------------+
240 row
< Paused
, play
, Playing
, &p::resume_playback
>,
241 row
< Paused
, stop
, Stopped
, &p::stop_playback
>,
242 row
< Paused
, open_close
, Open
, &p::stop_and_open
>
243 // +---------+-------------+---------+---------------------+
249 row
<Stopped
, play
, Playing
, &player::start_playback
>
251 row
<Paused
, play
, Playing
, &player::resume_playback
>
252 , default_event_dispatcher
258 void player::start_playback(play
const&){}
259 void player::open_drawer(open_close
const&){}
260 void player::close_drawer(open_close
const&){}
261 void player::store_cd_info(cd_detected
const&){}
262 void player::stop_playback(stop
const&){}
263 void player::pause_playback(pause
const&){}
264 void player::resume_playback(play
const&){}
265 void player::stop_and_open(open_close
const&){}
272 player p
; // An instance of the FSM
274 p
.process_event(open_close()); // user opens CD player
275 p
.process_event(open_close()); // inserts CD and closes
276 p
.process_event( // CD is detected
279 , std::vector
<std::clock_t>( /* track lengths */ )
282 p
.process_event(play()); // etc.
283 p
.process_event(pause());
284 p
.process_event(play());
285 p
.process_event(stop());