diff options
Diffstat (limited to 'src/boost/libs/mpl/example/fsm/player1.cpp')
-rw-r--r-- | src/boost/libs/mpl/example/fsm/player1.cpp | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/boost/libs/mpl/example/fsm/player1.cpp b/src/boost/libs/mpl/example/fsm/player1.cpp new file mode 100644 index 00000000..a5a1a2cb --- /dev/null +++ b/src/boost/libs/mpl/example/fsm/player1.cpp @@ -0,0 +1,287 @@ +/* + + 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; +} |