123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- /*
- Copyright David Abrahams 2003-2004
- Copyright Aleksey Gurtovoy 2003-2004
- Distributed under the Boost Software License, Version 1.0.
- (See accompanying file LICENSE_1_0.txt or copy at
- http://www.boost.org/LICENSE_1_0.txt)
-
- This file was automatically extracted from the source of
- "C++ Template Metaprogramming", by David Abrahams and
- Aleksey Gurtovoy.
- It was built successfully with GCC 3.4.2 on Windows using
- the following command:
- g++ -I..\..\boost_1_32_0 -o%TEMP%\metaprogram-chapter11-example16.exe example16.cpp
-
- */
- #include <boost/mpl/fold.hpp>
- #include <boost/mpl/filter_view.hpp>
- #include <boost/type_traits/is_same.hpp>
- #include <vector>
- #include <ctime>
- #include <boost/mpl/vector.hpp>
- #include <boost/mpl/placeholders.hpp>
- #include <boost/mpl/assert.hpp>
- #include <boost/static_assert.hpp>
- namespace mpl = boost::mpl;
- using namespace mpl::placeholders;
- #include <cassert>
- template<
- class Transition
- , class Next
- >
- struct event_dispatcher
- {
- typedef typename Transition::fsm_t fsm_t;
- typedef typename Transition::event event;
- static int dispatch(
- fsm_t& fsm, int state, event const& e)
- {
- if (state == Transition::current_state)
- {
- Transition::execute(fsm, e);
- return Transition::next_state;
- }
- else // move on to the next node in the chain.
- {
- return Next::dispatch(fsm, state, e);
- }
- }
- };
- template <class Derived> class state_machine;
- struct default_event_dispatcher
- {
- template<class FSM, class Event>
- static int dispatch(
- state_machine<FSM>& m, int state, Event const& e)
- {
- return m.call_no_transition(state, e);
- }
- };
- template<class Table, class Event>
- struct generate_dispatcher;
- template<class Derived>
- class state_machine
- {
- // ...
- protected:
- template<
- int CurrentState
- , class Event
- , int NextState
- , void (Derived::*action)(Event const&)
- >
- struct row
- {
- // for later use by our metaprogram
- static int const current_state = CurrentState;
- static int const next_state = NextState;
- typedef Event event;
- typedef Derived fsm_t;
- // do the transition action.
- static void execute(Derived& fsm, Event const& e)
- {
- (fsm.*action)(e);
- }
- };
-
- friend class default_event_dispatcher;
-
- template <class Event>
- int call_no_transition(int state, Event const& e)
- {
- return static_cast<Derived*>(this) // CRTP downcast
- ->no_transition(state, e);
- }
- //
- public:
- template<class Event>
- int process_event(Event const& evt)
- {
- // generate the dispatcher type.
- typedef typename generate_dispatcher<
- typename Derived::transition_table, Event
- >::type dispatcher;
- // dispatch the event.
- this->state = dispatcher::dispatch(
- *static_cast<Derived*>(this) // CRTP downcast
- , this->state
- , evt
- );
- // return the new state
- return this->state;
- }
- // ...
- protected:
- state_machine()
- : state(Derived::initial_state)
- {
- }
- private:
- int state;
- // ...
- // ...
- public:
- template <class Event>
- int no_transition(int state, Event const& e)
- {
- assert(false);
- return state;
- }
- // ...
- ////
- };
- // get the Event associated with a transition.
- template <class Transition>
- struct transition_event
- {
- typedef typename Transition::event type;
- };
- template<class Table, class Event>
- struct generate_dispatcher
- : mpl::fold<
- mpl::filter_view< // select rows triggered by Event
- Table
- , boost::is_same<Event, transition_event<_1> >
- >
- , default_event_dispatcher
- , event_dispatcher<_2,_1>
- >
- {};
- struct play {};
- struct open_close {};
- struct cd_detected {
- cd_detected(char const*, std::vector<std::clock_t> const&) {}
- };
- #ifdef __GNUC__ // in which pause seems to have a predefined meaning
- # define pause pause_
- #endif
- struct pause {};
- struct stop {};
-
- // concrete FSM implementation
- class player : public state_machine<player>
- {
- private:
- // the list of FSM states
- enum states {
- Empty, Open, Stopped, Playing, Paused
- , initial_state = Empty
- };
-
- #ifdef __MWERKS__
- public: // Codewarrior bug workaround. Tested at 0x3202
- #endif
-
- void start_playback(play const&);
- void open_drawer(open_close const&);
- void close_drawer(open_close const&);
- void store_cd_info(cd_detected const&);
- void stop_playback(stop const&);
- void pause_playback(pause const&);
- void resume_playback(play const&);
- void stop_and_open(open_close const&);
-
- #ifdef __MWERKS__
- private:
- #endif
- friend class state_machine<player>;
- typedef player p; // makes transition table cleaner
- // transition table
- struct transition_table : mpl::vector11<
- // Start Event Next Action
- // +---------+-------------+---------+---------------------+
- row < Stopped , play , Playing , &p::start_playback >,
- row < Stopped , open_close , Open , &p::open_drawer >,
- // +---------+-------------+---------+---------------------+
- row < Open , open_close , Empty , &p::close_drawer >,
- // +---------+-------------+---------+---------------------+
- row < Empty , open_close , Open , &p::open_drawer >,
- row < Empty , cd_detected , Stopped , &p::store_cd_info >,
- // +---------+-------------+---------+---------------------+
- row < Playing , stop , Stopped , &p::stop_playback >,
- row < Playing , pause , Paused , &p::pause_playback >,
- row < Playing , open_close , Open , &p::stop_and_open >,
- // +---------+-------------+---------+---------------------+
- row < Paused , play , Playing , &p::resume_playback >,
- row < Paused , stop , Stopped , &p::stop_playback >,
- row < Paused , open_close , Open , &p::stop_and_open >
- // +---------+-------------+---------+---------------------+
- > {};
- typedef
-
- event_dispatcher<
- row<Stopped, play, Playing, &player::start_playback>
- , event_dispatcher<
- row<Paused, play, Playing, &player::resume_playback>
- , default_event_dispatcher
- >
- >
- dummy;
- };
- void player::start_playback(play const&){}
- void player::open_drawer(open_close const&){}
- void player::close_drawer(open_close const&){}
- void player::store_cd_info(cd_detected const&){}
- void player::stop_playback(stop const&){}
- void player::pause_playback(pause const&){}
- void player::resume_playback(play const&){}
- void player::stop_and_open(open_close const&){}
-
- int main()
- {
- player p; // An instance of the FSM
- p.process_event(open_close()); // user opens CD player
- p.process_event(open_close()); // inserts CD and closes
- p.process_event( // CD is detected
- cd_detected(
- "louie, louie"
- , std::vector<std::clock_t>( /* track lengths */ )
- )
- );
- p.process_event(play()); // etc.
- p.process_event(pause());
- p.process_event(play());
- p.process_event(stop());
- return 0;
- }
|