]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/mpl/example/fsm/player1.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / mpl / example / fsm / player1.cpp
CommitLineData
7c673cae
FG
1/*
2
3 Copyright David Abrahams 2003-2004
4 Copyright Aleksey Gurtovoy 2003-2004
5
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)
9
10 This file was automatically extracted from the source of
11 "C++ Template Metaprogramming", by David Abrahams and
12 Aleksey Gurtovoy.
13
14 It was built successfully with GCC 3.4.2 on Windows using
15 the following command:
16
17 g++ -I..\..\boost_1_32_0 -o%TEMP%\metaprogram-chapter11-example16.exe example16.cpp
18
19
20*/
21#include <boost/mpl/fold.hpp>
22#include <boost/mpl/filter_view.hpp>
23#include <boost/type_traits/is_same.hpp>
24#include <vector>
25#include <ctime>
26#include <boost/mpl/vector.hpp>
27
28#include <boost/mpl/placeholders.hpp>
29#include <boost/mpl/assert.hpp>
30#include <boost/static_assert.hpp>
31namespace mpl = boost::mpl;
32using namespace mpl::placeholders;
33
34#include <cassert>
35
36template<
37 class Transition
38 , class Next
39>
40struct event_dispatcher
41{
42 typedef typename Transition::fsm_t fsm_t;
43 typedef typename Transition::event event;
44
45 static int dispatch(
46 fsm_t& fsm, int state, event const& e)
47 {
48 if (state == Transition::current_state)
49 {
50 Transition::execute(fsm, e);
51 return Transition::next_state;
52 }
53 else // move on to the next node in the chain.
54 {
55 return Next::dispatch(fsm, state, e);
56 }
57 }
58};
59
60
61
62template <class Derived> class state_machine;
63
64struct default_event_dispatcher
65{
66 template<class FSM, class Event>
67 static int dispatch(
68 state_machine<FSM>& m, int state, Event const& e)
69 {
70 return m.call_no_transition(state, e);
71 }
72};
73
74
75 template<class Table, class Event>
76 struct generate_dispatcher;
77
78template<class Derived>
79class state_machine
80{
81 // ...
82 protected:
83 template<
84 int CurrentState
85 , class Event
86 , int NextState
87 , void (Derived::*action)(Event const&)
88 >
89 struct row
90 {
91 // for later use by our metaprogram
92 static int const current_state = CurrentState;
93 static int const next_state = NextState;
94 typedef Event event;
95 typedef Derived fsm_t;
96
97 // do the transition action.
98 static void execute(Derived& fsm, Event const& e)
99 {
100 (fsm.*action)(e);
101 }
102 };
103
104
105 friend class default_event_dispatcher;
106
107 template <class Event>
108 int call_no_transition(int state, Event const& e)
109 {
110 return static_cast<Derived*>(this) // CRTP downcast
111 ->no_transition(state, e);
112 }
113 //
114public:
115
116template<class Event>
117int process_event(Event const& evt)
118{
119 // generate the dispatcher type.
120 typedef typename generate_dispatcher<
121 typename Derived::transition_table, Event
122 >::type dispatcher;
123
124 // dispatch the event.
125 this->state = dispatcher::dispatch(
126 *static_cast<Derived*>(this) // CRTP downcast
127 , this->state
128 , evt
129 );
130
131 // return the new state
132 return this->state;
133}
134
135// ...
136 protected:
137 state_machine()
138 : state(Derived::initial_state)
139 {
140 }
141
142 private:
143 int state;
144// ...
145
146// ...
147 public:
148 template <class Event>
149 int no_transition(int state, Event const& e)
150 {
151 assert(false);
152 return state;
153 }
154// ...
155////
156 };
157
158
159// get the Event associated with a transition.
160template <class Transition>
161struct transition_event
162{
163 typedef typename Transition::event type;
164};
165
166template<class Table, class Event>
167struct generate_dispatcher
168 : mpl::fold<
169 mpl::filter_view< // select rows triggered by Event
170 Table
171 , boost::is_same<Event, transition_event<_1> >
172 >
173 , default_event_dispatcher
174 , event_dispatcher<_2,_1>
175 >
176{};
177
178
179
180 struct play {};
181 struct open_close {};
182 struct cd_detected {
183 cd_detected(char const*, std::vector<std::clock_t> const&) {}
184 };
185 #ifdef __GNUC__ // in which pause seems to have a predefined meaning
186 # define pause pause_
187 #endif
188 struct pause {};
189 struct stop {};
190
191
192// concrete FSM implementation
193class player : public state_machine<player>
194{
195 private:
196 // the list of FSM states
197 enum states {
198 Empty, Open, Stopped, Playing, Paused
199 , initial_state = Empty
200 };
201
202
203 #ifdef __MWERKS__
204 public: // Codewarrior bug workaround. Tested at 0x3202
205 #endif
206
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&);
215
216
217 #ifdef __MWERKS__
218 private:
219 #endif
220 friend class state_machine<player>;
221 typedef player p; // makes transition table cleaner
222
223 // transition table
224 struct transition_table : mpl::vector11<
225
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 // +---------+-------------+---------+---------------------+
244
245 > {};
246typedef
247
248event_dispatcher<
249 row<Stopped, play, Playing, &player::start_playback>
250 , event_dispatcher<
251 row<Paused, play, Playing, &player::resume_playback>
252 , default_event_dispatcher
253 >
254>
255 dummy;
256};
257
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&){}
266
267
268
269
270int main()
271{
272 player p; // An instance of the FSM
273
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
277 cd_detected(
278 "louie, louie"
279 , std::vector<std::clock_t>( /* track lengths */ )
280 )
281 );
282 p.process_event(play()); // etc.
283 p.process_event(pause());
284 p.process_event(play());
285 p.process_event(stop());
286 return 0;
287}