summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/mpl/example/fsm
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/mpl/example/fsm')
-rw-r--r--src/boost/libs/mpl/example/fsm/README.txt28
-rw-r--r--src/boost/libs/mpl/example/fsm/aux_/STT_impl_gen.hpp145
-rw-r--r--src/boost/libs/mpl/example/fsm/aux_/base_event.hpp59
-rw-r--r--src/boost/libs/mpl/example/fsm/aux_/event.hpp54
-rw-r--r--src/boost/libs/mpl/example/fsm/aux_/state.hpp42
-rw-r--r--src/boost/libs/mpl/example/fsm/aux_/transition.hpp47
-rw-r--r--src/boost/libs/mpl/example/fsm/player.cpp76
-rw-r--r--src/boost/libs/mpl/example/fsm/player1.cpp287
-rw-r--r--src/boost/libs/mpl/example/fsm/player2.cpp326
-rw-r--r--src/boost/libs/mpl/example/fsm/state_machine.hpp145
10 files changed, 1209 insertions, 0 deletions
diff --git a/src/boost/libs/mpl/example/fsm/README.txt b/src/boost/libs/mpl/example/fsm/README.txt
new file mode 100644
index 00000000..0f4863fe
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/README.txt
@@ -0,0 +1,28 @@
+What's In This Directory
+========================
+
+* player1.cpp - this is exactly what's covered in C++ Template
+ Metaprogramming (http://www.boost-consulting.com/mplbook); in fact,
+ it was auto-extracted from the examples as shown in the book. The
+ state machine framework and its use are together in one .cpp file;
+ normally they would be separated. You can think of the framework as
+ ending with the definition of the generate_dispatcher class
+ template.
+
+ You can ignore the typedef called "dummy;" that was included in order to
+ test an intermediate example that appears in the book.
+
+* player2.cpp - this example demonstrates that the abstraction of the
+ framework is complete by replacing its implementation with one that
+ dispatches using O(1) table lookups, while still using the same code
+ to describe the particular FSM. Look at this one if you want to see
+ how to generate a static lookup table that's initialized at dynamic
+ initialization time.
+
+* player.cpp, state_machine.hpp - This example predates the book, and
+ is more sophisticated in some ways than what we cover in the other
+ examples. In particular, it supports state invariants, and it
+ maintains an internal event queue, which requires an additional
+ layer of runtime dispatching to sort out the next event to be
+ processed.
+
diff --git a/src/boost/libs/mpl/example/fsm/aux_/STT_impl_gen.hpp b/src/boost/libs/mpl/example/fsm/aux_/STT_impl_gen.hpp
new file mode 100644
index 00000000..1fd0a5ff
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/aux_/STT_impl_gen.hpp
@@ -0,0 +1,145 @@
+
+#ifndef BOOST_FSM_HANDLER_INCLUDED
+#define BOOST_FSM_HANDLER_INCLUDED
+
+// Copyright Aleksey Gurtovoy 2002-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)
+//
+// See http://www.boost.org/libs/mpl for documentation.
+
+// $Id$
+// $Date$
+// $Revision$
+
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/fold.hpp>
+#include <boost/mpl/front.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include <typeinfo>
+#include <cassert>
+
+namespace fsm { namespace aux {
+
+namespace mpl = boost::mpl;
+using namespace mpl::placeholders;
+
+template< typename Transition >
+struct STT_void_row_impl
+{
+ typedef typename Transition::from_state_t state_t;
+ typedef typename Transition::fsm_t fsm_t;
+ typedef typename Transition::base_event_t base_event_t;
+
+ static long do_process_event(fsm_t&, long state, base_event_t const&)
+ {
+ assert(false);
+ return state;
+ }
+
+ static long do_transition(fsm_t&, long state, base_event_t const&)
+ {
+ assert(false);
+ return state;
+ }
+};
+
+
+template<
+ typename PrevRowImpl
+ , typename Transition
+ >
+struct STT_event_row_impl
+ : PrevRowImpl
+{
+ typedef typename Transition::from_state_t state_t;
+ typedef typename Transition::fsm_t fsm_t;
+ typedef typename Transition::base_event_t base_event_t;
+
+ static long do_process_event(fsm_t& fsm, long state, base_event_t const& evt)
+ {
+ if (typeid(typename Transition::event_t) == typeid(evt))
+ {
+ // typedefs are here to make GCC happy
+ typedef typename Transition::to_state_t to_state_;
+ typedef typename Transition::from_state_t from_state_;
+
+ return Transition::do_transition(fsm, evt)
+ ? to_state_::do_check_invariant(fsm)
+ : from_state_::do_check_invariant(fsm)
+ ;
+ }
+
+ return PrevRowImpl::do_process_event(fsm, state, evt);
+ }
+};
+
+template<
+ typename PrevRowImpl
+ , typename StateType
+ >
+struct STT_state_row_impl
+ : PrevRowImpl
+{
+ typedef typename PrevRowImpl::fsm_t fsm_t;
+ typedef typename PrevRowImpl::base_event_t base_event_t;
+
+ static long do_transition(fsm_t& fsm, long state, base_event_t const& evt)
+ {
+ return state == StateType::value
+ ? PrevRowImpl::do_process_event(fsm, state, evt)
+ : PrevRowImpl::do_transition(fsm, state, evt)
+ ;
+ }
+
+ static long do_process_event(fsm_t&, long state, base_event_t const&)
+ {
+ assert(false);
+ return state;
+ }
+};
+
+template<
+ typename PrevRowImpl
+ , typename Transition
+ >
+struct STT_row_impl
+{
+ typedef typename mpl::if_<
+ boost::is_same<
+ typename PrevRowImpl::state_t
+ , typename Transition::from_state_t
+ >
+ , STT_event_row_impl< PrevRowImpl,Transition >
+ , STT_event_row_impl<
+ STT_state_row_impl< PrevRowImpl,typename PrevRowImpl::state_t >
+ , Transition
+ >
+ >::type type;
+};
+
+
+template< typename Transitions >
+struct STT_impl_gen
+{
+ private:
+ typedef typename mpl::front<Transitions>::type first_;
+ typedef typename mpl::fold<
+ Transitions
+ , STT_void_row_impl<first_>
+ , STT_row_impl<_,_>
+ >::type STT_impl_;
+
+ public:
+ typedef STT_state_row_impl<
+ STT_impl_
+ , typename STT_impl_::state_t
+ > type;
+};
+
+}}
+
+#endif // BOOST_FSM_HANDLER_INCLUDED
diff --git a/src/boost/libs/mpl/example/fsm/aux_/base_event.hpp b/src/boost/libs/mpl/example/fsm/aux_/base_event.hpp
new file mode 100644
index 00000000..99df7d9d
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/aux_/base_event.hpp
@@ -0,0 +1,59 @@
+
+#ifndef BOOST_FSM_BASE_EVENT_INCLUDED
+#define BOOST_FSM_BASE_EVENT_INCLUDED
+
+// Copyright Aleksey Gurtovoy 2002-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)
+//
+// See http://www.boost.org/libs/mpl for documentation.
+
+// $Id$
+// $Date$
+// $Revision$
+
+#include <memory>
+#include <boost/config.hpp>
+
+namespace fsm { namespace aux {
+
+// represent an abstract base for FSM events
+
+struct base_event
+{
+ public:
+ virtual ~base_event() {};
+
+#if defined(BOOST_NO_CXX11_SMART_PTR)
+
+ std::auto_ptr<base_event> clone() const
+
+#else
+
+ std::unique_ptr<base_event> clone() const
+
+#endif
+
+ {
+ return do_clone();
+ }
+
+ private:
+
+#if defined(BOOST_NO_CXX11_SMART_PTR)
+
+ virtual std::auto_ptr<base_event> do_clone() const = 0;
+
+#else
+
+ virtual std::unique_ptr<base_event> do_clone() const = 0;
+
+#endif
+
+};
+
+}}
+
+#endif // BOOST_FSM_BASE_EVENT_INCLUDED
diff --git a/src/boost/libs/mpl/example/fsm/aux_/event.hpp b/src/boost/libs/mpl/example/fsm/aux_/event.hpp
new file mode 100644
index 00000000..895bd7a6
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/aux_/event.hpp
@@ -0,0 +1,54 @@
+
+#ifndef BOOST_FSM_EVENT_INCLUDED
+#define BOOST_FSM_EVENT_INCLUDED
+
+// Copyright Aleksey Gurtovoy 2002-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)
+//
+// See http://www.boost.org/libs/mpl for documentation.
+
+// $Id$
+// $Date$
+// $Revision$
+
+#include "base_event.hpp"
+
+namespace fsm { namespace aux {
+
+template< typename Derived >
+struct event
+ : base_event
+{
+ public:
+ typedef base_event base_t;
+
+ private:
+
+#if defined(BOOST_NO_CXX11_SMART_PTR)
+
+ virtual std::auto_ptr<base_event> do_clone() const
+ {
+ return std::auto_ptr<base_event>(
+ new Derived(static_cast<Derived const&>(*this))
+ );
+ }
+
+#else
+
+ virtual std::unique_ptr<base_event> do_clone() const
+ {
+ return std::unique_ptr<base_event>(
+ new Derived(static_cast<Derived const&>(*this))
+ );
+ }
+
+#endif
+
+};
+
+}}
+
+#endif // BOOST_FSM_EVENT_INCLUDED
diff --git a/src/boost/libs/mpl/example/fsm/aux_/state.hpp b/src/boost/libs/mpl/example/fsm/aux_/state.hpp
new file mode 100644
index 00000000..bbe2bbf3
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/aux_/state.hpp
@@ -0,0 +1,42 @@
+
+#ifndef BOOST_FSM_STATE_INCLUDED
+#define BOOST_FSM_STATE_INCLUDED
+
+// Copyright Aleksey Gurtovoy 2002-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)
+//
+// See http://www.boost.org/libs/mpl for documentation.
+
+// $Id$
+// $Date$
+// $Revision$
+
+#include <boost/mpl/integral_c.hpp>
+
+namespace fsm { namespace aux {
+
+namespace mpl = boost::mpl;
+
+// represent a FSM state
+
+template<
+ typename T
+ , long State
+ , void (T::* invariant_func)() const
+ >
+struct state
+ : mpl::integral_c<long,State>
+{
+ static long do_check_invariant(T const& x)
+ {
+ if (invariant_func) (x.*invariant_func)();
+ return State;
+ }
+};
+
+}}
+
+#endif // BOOST_FSM_STATE_INCLUDED
diff --git a/src/boost/libs/mpl/example/fsm/aux_/transition.hpp b/src/boost/libs/mpl/example/fsm/aux_/transition.hpp
new file mode 100644
index 00000000..842e5e08
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/aux_/transition.hpp
@@ -0,0 +1,47 @@
+
+#ifndef BOOST_FSM_TRANSITION_INCLUDED
+#define BOOST_FSM_TRANSITION_INCLUDED
+
+// Copyright Aleksey Gurtovoy 2002-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)
+//
+// See http://www.boost.org/libs/mpl for documentation.
+
+// $Id$
+// $Date$
+// $Revision$
+
+#include <cassert>
+
+namespace fsm { namespace aux {
+
+// represent a signle transition between states |From| and |To|
+
+template<
+ typename T
+ , typename From
+ , typename Event
+ , typename To
+ , bool (T::* transition_func)(Event const&)
+ >
+struct transition
+{
+ typedef T fsm_t;
+ typedef From from_state_t;
+ typedef Event event_t;
+ typedef To to_state_t;
+
+ typedef typename Event::base_t base_event_t;
+ static bool do_transition(T& x, base_event_t const& e)
+ {
+ assert(dynamic_cast<event_t const*>(&e) == &e);
+ return (x.*transition_func)(static_cast<event_t const &>(e));
+ }
+};
+
+}}
+
+#endif // BOOST_FSM_TRANSITION_INCLUDED
diff --git a/src/boost/libs/mpl/example/fsm/player.cpp b/src/boost/libs/mpl/example/fsm/player.cpp
new file mode 100644
index 00000000..c3a5a124
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/player.cpp
@@ -0,0 +1,76 @@
+
+// Copyright Aleksey Gurtovoy 2002-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)
+//
+// See http://www.boost.org/libs/mpl for documentation.
+
+// $Id$
+// $Date$
+// $Revision$
+
+#include "state_machine.hpp"
+#include <boost/mpl/list.hpp>
+
+#include <iostream>
+
+namespace mpl = boost::mpl;
+
+class player
+ : public fsm::state_machine<player>
+{
+ public:
+ player() {}
+
+ // events
+ struct play_event : event<play_event> {};
+ struct stop_event : event<stop_event> {};
+ struct pause_event : event<pause_event> {};
+
+// MWCW 8.1 is too eager in inforcing access for non-type template parameters
+// private:
+ typedef player self_t;
+
+ // state invariants
+ void stopped_state_invariant() const {}
+ void playing_state_invariant() const {}
+ void paused_state_invariant() const {}
+
+ // states (invariants are passed as non-type template arguments)
+ typedef state<0, &self_t::stopped_state_invariant> stopped;
+ typedef state<1, &self_t::playing_state_invariant> playing;
+ typedef state<2, &self_t::paused_state_invariant> paused;
+
+// private:
+
+ // transition functions
+ bool do_play(play_event const&) { std::cout << "player::do_play\n"; return true; }
+ bool do_stop(stop_event const&) { std::cout << "player::do_stop\n"; return true; }
+ bool do_pause(pause_event const&) { std::cout << "player::do_pause\n"; return true; }
+ bool do_resume(play_event const&) { std::cout << "player::do_resume\n"; return true; }
+
+ // transitions, in the following format:
+ // | current state | event | next state | transition function |
+ friend class fsm::state_machine<player>;
+ typedef mpl::list<
+ transition<stopped, play_event, playing, &player::do_play>
+ , transition<playing, stop_event, stopped, &player::do_stop>
+ , transition<playing, pause_event, paused, &player::do_pause>
+ , transition<paused, play_event, playing, &player::do_resume>
+ , transition<paused, stop_event, stopped, &player::do_stop>
+ >::type transition_table;
+
+ typedef stopped initial_state;
+};
+
+int main()
+{
+ player p;
+ p.process_event(player::play_event());
+ p.process_event(player::pause_event());
+ p.process_event(player::play_event());
+ p.process_event(player::stop_event());
+ return 0;
+}
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;
+}
diff --git a/src/boost/libs/mpl/example/fsm/player2.cpp b/src/boost/libs/mpl/example/fsm/player2.cpp
new file mode 100644
index 00000000..8704ef5d
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/player2.cpp
@@ -0,0 +1,326 @@
+//
+// 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 < 310
+namespace std { using ::clock_t; }
+#endif
+
+namespace 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;
+}
diff --git a/src/boost/libs/mpl/example/fsm/state_machine.hpp b/src/boost/libs/mpl/example/fsm/state_machine.hpp
new file mode 100644
index 00000000..4bfd0169
--- /dev/null
+++ b/src/boost/libs/mpl/example/fsm/state_machine.hpp
@@ -0,0 +1,145 @@
+
+#ifndef BOOST_FSM_STATE_MACHINE_INCLUDED
+#define BOOST_FSM_STATE_MACHINE_INCLUDED
+
+// Copyright Aleksey Gurtovoy 2002-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)
+//
+// See http://www.boost.org/libs/mpl for documentation.
+
+// $Id$
+// $Date$
+// $Revision$
+
+#include "aux_/event.hpp"
+#include "aux_/state.hpp"
+#include "aux_/transition.hpp"
+#include "aux_/STT_impl_gen.hpp"
+#include <boost/shared_ptr.hpp>
+
+#include <queue>
+#include <memory>
+#include <cassert>
+
+namespace fsm {
+
+template< typename Derived >
+class state_machine
+{
+ private:
+ typedef state_machine self_t;
+ typedef aux::base_event base_event_t;
+ typedef boost::shared_ptr<base_event_t const> base_event_ptr_t;
+
+ public:
+ typedef long state_t;
+ typedef void (Derived::* invariant_func_t)() const;
+
+ template< typename DerivedEvent >
+ struct event
+ : aux::event<DerivedEvent>
+ {
+ };
+
+ void process_event(base_event_t const& evt)
+ {
+ // all internal events should be handled at this point
+ assert(!m_events_queue.size());
+
+ // process the external event passed
+ do_transition(evt);
+
+ // if the previous transition generated any internal events,
+ // process those
+ while (m_events_queue.size())
+ {
+ do_transition(*m_events_queue.front());
+ m_events_queue.pop();
+ }
+ }
+
+ state_t current_state() const
+ {
+ return m_state;
+ }
+
+ protected:
+ // interface for the derived class
+
+ state_machine(state_t const& initial_state)
+ : m_state(initial_state)
+ {
+ }
+
+ state_machine()
+ : m_state(typename Derived::initial_state())
+ {
+ }
+
+ virtual ~state_machine()
+ {
+ }
+
+
+#if defined(BOOST_NO_CXX11_SMART_PTR)
+
+ void post_event(std::auto_ptr<base_event_t const> evt)
+
+#else
+
+ void post_event(std::unique_ptr<base_event_t const> evt)
+
+#endif
+
+ {
+ m_events_queue.push(base_event_ptr_t(evt.release()));
+ }
+
+ template<
+ long State
+#if !defined(BOOST_INTEL_CXX_VERSION) && (!defined(__GNUC__) || __GNUC__ >= 3)
+ , invariant_func_t f = static_cast<invariant_func_t>(0)
+#else
+ , invariant_func_t f = 0
+#endif
+ >
+ struct state
+ : fsm::aux::state<Derived,State,f>
+ {
+ };
+
+ template<
+ typename From
+ , typename Event
+ , typename To
+ , bool (Derived::* transition_func)(Event const&)
+ >
+ struct transition
+ : aux::transition< Derived,From,Event,To,transition_func >
+ {
+ };
+
+ private:
+
+ void do_transition(base_event_t const& evt)
+ {
+ typedef typename Derived::transition_table STT_;
+ typedef typename aux::STT_impl_gen< STT_ >::type STT_impl_;
+
+ m_state = STT_impl_::do_transition(
+ static_cast<Derived&>(*this)
+ , m_state
+ , evt
+ );
+ }
+
+ state_t m_state;
+ std::queue< base_event_ptr_t > m_events_queue;
+};
+
+} // namespace fsm
+
+#endif // BOOST_FSM_STATE_MACHINE_INCLUDED