player2.cpp
来自「Boost provides free peer-reviewed portab」· C++ 代码 · 共 327 行
CPP
327 行
//// Copyright 2005 David Abrahams and Aleksey Gurtovoy. 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)//#include "boost/mpl/int.hpp"#include "boost/mpl/fold.hpp"#include "boost/mpl/prior.hpp"#include "boost/mpl/count.hpp"#include "boost/mpl/insert.hpp"#include <boost/mpl/greater.hpp>#include <boost/mpl/for_each.hpp>#include <boost/mpl/filter_view.hpp>#include "boost/mpl/vector/vector20.hpp"#include "boost/assert.hpp"#include <boost/type_traits/is_same.hpp>#include <vector>#include <ctime>#include <iostream>#if defined(BOOST_DINKUMWARE_STDLIB) && BOOST_DINKUMWARE_STDLIB < 310namespace std { using ::clock_t; }#endifnamespace mpl = boost::mpl;using namespace mpl::placeholders;// A metafunction that returns the Event associated with a transition.template <class Transition>struct transition_event{ typedef typename Transition::event type;};// A metafunction computing the maximum of a transition's source and// end states.template <class Transition>struct transition_max_state{ typedef typename mpl::int_< (Transition::current_state > Transition::next_state) ? Transition::current_state : Transition::next_state > type;};template<class Derived>class state_machine;// Generates a singleton runtime lookup table that maps current state// to a function that makes the FSM take its transition on the given// Event type.template <class Fsm, int initial_state, class Stt, class Event>struct dispatch_table{ private: // This is a table of these function pointers. typedef int (*cell)(Fsm&, int, Event const&); // Compute the maximum state value in the Fsm so we know how big // to make the table BOOST_STATIC_CONSTANT( int, max_state = ( mpl::fold<Stt , mpl::int_<initial_state> , mpl::if_< mpl::greater<transition_max_state<_2>,_1> , transition_max_state<_2> , _1 > >::type::value ) ); // A function object for use with mpl::for_each that stuffs // transitions into cells. struct init_cell { init_cell(dispatch_table* self_) : self(self_) {} // Cell initializer function object, used with mpl::for_each template <class Transition> void operator()(Transition const&) const { self->entries[Transition::current_state] = &Transition::execute; } dispatch_table* self; }; public: // initialize the dispatch table for a given Event and Fsm dispatch_table() { // Initialize cells for no transition for (int i = 0; i <= max_state; ++i) { // VC7.1 seems to need the two-phase assignment. cell call_no_transition = &state_machine<Fsm>::call_no_transition; entries[i] = call_no_transition; } // Go back and fill in cells for matching transitions. mpl::for_each< mpl::filter_view< Stt , boost::is_same<transition_event<_>, Event> > >(init_cell(this)); } // The singleton instance. static const dispatch_table instance; public: // data members cell entries[max_state + 1];};// This declares the statically-initialized dispatch_table instance.template <class Fsm, int initial_state, class Stt, class Event>const dispatch_table<Fsm, initial_state, Stt, Event>dispatch_table<Fsm, initial_state, Stt, Event>::instance;// CRTP base class for state machines. Pass the actual FSM class as// the Derived parameter.template<class Derived>class state_machine{ public: // Member functions // Main function used by clients of the derived FSM to make // transitions. template<class Event> int process_event(Event const& evt) { typedef typename Derived::transition_table stt; typedef dispatch_table<Derived, Derived::initial_state,stt,Event> table; // Call the action return this->m_state = table::instance.entries[this->m_state]( *static_cast<Derived*>(this), this->m_state, evt); } // Getter that returns the current state of the FSM int current_state() const { return this->m_state; } private: template <class Fsm, int initial_state, class Stt, class Event> friend class dispatch_table; template <class Event> static int call_no_transition(Derived& fsm, int state, Event const& e) { return fsm.no_transition(state, e); } // Default no-transition handler. Can be replaced in the Derived // FSM class. template <class Event> int no_transition(int state, Event const& e) { BOOST_ASSERT(false); return state; } protected: // interface for the derived class template<class State> state_machine(State state) // Construct with an initial state : m_state(state) { } state_machine() : m_state(Derived::initial_state) // Construct with the default initial_state { } // Template used to form rows in the transition table template< int CurrentState , class Event , int NextState , void (Derived::*action)(Event const&) > struct row { BOOST_STATIC_CONSTANT(int, current_state = CurrentState); BOOST_STATIC_CONSTANT(int, next_state = NextState); typedef Event event; // Take the transition action and return the next state. static int execute(Derived& fsm, int state, Event const& evt) { BOOST_ASSERT(state == current_state); (fsm.*action)(evt); return next_state; } }; private: // data members int m_state;};namespace // Concrete FSM implementation{ // events struct play {}; struct stop {}; struct pause {}; struct open_close {}; // A "complicated" event type that carries some data. struct cd_detected { cd_detected(std::string name, std::vector<std::clock_t> durations) : name(name) , track_durations(durations) {} std::string name; std::vector<std::clock_t> track_durations; }; // Concrete FSM implementation class player : public state_machine<player> { // 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 // transition actions void start_playback(play const&) { std::cout << "player::start_playback\n"; } void open_drawer(open_close const&) { std::cout << "player::open_drawer\n"; } void close_drawer(open_close const&) { std::cout << "player::close_drawer\n"; } void store_cd_info(cd_detected const&) { std::cout << "player::store_cd_info\n"; } void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; } void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; } void resume_playback(play const&) { std::cout << "player::resume_playback\n"; } void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }#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 > // +---------+-------------+---------+---------------------+ > {}; // Replaces the default no-transition response. template <class Event> int no_transition(int state, Event const& e) { std::cout << "no transition from state " << state << " on event " << typeid(e).name() << std::endl; return state; } }; // // Testing utilities. // static char const* const state_names[] = { "Empty", "Open", "Stopped", "Playing", "Paused" }; void pstate(player const& p) { std::cout << " -> " << state_names[p.current_state()] << std::endl; } void test() { player p; p.process_event(open_close()); pstate(p); p.process_event(open_close()); pstate(p); p.process_event( cd_detected( "louie, louie" , std::vector<std::clock_t>( /* track lengths */ ) ) ); pstate(p); p.process_event(play()); pstate(p); p.process_event(pause()); pstate(p); p.process_event(play()); pstate(p); p.process_event(stop()); pstate(p); }}int main(){ test(); return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?