1
0
mirror of https://git.suyu.dev/suyu/suyu synced 2025-11-06 01:49:04 -06:00

Initial commit

This commit is contained in:
Crimson-Hawk
2024-03-05 16:42:40 +08:00
commit f1e4595ebf
39576 changed files with 7006612 additions and 0 deletions

View File

@@ -0,0 +1,15 @@
# Boost.MPL Library example Jamfile
#
# Copyright (c) 2008 James E. King III
#
# Distributed under the Boost Software License, Version 1.0. (See accompany-
# ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
import testing ;
test-suite "mpl-examples"
: [ run inherit_linearly.cpp ]
[ compile integer.cpp ]
[ run tuple_from_list.cpp ]
;

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -0,0 +1,62 @@
// 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/inherit_linearly.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>
namespace mpl = boost::mpl;
using namespace mpl::placeholders;
template< typename Base, typename T >
struct tuple_part
: Base
{
typedef tuple_part type; // note the typedef
typedef typename Base::index::next index;
friend T& field(tuple_part& t, index) { return t.field_; }
T field_;
};
struct empty_tuple
{
typedef mpl::int_<-1> index;
};
typedef mpl::inherit_linearly<
mpl::list<int,char const*,bool>
, tuple_part<_,_>
, empty_tuple
>::type my_tuple;
int main()
{
my_tuple t;
field(t, mpl::int_<0>()) = -1;
field(t, mpl::int_<1>()) = "text";
field(t, mpl::int_<2>()) = false;
std::cout
<< field(t, mpl::int_<0>()) << '\n'
<< field(t, mpl::int_<1>()) << '\n'
<< field(t, mpl::int_<2>()) << '\n'
;
return 0;
}

View File

@@ -0,0 +1,58 @@
// 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/inherit.hpp>
#include <boost/mpl/inherit_linearly.hpp>
#include <boost/mpl/list.hpp>
#include <iostream>
namespace mpl = boost::mpl;
using namespace mpl::placeholders;
template< typename T >
struct tuple_field
{
typedef tuple_field type; // note the typedef
T field_;
};
template< typename T >
inline
T& field(tuple_field<T>& t)
{
return t.field_;
}
typedef mpl::inherit_linearly<
mpl::list<int,char const*,bool>
, mpl::inherit< _1, tuple_field<_2> >
>::type my_tuple;
int main()
{
my_tuple t;
field<int>(t) = -1;
field<char const*>(t) = "text";
field<bool>(t) = false;
std::cout
<< field<int>(t) << '\n'
<< field<char const*>(t) << '\n'
<< field<bool>(t) << '\n'
;
return 0;
}

View File

@@ -0,0 +1,67 @@
// Copyright Aleksey Gurtovoy 2001-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/multiplies.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/lower_bound.hpp>
#include <boost/mpl/transform_view.hpp>
#include <boost/mpl/sizeof.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/base.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_same.hpp>
namespace mpl = boost::mpl;
using namespace mpl::placeholders;
template< int bit_size >
class big_int
{
// ...
};
template< int bit_size >
struct integer
{
typedef mpl::list<char,short,int,long> builtins_;
typedef typename mpl::base< typename mpl::lower_bound<
mpl::transform_view< builtins_
, mpl::multiplies< mpl::sizeof_<_1>, mpl::int_<8> >
>
, mpl::int_<bit_size>
>::type >::type iter_;
typedef typename mpl::end<builtins_>::type last_;
typedef typename mpl::eval_if<
boost::is_same<iter_,last_>
, mpl::identity< big_int<bit_size> >
, mpl::deref<iter_>
>::type type;
};
typedef integer<1>::type int1;
typedef integer<5>::type int5;
typedef integer<15>::type int15;
typedef integer<32>::type int32;
typedef integer<100>::type int100;
BOOST_MPL_ASSERT(( boost::is_same< int1, char > ));
BOOST_MPL_ASSERT(( boost::is_same< int5, char > ));
BOOST_MPL_ASSERT(( boost::is_same< int15, short > ));
BOOST_MPL_ASSERT(( boost::is_same< int32, int > ));
BOOST_MPL_ASSERT(( boost::is_same< int100, big_int<100> > ));

View File

@@ -0,0 +1,46 @@
// 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/reverse_fold.hpp>
#include <boost/mpl/list.hpp>
#include <boost/tuple/tuple.hpp>
#include <iostream>
using namespace boost::mpl;
template< typename Types > struct tuple_gen
: reverse_fold<
Types
, boost::tuples::null_type
, boost::tuples::cons<_2,_1>
>
{
};
int main()
{
tuple_gen< list<int,char const*,bool> >::type t;
boost::get<0>(t) = -1;
boost::get<1>(t) = "text";
boost::get<2>(t) = false;
std::cout
<< boost::get<0>(t) << '\n'
<< boost::get<1>(t) << '\n'
<< boost::get<2>(t) << '\n'
;
return 0;
}