Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/mpl/example/fsm/player1.cpp @ 12

Last change on this file since 12 was 12, checked in by landauf, 17 years ago

added boost

  • Property svn:executable set to *
File size: 7.2 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.