BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Building upon my version of the solution to 11-0, and using this for my
transition table structure:
// +-----------+--------------------+----------------+------------------------+
// | Start | EntryAction | ExitAction | |
// | | Event1 | Next1 | Action1 |
// | | Event2 | Next2 | Action2 |
// +-----------+--------------------+----------------+------------------------+
Here's the code. Comments or simplifications appreciated!
#include <boost/mpl/vector.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/filter_view.hpp>
#include <boost/mpl/placeholders.hpp>
#include <cassert>
#include <ctime>
#include <vector>
#include <iostream>
namespace mpl = boost::mpl;
using namespace mpl::placeholders;
template<class StateEntry, class Next>
struct on_exit_dispatcher
{
typedef typename StateEntry::fsm_t fsm_t;
static void dispatch_on_exit(fsm_t &m, int state)
{
if (state == StateEntry::current_state)
{
StateEntry::on_exit(m);
}
else
{
Next::dispatch_on_exit(m, state);
}
}
};
template<class StateEntry, class Next>
struct on_entry_dispatcher
{
typedef typename StateEntry::fsm_t fsm_t;
static void dispatch_on_entry(fsm_t &m, int state)
{
if (state == StateEntry::current_state)
{
StateEntry::on_entry(m);
}
else
{
Next::dispatch_on_entry(m, state);
}
}
};
template <class OnEventEntry>
struct on_event_entry_event
{
typedef typename OnEventEntry::event type;
};
template<class StateEntry, class Next, class Event>
struct event_dispatcher
{
typedef typename StateEntry::event_vector event_vector;
typedef typename mpl::find_if<event_vector,
boost::is_same<Event, on_event_entry_event<_1> > >::type event_entry_iter;
typedef typename mpl::deref<event_entry_iter>::type event_entry;
typedef typename event_entry::fsm_t fsm_t;
static int dispatch_execute(fsm_t &m, int state, Event const &e)
{
if (state == StateEntry::current_state)
{
event_entry::execute(m, e);
return event_entry::next_state;
}
else
{
return Next::dispatch_execute(m, state, e);
}
}
};
template <class MyDerivedFSM> class state_machine;
struct default_event_dispatcher
{
template <class FSM, class Event>
static int dispatch_execute(state_machine<FSM> &m, int state, Event const &e)
{
return m.call_no_transition(state, e);
}
};
struct default_on_entry_dispatcher
{
template <class FSM>
static void dispatch_on_entry (state_machine<FSM> &m, int state)
{}
};
struct default_on_exit_dispatcher
{
template <class FSM>
static void dispatch_on_exit (state_machine<FSM> &m, int state)
{}
};
template <class StateEntry, class Event>
struct has_event_entry
{
typedef typename StateEntry::event_vector event_vector;
typedef typename mpl::find_if<event_vector,
boost::is_same<Event, on_event_entry_event<_1> > >::type event_entry_iter;
typedef typename boost::is_same<event_entry_iter,
typename mpl::end<event_vector>::type>::type iter_is_end;
typedef typename boost::is_same<boost::false_type, iter_is_end>::type type;
};
template <class Table, class Event>
struct generate_event_dispatcher
: mpl::fold<
mpl::filter_view<
Table,
has_event_entry<_1, Event>
>,
default_event_dispatcher,
event_dispatcher<_2, _1, Event>
>
{};
template <class Table>
struct generate_on_entry_dispatcher
: mpl::fold<
Table,
default_on_entry_dispatcher,
on_entry_dispatcher<_2, _1>
>
{};
template <class Table>
struct generate_on_exit_dispatcher
: mpl::fold<
Table,
default_on_exit_dispatcher,
on_exit_dispatcher<_2, _1>
>
{};
template <class MyDerivedFSM>
class state_machine
{
public:
template <class Event>
int process_event (Event const &e)
{
typedef typename generate_event_dispatcher<
typename MyDerivedFSM::transition_table, Event>::type event_dispatcher;
typedef typename generate_on_entry_dispatcher<
typename MyDerivedFSM::transition_table>::type on_entry_dispatcher;
typedef typename generate_on_exit_dispatcher<
typename MyDerivedFSM::transition_table>::type on_exit_dispatcher;
int newState = event_dispatcher::dispatch_execute(
*static_cast<MyDerivedFSM*>(this), this->state_, e);
if (newState != this->state_)
{
on_exit_dispatcher::dispatch_on_exit(
*static_cast<MyDerivedFSM*>(this), this->state_);
this->state_ = newState;
on_entry_dispatcher::dispatch_on_entry(
*static_cast<MyDerivedFSM*>(this), this->state_);
}
return this->state_;
}
template <class Event>
int no_transition (int state, Event const &e)
{
assert(false);
return state;
}
template <class Event>
int call_no_transition (int state, Event const &e)
{
return static_cast<MyDerivedFSM*>(this)->no_transition(state, e);
}
protected:
state_machine ()
: state_(MyDerivedFSM::initial_state)
{
}
~state_machine ()
{
}
template < class Event,
int NextState,
void (MyDerivedFSM::*Action)(Event const&)
>
struct on_event
{
static int const next_state = NextState;
typedef Event event;
typedef MyDerivedFSM fsm_t;
static void execute (MyDerivedFSM &fsm, Event const &e)
{
(fsm.*Action)(e);
}
};
template < int CurrentState,
void (MyDerivedFSM::*EntryAction)(),
void (MyDerivedFSM::*ExitAction)(),
class VectorOfEvents
>
struct in_state
{
static int const current_state = CurrentState;
typedef VectorOfEvents event_vector;
typedef MyDerivedFSM fsm_t;
static void on_entry (MyDerivedFSM &fsm)
{
if (EntryAction != 0)
{
(fsm.*EntryAction)();
}
}
static void on_exit (MyDerivedFSM &fsm)
{
if (ExitAction != 0)
{
(fsm.*ExitAction)();
}
}
};
int state_;
};
class Player :
public state_machine<Player>
{
public:
Player(){}
~Player(){}
//Events
struct Play {};
struct OpenClose {};
struct CDDetected
{
CDDetected(char const*, std::vector<std::clock_t> const&) {}
};
struct Stop {};
struct Pause {};
private:
//FSM states
enum states
{
Empty,
Open,
Stopped,
Playing,
Paused,
initial_state=Empty
};
//FSM Transition actions
void start_playback(Play const&);
void open_drawer(OpenClose const&);
void close_drawer(OpenClose const&);
void store_cd_info(CDDetected const &);
void stop_playback(Stop const&);
void pause_playback(Pause const &);
void resume_playback(Play const&);
void stop_and_open(OpenClose const &);
void detect_cd_info();
void state_entry();
void state_exit();
friend class state_machine<Player>;
typedef Player p;
struct transition_table : mpl::vector5<
// +-----------+--------------------+----------------+------------------------+
// | Start | EntryAction | ExitAction | |
// | | Event1 | Next1 | Action1 |
// | | Event2 | Next2 | Action2 |
// +-----------+--------------------+----------------+------------------------+
in_state< Stopped , &p::state_entry , &p::state_exit , mpl::vector2<
on_event< Play , Playing , &p::start_playback >,
on_event< OpenClose , Open , &p::open_drawer > > >,
// +-----------+--------------------+----------------+--------------------+---+
in_state< Open , &p::state_entry , &p::state_exit , mpl::vector1<
on_event< OpenClose , Empty , &p::close_drawer > > >,
// +-----------+--------------------+----------------+--------------------+---+
in_state< Empty , &p::detect_cd_info , &p::state_exit , mpl::vector2<
on_event< OpenClose , Open , &p::open_drawer >,
on_event< CDDetected , Stopped , &p::store_cd_info > > >,
// +-----------+--------------------+----------------+--------------------+---+
in_state< Playing , &p::state_entry , &p::state_exit , mpl::vector3<
on_event< Pause , Paused , &p::pause_playback >,
on_event< Stop , Stopped , &p::stop_playback >,
on_event< OpenClose , Open , &p::stop_and_open > > >,
// +-----------+--------------------+----------------+--------------------+---+
in_state< Paused , 0 , 0 , mpl::vector3<
on_event< Play , Playing , &p::resume_playback>,
on_event< Stop , Stopped , &p::stop_playback >,
on_event< OpenClose , Open , &p::stop_and_open > > >
// +-----------+--------------------+----------------+--------------------+---+
> {};
};
inline void
Player::start_playback (Play const&)
{
std::cout << "Starting playback" << std::endl;
}
inline void
Player::open_drawer (OpenClose const&)
{
std::cout << "Opening drawer" << std::endl;
}
inline void
Player::close_drawer (OpenClose const&)
{
std::cout << "Closing drawer" << std::endl;
}
inline void
Player::store_cd_info (CDDetected const&)
{
std::cout << "Storing CD Info" << std::endl;
}
inline void
Player::stop_playback (Stop const&)
{
std::cout << "Stopping playback" << std::endl;
}
inline void
Player::pause_playback (Pause const&)
{
std::cout << "Pausing playback" << std::endl;
}
inline void
Player::resume_playback (Play const&)
{
std::cout << "Resuming playback" << std::endl;
}
inline void
Player::stop_and_open (OpenClose const&)
{
std::cout << "Stopping playback, opening drawer" << std::endl;
}
inline void
Player:: state_entry ()
{
std::cout << "Entering state: " << this->state_ << std::endl;
}
inline void
Player:: state_exit ()
{
std::cout << "Leaving state: " << this->state_ << std::endl;
}
inline void
Player:: detect_cd_info ()
{
std::cout << "Detecting CD info (in state: " << this->state_ << ")" << std::endl;
process_event(CDDetected("louie, louie", std::vector<std::clock_t>()));
}
int main(int argc, char* argv[])
{
Player p;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::Play());
std::cout << "---------------------" << std::endl;
p.process_event(Player::Pause());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::Play());
std::cout << "---------------------" << std::endl;
p.process_event(Player::Stop());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::Play());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::OpenClose());
std::cout << "---------------------" << std::endl;
p.process_event(Player::Play());
std::cout << "---------------------" << std::endl;
p.process_event(Player::Stop());
std::cout << "---------------------" << std::endl;
int c;
std::cin >> c;
return 0;
}
Disclaimer: This site not officially maintained by Boost Developers