|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r62129 - in trunk/libs/msm: . doc doc/HTML doc/HTML/examples doc/HTML/examples/distributed_table doc/HTML/examples/iPod_distributed doc/PDF doc/PDF/examples doc/PDF/examples/distributed_table doc/PDF/examples/iPod_distributed doc/images doc/src
From: christophe.j.henry_at_[hidden]
Date: 2010-05-21 17:15:54
Author: chenry
Date: 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
New Revision: 62129
URL: http://svn.boost.org/trac/boost/changeset/62129
Log:
msm added to trunk
Added:
trunk/libs/msm/
trunk/libs/msm/doc/
trunk/libs/msm/doc/HTML/
trunk/libs/msm/doc/HTML/ar01s02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ar01s03.html (contents, props changed)
trunk/libs/msm/doc/HTML/ar01s04.html (contents, props changed)
trunk/libs/msm/doc/HTML/ar01s05.html (contents, props changed)
trunk/libs/msm/doc/HTML/ar01s06.html (contents, props changed)
trunk/libs/msm/doc/HTML/ar01s07.html (contents, props changed)
trunk/libs/msm/doc/HTML/ar01s08.html (contents, props changed)
trunk/libs/msm/doc/HTML/ar01s09.html (contents, props changed)
trunk/libs/msm/doc/HTML/boost.css (contents, props changed)
trunk/libs/msm/doc/HTML/boostbook.css (contents, props changed)
trunk/libs/msm/doc/HTML/ch01.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch02s02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch02s03.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch03.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch03s02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch03s03.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch03s04.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch03s05.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch04.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch04s02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch04s03.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch04s04.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch04s05.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch05.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch06.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch06s02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch06s03.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch06s04.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch07.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch07s02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch08.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch08s02.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch08s03.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch09.html (contents, props changed)
trunk/libs/msm/doc/HTML/ch10.html (contents, props changed)
trunk/libs/msm/doc/HTML/docutils.css (contents, props changed)
trunk/libs/msm/doc/HTML/examples/
trunk/libs/msm/doc/HTML/examples/AnonymousTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/AnonymousTutorialEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/AnonymousTutorialWithFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/BoostCon09Full.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/CompilerStressTestEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/CompositeTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/CompositeTutorialEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/DirectEntryEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/DirectEntryTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/EumlInternal.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/EumlInternalDistributed.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/EumlSimple.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/Flags.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/History.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/HistoryEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/MsmComposite.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/MsmSimple.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/MsmSimpleFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/Orthogonal-deferred.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/Orthogonal-deferred2.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/OrthogonalDeferredEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/OrthogonalDeferredEuml2.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/ParsingDigits.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SC Composite.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SC Simple.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SM-2Arg.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTimer.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTutorial2.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTutorialEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTutorialEuml2.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternal.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternal2.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternalFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors2.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors3.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/TestInternal.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/char_event_dispatcher.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/distributed_table/
trunk/libs/msm/doc/HTML/examples/distributed_table/DistributedTable.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/distributed_table/Empty.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/distributed_table/Empty.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/distributed_table/Events.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/distributed_table/Open.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/distributed_table/Open.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPodEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPodSearch.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPodSearchEuml.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPod_distributed/
trunk/libs/msm/doc/HTML/examples/iPod_distributed/Events.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPod_distributed/MenuMode.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPod_distributed/MenuMode.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPod_distributed/PlayingMode.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPod_distributed/PlayingMode.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/iPod_distributed/iPod.cpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/ipod_functors.hpp (contents, props changed)
trunk/libs/msm/doc/HTML/examples/logging_functors.h (contents, props changed)
trunk/libs/msm/doc/HTML/index.html (contents, props changed)
trunk/libs/msm/doc/HTML/minimal.css (contents, props changed)
trunk/libs/msm/doc/HTML/pr01.html (contents, props changed)
trunk/libs/msm/doc/HTML/pt01.html (contents, props changed)
trunk/libs/msm/doc/HTML/pt02.html (contents, props changed)
trunk/libs/msm/doc/HTML/re01.html (contents, props changed)
trunk/libs/msm/doc/HTML/re02.html (contents, props changed)
trunk/libs/msm/doc/HTML/re03.html (contents, props changed)
trunk/libs/msm/doc/HTML/reference.css (contents, props changed)
trunk/libs/msm/doc/HTML/rn01.html (contents, props changed)
trunk/libs/msm/doc/HTML/rn01re01.html (contents, props changed)
trunk/libs/msm/doc/PDF/
trunk/libs/msm/doc/PDF/examples/
trunk/libs/msm/doc/PDF/examples/AnonymousTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/AnonymousTutorialEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/AnonymousTutorialWithFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/BoostCon09Full.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/CompilerStressTestEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/CompositeTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/CompositeTutorialEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/DirectEntryEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/DirectEntryTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/EumlInternal.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/EumlInternalDistributed.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/EumlSimple.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/Flags.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/History.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/HistoryEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/MsmComposite.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/MsmSimple.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/MsmSimpleFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/Orthogonal-deferred.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/Orthogonal-deferred2.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/OrthogonalDeferredEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/OrthogonalDeferredEuml2.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/ParsingDigits.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SC Composite.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SC Simple.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SM-2Arg.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTimer.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTutorial.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTutorial2.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTutorialEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTutorialEuml2.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternal.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternal2.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternalFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors2.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors3.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/TestInternal.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/char_event_dispatcher.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/distributed_table/
trunk/libs/msm/doc/PDF/examples/distributed_table/DistributedTable.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/distributed_table/Empty.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/distributed_table/Empty.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/distributed_table/Events.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/distributed_table/Open.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/distributed_table/Open.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPodEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPodSearch.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPodSearchEuml.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPod_distributed/
trunk/libs/msm/doc/PDF/examples/iPod_distributed/Events.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPod_distributed/MenuMode.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPod_distributed/MenuMode.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPod_distributed/PlayingMode.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPod_distributed/PlayingMode.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/iPod_distributed/iPod.cpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/ipod_functors.hpp (contents, props changed)
trunk/libs/msm/doc/PDF/examples/logging_functors.h (contents, props changed)
trunk/libs/msm/doc/PDF/msm.pdf (contents, props changed)
trunk/libs/msm/doc/images/
trunk/libs/msm/doc/images/AnnexA.jpg (contents, props changed)
trunk/libs/msm/doc/images/Anonymous.jpg (contents, props changed)
trunk/libs/msm/doc/images/CompositeTutorial.jpg (contents, props changed)
trunk/libs/msm/doc/images/FlagsTutorial.jpg (contents, props changed)
trunk/libs/msm/doc/images/HistoryTutorial.jpg (contents, props changed)
trunk/libs/msm/doc/images/Orthogonal-deferred.jpg (contents, props changed)
trunk/libs/msm/doc/images/ParsingDigits.jpg (contents, props changed)
trunk/libs/msm/doc/images/SimpleTutorial.jpg (contents, props changed)
trunk/libs/msm/doc/images/completion.gif (contents, props changed)
trunk/libs/msm/doc/images/conflict1.gif (contents, props changed)
trunk/libs/msm/doc/images/conflict2.gif (contents, props changed)
trunk/libs/msm/doc/images/entry tutorial.jpg (contents, props changed)
trunk/libs/msm/doc/images/entry_point.gif (contents, props changed)
trunk/libs/msm/doc/images/error_no_regions.jpg (contents, props changed)
trunk/libs/msm/doc/images/exit.gif (contents, props changed)
trunk/libs/msm/doc/images/explicit.gif (contents, props changed)
trunk/libs/msm/doc/images/fork.gif (contents, props changed)
trunk/libs/msm/doc/images/history.gif (contents, props changed)
trunk/libs/msm/doc/images/init_state.gif (contents, props changed)
trunk/libs/msm/doc/images/regions.gif (contents, props changed)
trunk/libs/msm/doc/images/sm.gif (contents, props changed)
trunk/libs/msm/doc/images/state.gif (contents, props changed)
trunk/libs/msm/doc/images/terminate.gif (contents, props changed)
trunk/libs/msm/doc/images/transition.jpg (contents, props changed)
trunk/libs/msm/doc/src/
trunk/libs/msm/doc/src/msm.xml (contents, props changed)
Added: trunk/libs/msm/doc/HTML/ar01s02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,20 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Founding idea</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="index.html" title="Meta State Machine (MSM)"><link rel="next" href="ar01s03.html" title="UML Short Guide"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Founding idea</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s03.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Founding idea"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e99"></a>Founding idea</h2></div></div></div><p>Let's start with an example taken
from the C++ Template Metaprogramming book:</p><p>
+ <code class="code">class player : public state_machine<player></code></p><p><code class="code">{ </code></p><p><code class="code">// The list of FSM states enum states { Empty, Open, Stopped, Playing, Paused ,
+ initial_state = Empty }; </code></p><p><code class="code">// transition actions void start_playback(play const&) { std::cout <<
+ "player::start_playback\n"; } </code></p><p><code class="code">void open_drawer(open_close const&) { std::cout <<
+ "player::open_drawer\n"; } </code></p><p><code class="code">void close_drawer(open_close const&) { std::cout <<
+ "player::close_drawer\n"; } </code></p><p><code class="code">void store_cd_info(cd_detected const&) { std::cout <<
+ "player::store_cd_info\n"; } </code></p><p><code class="code">void stop_playback(stop const&) { std::cout <<
+ "player::stop_playback\n"; } </code></p><p><code class="code">void pause_playback(pause const&) { std::cout <<
+ "player::pause_playback\n"; } </code></p><p><code class="code">void resume_playback(play const&) { std::cout <<
+ "player::resume_playback\n"; } </code></p><p><code class="code">void stop_and_open(open_close const&) { std::cout <<
+ "player::stop_and_open\n"; } </code></p><p><code class="code">friend class state_machine<player>; </code></p><p><code class="code">typedef player p; // makes transition table cleaner </code></p><p><code class="code">// Transition table </code></p><p><code class="code">struct transition_table : mpl::vector11< </code></p><p><code class="code">row < Stopped , play , Playing , &p::start_playback >, </code></p><p><code class="code">row < Stopped , open_close , Open , &p::open_drawer >, </code></p><p><code class="code">row < Open , open_close , Empty , &p::close_drawer >, </code></p><p><code class="code">row < Empty , open_close , Open , &p::open_drawer >, </code></p><p><code class="code">row < Empty , cd_detected , Stopped , &p::store_cd_info >, </code></p><p><code class="code">row < Playing , stop , Stopped , &p::stop_playback >, </code></p><p><code class="code">row < Playing , pause , Paused , &p::pause_playback >, <
/code></p><p><code class="code">row < Playing , open_close , Open , &p::stop_and_open >, </code></p><p><code class="code">row < Paused , play , Playing , &p::resume_playback >, </code></p><p><code class="code">row < Paused , stop , Stopped , &p::stop_playback >, </code></p><p><code class="code">row < Paused , open_close , Open , &p::stop_and_open > </code></p><p><code class="code">> {}; </code></p><p><code class="code">// Replaces the default no-transition response. </code></p><p><code class="code">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; } };</code>
+ </p><p><code class="code">void test() { player p; p.process_event(open_close());...}</code></p><p>This example is the foundation for the idea driving MSM: a descriptive and expressive
+ language based on a transition table with as little syntactic noise as possible, all
+ this while offering as many features from the UML 2.0 standard as possible. MSM also
+ offers several expressive state machine definition syntaxes with different
+ trade-offs.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Meta State Machine (MSM) </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> UML Short Guide</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ar01s03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,122 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>UML Short Guide</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="ar01s02.html" title="Founding idea"><link rel="next" href="ar01s04.html" title="User's Guide"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">UML Short Guide</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s04.html">Next</a></td></tr></table><hr></div><div class="sect1" title="UML Short Guide"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e198"></a>UML Short Guide</h2></div></div></div><div class="sect2" title="What are st
ate machines?"><div class="titlepage"><div><div><h3 class="title"><a name="d0e201"></a>What are state machines?</h3></div></div></div><p>State machines are the description of the lifeline of a thing. They describe the
+ different stages of the lifeline, the events influencing it, and what it does when a
+ particular event is detected at a particular stage. They offer the complete
+ specification of the dynamic behavior of the thing.</p></div><div class="sect2" title="Concepts"><div class="titlepage"><div><div><h3 class="title"><a name="d0e206"></a>Concepts</h3></div></div></div><div class="sect3" title="State machine, state, transition, event"><div class="titlepage"><div><div><h4 class="title"><a name="d0e209"></a>State machine, state, transition, event </h4></div></div></div><p>Thinking in terms of state machines is a bit surprising at first, so let us
+ have a quick glance at the concepts.</p><p>A state machine is a concrete model describing the behavior of a system. It is
+ composed of a finite number of states and transitions.</p><p>
+ <span class="inlinemediaobject"><img src="../images/sm.gif"></span></p><p>A simple state has no sub states. It can have data, entry and exit behaviors
+ and deferrable events. One can add entry and exit conditions to states (or state
+ machines), which are executed whenever a state is entered or left, no matter
+ how. A state can also have internal transitions which cause no entry or exit
+ action to be called. A state can mark events as deferred. This means the event
+ cannot be processed if this state is active, but it must be retained. Next time
+ a state not deferring this event is active, the event will be processed, as if
+ it had just been detected. </p><p><span class="inlinemediaobject"><img src="../images/state.gif"></span></p><p>A transition is the switching between active states, triggered by an event.
+ Actions and guard conditions can be attached to the transition. The action is
+ executes when the transition fires, the guard is a Boolean operation executed
+ first and which can prevent the transition from firing if returning
+ false.</p><p>
+ <span class="inlinemediaobject"><img src="../images/transition.jpg"></span></p><p>An initial state marks the first active state of a state machine. It has no
+ real existence and neither has the transition originating from it.</p><p>
+ <span class="inlinemediaobject"><img src="../images/init_state.gif"></span></p></div><div class="sect3" title="Submachines, orthogonal regions, pseudostates"><div class="titlepage"><div><div><h4 class="title"><a name="d0e241"></a>Submachines, orthogonal regions, pseudostates </h4></div></div></div><p>A composite state is a state containing a region or decomposed in two or more
+ regions. A composite state contains its own set of states and regions. </p><p>A submachine is a state machine inserted as a state in another state machine.
+ The same state machine can be inserted more than once. </p><p>Orthogonal regions are parts of a composite state or submachine, each having
+ its own set of mutually exclusive set of states and transitions. </p><p><span class="inlinemediaobject"><img src="../images/regions.gif"></span></p><p>UML also defines a number of pseudo states, which are considered important
+ concepts to model, but not enough to make them first-class citizens. The
+ terminate pseudo state terminates the execution of a state machine (MSM handles
+ this slightly differently. The state machine is not destroyed but no further
+ event processing occurs.). </p><p><span class="inlinemediaobject"><img src="../images/terminate.gif"></span></p><p>An exit point pseudo state exits a composite state or a submachine and forces
+ termination of execution in all contained regions.</p><p><span class="inlinemediaobject"><img src="../images/exit.gif"></span></p><p>An entry point pseudo state allows a kind of controlled entry inside a
+ composite. Precisely, it connects a transition outside the composite to a
+ transition inside the composite. An important point is that this mechanism only
+ allows a single region to be entered. In the above diagram, in region1, the
+ initial state would become active. </p><p><span class="inlinemediaobject"><img src="../images/entry_point.gif"></span></p><p>There are also two more ways to enter a composite state (apart the obvious and
+ more common case of a transition terminating on the composite as shown in the
+ region case). An explicit entry means that an inside state is the target of a
+ transition. Unlike with direct entry, no tentative encapsulation is made, and
+ only one transition is executed. Needless to say, I would not recommend using
+ this. </p><p><span class="inlinemediaobject"><img src="../images/explicit.gif"></span></p><p>The last entry possibility is using fork. A fork is an explicit entry into one
+ or more regions. Other regions are again activated using their initial state. </p><p><span class="inlinemediaobject"><img src="../images/fork.gif"></span></p></div><div class="sect3" title="History"><div class="titlepage"><div><div><h4 class="title"><a name="d0e284"></a>
+ <span class="command"><strong><a name="uml-history"></a></strong></span>History </h4></div></div></div><p>UML defines two sorts of history, shallow history and deep history. Shallow
+ history is a pseudo state representing the most recent substate of a composite
+ or submachine. A composite can have at most one shallow history. A transition
+ with a history pseudo state as target is equivalent to a transition with the
+ most recent substate as target. And very importantly, only one transition may
+ originate from the history. Deep history is a shallow history recursively
+ reactivating the substates of the most recent substate. It is represented like
+ the shallow history with a star (H* inside a circle).</p><p>
+ <span class="inlinemediaobject"><img src="../images/history.gif"></span></p><p>History is not a completely satisfying concept. First of all, there can be
+ just one history pseudo state and only one transition may originate from it. So
+ they do not mix well with orthogonal regions as only one region can be
+ “remembered”. Deep history is even worse and looks like a last-minute addition.
+ History has to be activated by a transition and only one transition originates
+ from it, so how to model the transition originating from the deep history pseudo
+ state and pointing to the most recent substate of the substate? As a bonus, it
+ is also inflexible and does not accept new types of histories. Let's face it,
+ history sounds great and is useful in theory, but the UML version is not quite
+ making the cut. And therefore, MSM provides a different version of it. </p></div><div class="sect3" title="Completion events / anonymous transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e298"></a><span class="command"><strong><a name="uml-anonymous"></a></strong></span>Completion events / anonymous
+ transitions</h4></div></div></div><p>Completion events, also called anonymous transitions, are defined as
+ transitions having no defined event triggering them. This means that such
+ transitions will immediately fire when a state being the source of an anonymous
+ transition becomes active, provided that a guard allows it. They are useful in
+ modeling algorithms as an activity diagram would normally do. In the real-time
+ world, they have the advantage of being able to estimate how long a periodically
+ executed action will last. For example, consider the following diagram. </p><p><span class="inlinemediaobject"><img src="../images/completion.gif"></span></p><p>The designer now knows at any time that he will need a maximum of 4
+ transitions. Being able to estimate how long a transition takes, he can estimate
+ how much of a time frame he will need to require (real-time applications are
+ often executed at regular intervals). If he can also estimate the duration of
+ actions, he can even use graph algorithms to better estimate his timing
+ requirements. </p></div><div class="sect3" title="Internal transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e310"></a><span class="command"><strong><a name="UML-internal-transition"></a></strong></span> Internal transitions </h4></div></div></div><p>Internal transitions are transitions executing in the scope of the active
+ state, being a simple state or a submachine. One can see them as a
+ self-transition of this state, without an entry or exit action called.</p></div><div class="sect3" title="Conflicting transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e316"></a>
+ <span class="command"><strong><a name="transition-conflict"></a></strong></span>Conflicting transitions </h4></div></div></div><p>If, for a given event, several transitions are enabled, they are said to be in
+ conflict. There are two kinds of conflicts: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>For a given source state, several transitions are defined,
+ triggered by the same event. Normally, the guard condition in each
+ transition defines which one is fired.</p></li><li class="listitem"><p>The source state is a submachine or simple state and the conflict
+ is between a transition internal to this state and a transition
+ triggered by the same event and having as target another
+ state.</p></li></ul></div><p>The first one is simple; one only needs to define two or more
+ rows in the transition table, with the same source and trigger, with a different
+ guard condition. Beware, however, that the UML standard wants these conditions
+ to be not overlapping. If they do, the standard says nothing except that this is
+ incorrect, so the implementer is free to implement it the way he sees fit. In
+ the case of MSM, the transition appearing last in the transition table gets
+ selected first, if it returns false (meaning disabled), the library tries with
+ the previous one, and so on.</p><p>
+ <span class="inlinemediaobject"><img src="../images/conflict1.gif"></span></p><p>In the second case, UML defines that the most inner transition gets selected
+ first, which makes sense, otherwise no exit point pseudo state would be possible
+ (the inner transition brings us to the exit point, from where the containing
+ state machine can take over). </p><p><span class="inlinemediaobject"><img src="../images/conflict2.gif"></span></p><p>Msm handles all these cases itself, so the designer needs only concentrate on
+ its state machine and the UML subtleties (not overlapping conditions), not on
+ implementing this behavior himself. </p></div></div><div class="sect2" title="State machine glossary"><div class="titlepage"><div><div><h3 class="title"><a name="d0e344"></a>State machine glossary</h3></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>state machine: the lifecycle of a thing. It is made of states,
+ regions, transitions and processes incoming events.</p></li><li class="listitem"><p>state: a stage in the lifecycle of a state machine. A state (like a
+ submachine) can have an entry and exit action.</p></li><li class="listitem"><p>event: an incident provoking (or not) a reaction of the state
+ machine</p></li><li class="listitem"><p>transition: a specification of how a state machine reacts to an event.
+ It specifies a source state, the event triggering the transition, the
+ target state (which will become the newly active state if the transition
+ is triggered), guard and actions.</p></li><li class="listitem"><p>action: an operation executed during the triggering of the
+ transition.</p></li><li class="listitem"><p>guard: a boolean operation being able to prevent the triggering of a
+ transition which would otherwise fire.</p></li><li class="listitem"><p>transition table: representation of a state machine. A state machine
+ diagram is another but incomplete representation of the same
+ model.</p></li><li class="listitem"><p>initial state: The state in which the state machine starts. Having
+ several orthogonal regions means having as many initial states.</p></li><li class="listitem"><p>composite / submachine: A composite state is a state which is itself a
+ state machine. A submachine is an instance of a composite state and can
+ be found several times in a same state machine.</p></li><li class="listitem"><p>orthogonal regions: (logically) parallel flow of execution of a state
+ machine. Every region of a state machine gets a chance to process an
+ incoming event.</p></li><li class="listitem"><p>terminate pseudo-state: when this state becomes active, it terminates
+ the execution of the whole state machine.</p></li><li class="listitem"><p>entry/exit pseudo state: defined for composites / submachines and are
+ defined as a connection between a transition outside of the composite
+ and a transition inside the composite. It is a way to enter or leave a
+ submachine through a predefined point.</p></li><li class="listitem"><p>fork: a fork allows explicit entry into several orthogonal regions of
+ a submachine.</p></li><li class="listitem"><p>history: a history is a way to remember the active state of a
+ submachine so that the submachine can proceed in its last state next
+ time it becomes active.</p></li><li class="listitem"><p>completion events (also called completion transitions): when a
+ transition has no named event triggering it, it automatically fires when
+ the source state is active, unless a guard forbids it.</p></li><li class="listitem"><p>transition conflict: a conflict is present if for a given source state
+ and incoming event, several transitions are possible. UML specifies that
+ guard conditions have to solve the conflict.</p></li><li class="listitem"><p>internal transitions: transition from a state to itself without having
+ exit and entry actions being called.</p></li></ul></div><p>
+ </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s02.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Founding idea </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> User's Guide</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ar01s04.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s04.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,1302 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>User's Guide</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="ar01s03.html" title="UML Short Guide"><link rel="next" href="ar01s05.html" title="Performance / Compilers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">User's Guide</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr></table><hr></div><div class="sect1" title="User's Guide"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e402"></a>User's Guide</h2></div></div></div><div class="sect2" title="Design"><d
iv class="titlepage"><div><div><h3 class="title"><a name="d0e405"></a>Design</h3></div></div></div><p>Msm is divided between front–ends and back-ends. At the moment, there is just one
+ back-end. On the front-end side, there is more to see. Msm offers several state
+ machine description languages with many more possible. Now, everybody can build his
+ own description language (in case one gets bored with the ones provided) without
+ changes to the library. For who feels like being a language writer this document
+ adds a description of the interface between front-end and back-end.TODO.</p><p>There are, at the moment, three main front-ends. The basic one is an adaptation of
+ the example provided in the MPL book (TODO add link) with actions defined as
+ pointers to state or state machine methods. The second one is based on functors. The
+ third, eUML (embedded UML) is an experimental language based on Boost.Proto and
+ Boost.Typeof and hiding most of the metaprogramming to increase readability. Both
+ eUML and the functor front-end also offer a functional library (a bit like
+ Boost.Phoenix) for use as action language (UML defining none).</p></div><div class="sect2" title="Basic front-end"><div class="titlepage"><div><div><h3 class="title"><a name="d0e412"></a>Basic front-end</h3></div></div></div><p>This is the historical front-end, inherited from the MPL book. It provides a
+ transition table made of rows of different names and functionality. Actions and
+ guards are defined as methods and referenced through a pointer in the transition.
+ This front-end provides a simple interface making easy state machines easier to
+ define, but more complex state machines a bit harder. It also is slightly slower
+ than the functor and eUML front-ends (about 20%). Not that it does more, it simply
+ seems that the compiler better optimizes the functor actions.</p><div class="sect3" title="A simple example"><div class="titlepage"><div><div><h4 class="title"><a name="d0e417"></a>A simple example</h4></div></div></div><p>Let us have a look at a state machine diagram of the founding example:</p><p><span class="inlinemediaobject"><img src="../images/SimpleTutorial.jpg"></span></p><p>We are now going to build it with MSM's basic front-end. An <a class="link" href="examples/SimpleTutorial.cpp" target="_top">example</a> is also
+ provided.</p></div><div class="sect3" title="Transition table"><div class="titlepage"><div><div><h4 class="title"><a name="d0e431"></a>Transition table</h4></div></div></div><p>As previously stated, MSM is based on the transition table, so let us define
+ one:</p><p>struct transition_table : mpl::vector<</p><p>
+ </p><table frame="void" id="d0e440"><tbody><tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Stopped ,</td>
+ <td>play,</td>
+ <td>Playing,</td>
+ <td>&player_::start_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Stopped ,</td>
+ <td>open_close,</td>
+ <td>Open,</td>
+ <td>&player_::open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>_row <</td>
+ <td>Stopped ,</td>
+ <td>stop,</td>
+ <td>Stopped</td>
+ <td> </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Open ,</td>
+ <td>open_close ,</td>
+ <td>Empty ,</td>
+ <td>&player_::close_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Empty ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::store_cd_info ,</td>
+ <td>&player_::good_disk_format</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Playing ,</td>
+ <td>&player_::store_cd_info ,</td>
+ <td>&player_::auto_start</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::stop_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>pause ,</td>
+ <td>Paused ,</td>
+ <td>&player_::pause_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::stop_and_open</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>end_pause ,</td>
+ <td>Playing ,</td>
+ <td>&player_::resume_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::stop_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::stop_and_open</td>
+ <td> </td>
+ <td>></td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>You will notice that this is almost exactly our founding example. The only
+ change in the transition table is the different types of transitions (rows). The
+ founding example forces one to define an action method and offers no guards. You
+ have 4 basic row types:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">row</code> takes 5 arguments: start state, event, next
+ state, action and guard.</p></li><li class="listitem"><p><code class="code">a_row</code> (“a” for action) allows defining only the
+ action and omit the guard condition.</p></li><li class="listitem"><p><code class="code">g_row</code> (“g” for guard) allows omitting the action
+ method and defining only the guard.</p></li><li class="listitem"><p><code class="code">_row</code> allows omitting action and guard methods.</p></li></ul></div><p>The signature for action methods is:</p><p><code class="code">void stop_playback(stop const&)</code></p><p>Action methods return nothing and take the argument as const reference. Of
+ course nothing forbids you from defining an action for several events:</p><p><code class="code">template <class Event> void stop_playback(Event
+ const&)</code></p><p>Guards have as only difference the return value, which is a boolean:</p><p><code class="code">bool good_disk_format(cd_detected const& evt)</code></p><p>The transition table is actually a MPL vector (or list), which brings a
+ limitation that the default maximum size of the table is 20. If you need more
+ transitions, overriding this default behavior is necessary, for example add
+ before any header:</p><p><code class="code">#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS </code></p><p><code class="code">#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 // or whatever you need
+ </code></p><p><code class="code">#define BOOST_MPL_LIMIT_MAP_SIZE 30 // or whatever you need
+ </code></p><p>The other limitation is that the MPL types are defined only up to 50 entries.
+ For the moment, the only solution to achieve more is to add headers to the MPL
+ (luckily, this is not very complicated).TODO add them</p></div><div class="sect3" title="Defining states with entry/exit actions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e977"></a>Defining states with entry/exit actions</h4></div></div></div><p>While states were enums in the MPL book, they now are structs, which allows
+ them to hold data, provide entry, exit actions, different behaviors and be
+ reusable (as they do not know anything about the containing state machine). To
+ define a state, inherit from the correct state type:</p><p>struct Empty : public msm::front::state<> {};</p><p>They can optionally provide entry and exit behaviors:</p><p><code class="code">struct Empty : public msm::front::state<> {</code></p><p><code class="code">template <class Event, class Fsm> </code></p><p><code class="code">void on_entry(Event const&, Fsm& ) {std::cout <<
+ "entering: Empty" << std::endl;} </code></p><p><code class="code">template <class Event, class Fsm> </code></p><p><code class="code">void on_exit(Event const&, Fsm& ) {std::cout << "leaving:
+ Empty" << std::endl;} </code></p><p><code class="code">};</code></p><p>There are more state types (terminate, interrupt, pseudo states, etc.)
+ corresponding to the UML standard state types. These will be described in
+ details in the next pages.</p></div><div class="sect3" title="Defining a simple state machine"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1006"></a>Defining a simple state machine</h4></div></div></div><p>Declaring a state machine is straightforward and is done with a high signal /
+ noise ratio. In our player example, we declare the state machine as:</p><p><code class="code">struct player_ : public msm::front::state_machine_def<player_>{ /*
+ see below */}</code></p><p>This declares a state machine using the basic front-end. We now declare inside
+ the state machine structure the initial state:</p><p><code class="code">typedef Empty initial_state;</code></p><p>And that is about all of what is absolutely needed. In the example, the states
+ are declared inside the state machine for readability but this is not a
+ requirements, states can be declared wherever you see fit.</p><p>All what is left to us is to pick a back-end (which is quite simple as there
+ is only one at the moment):</p><p><code class="code">typedef msm::back::state_machine<player_> player;</code></p><p>You now have a ready-to-use state machine with entry/exit actions, guards,
+ transition actions, a message queue so that processing an event can generate
+ another event. The state machine also adapted itself to your need and removed
+ almost all features we didn't use in this simple example. Note that this is not
+ per default the faster possible state machine. See the section "getting more
+ speed" to know how to get the maximum speed. In a nutshell, MSM cannot know
+ about your usage of some features so you will have to explicitly tell it.</p><p>TODO no_transition TODO start fct</p></div><div class="sect3" title="Defining a submachine"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1030"></a>Defining a submachine</h4></div></div></div><p>We now want to extend our last state machine by making the Playing state a
+ state machine itself (a submachine).</p><p><span class="inlinemediaobject"><img src="../images/CompositeTutorial.jpg"></span></p><p>Again, an <a class="link" href="examples/CompositeTutorial.cpp" target="_top">example</a> is
+ also provided.</p><p>A submachine really is a state machine itself, so we declare Playing as such,
+ choosing a front-end and a back-end:</p><p><code class="code">struct Playing_ : public msm::Front::state_machine_def<Playing_>{...}
+ </code></p><p><code class="code">typedef msm::back::state_machine<Playing_> Playing;</code></p><p>Like for any state machine, one also needs a transition table and an initial
+ state:</p><p>struct transition_table : mpl::vector<</p><table id="d0e1056"><tbody><tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>------------------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song1 ,</td>
+ <td>NextSong,</td>
+ <td>Song2,</td>
+ <td>&Playing_::start_next_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song2 ,</td>
+ <td>PreviousSong,</td>
+ <td>Song1,</td>
+ <td>&Playing_::start_prev_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song2 ,</td>
+ <td>NextSong,</td>
+ <td>Song3,</td>
+ <td>&Playing_::start_next_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song3 ,</td>
+ <td>PreviousSong ,</td>
+ <td>Song2 ,</td>
+ <td>&Playing_::start_prev_song </td>
+ <td> </td>
+ <td>></td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>------------------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p><code class="code">typedef Song1 initial_state; </code></p><p>This is about all you need to do. MSM will now automatically recognize Playing
+ as a submachine and all events handled by Playing (NextSong and PreviousSong)
+ will now be automatically forwarded to Playing whenever this state is active.
+ All other state machine features described later are also available.</p></div><div class="sect3" title="Orthogonal regions, terminate state, event deferring"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1247"></a>Orthogonal regions, terminate state, event deferring</h4></div></div></div><p>It is a very common problem in many state machines to have to handle errors.
+ It usually involves defining a transition from all the states to a special error
+ state. Translation: not fun. It is also not practical to find from which state
+ the error originated. The following diagram shows an example of what clearly
+ becomes not very readable:</p><p><span class="inlinemediaobject"><img src="../images/error_no_regions.jpg"></span></p><p>This is neither very readable nor beautiful, clearly. And we do not even have
+ any action on the transitions yet.</p><p>Luckily, UML provides a helpful concept, orthogonal regions. See them as
+ lightweight state machines running at the same time in a same state machine and
+ having the capability to influence one another. The effect is that you have
+ several active states at any time. We can therefore keep our state machine from
+ the previous example and just define a new region made of two states, AllOk and
+ ErrorMode. AllOk is most of the time active. But the error_found error event
+ makes the second region move to the new active state ErrorMode. This event does
+ not interest the main region so it will simply be ignored.
+ "<code class="code">no_transition</code>" will be called only if no region at all handles
+ the event. </p><p>Adding an orthogonal region is easy, one only needs to declare more states in
+ the <code class="code">initial_state</code> typedef. So, adding a new region with AllOk as
+ the region's initial state is:</p><p><code class="code">typedef mpl::vector<Empty,AllOk> initial_state;</code></p><p><span class="inlinemediaobject"><img src="../images/Orthogonal-deferred.jpg"></span></p><p>Furthermore, when you detect an error, you usually do not want other events to
+ be handled. To achieve this, we use another UML feature, terminate states. When
+ any region moves to a terminate state, the state machine “terminates” (the state
+ machine and all its states stay alive) and all further events are ignored. This
+ is of course not mandatory, one can use orthogonal regions without terminate
+ states. Also note that, as UML mandates, every region gets a chance of handling
+ the event, in the order as declared by the <code class="code">initial_state</code> type. MSM
+ also provides a small extension to UML, interrupt states. If you declare
+ ErrorMode as interrupt state instead of terminate state, the state machine will
+ not handle any event other than the one which ends the interrupt. So it's like a
+ terminate state, with the difference that you are allowed to resume the state
+ machine when a condition (like handling of the original error) is met. </p><p>Last but not least, this example also shows here the handling of event
+ deferring. Let's say someone puts a disc and immediately presses play. The event
+ cannot be handled, yet you'd want it to be handled at a later point and not
+ force the user to press play again. The solution is to define it as deferred in
+ the Empty and Open states and get it handled in the first state where the event
+ is not to be deferred. It can then be handled or rejected. In this example, when
+ Stopped becomes active, the event will be handled because only Empty and Open
+ defer the event.</p><p>Notice how UML defines event deferring as a state property. To accomodate
+ this, MSM lets you specify this in states by providing a
+ <code class="code">deferred_events</code> type:</p><p><code class="code">struct Empty : public msm::front::state<> </code></p><p><code class="code">{ </code></p><p><code class="code">// if the play event is fired while in this state, defer it until a
+ state </code></p><p><code class="code">// handles or rejects it</code></p><p><code class="code"> typedef mpl::vector<play> deferred_events;</code></p><p><code class="code">...};</code></p><p>Please have a look at the <a class="link" href="examples/Orthogonal-deferred.cpp" target="_top">complete example</a>.</p><p>While this is wanted by UML and is simple, it is not always practical because
+ one could wish to defer only in certain conditions. One could also want to make
+ this be part of a transition action with the added bonus of a guard. It would
+ also be conform to the MSM philosophy to get as much as possible in the
+ transition table, where you can have all the important state machine structure
+ grouped together. This is also possible but not practical with this front-end so
+ we will need to pick a different row from the functor front-end. For a complete
+ description of the <code class="code">Row</code> type, please have a look at the <span class="command"><strong><a class="command" href="ar01s04.html#functor-front-end">functor front-end.</a></strong></span></p><p>First, as there is no state where MSM can detect the requirement of this
+ feature, we need to require deferred events capability explicitly, by adding a
+ type in the state machine definition:</p><p><code class="code">struct player_ : public
+ msm::front::state_machine_def<player_></code></p><p><code class="code">{ </code></p><p><code class="code">typedef int activate_deferred_events;</code></p><p><code class="code">...};</code></p><p>We can now defer an event in any transition of the transition table by using
+ as action the predefined <code class="code">msm::front::Defer</code> functor, for
+ example:</p><p><code class="code">Row < Empty , play , none , Defer , none ></code></p><p>This is an internal transition row(see <span class="command"><strong><a class="command" href="ar01s04.html#internal-transitions">internal transitions</a></strong></span>) but you
+ can ignore this for the moment. It just means that we are not leaving the Empty
+ state. What matters is that we use Defer as action. This is roughly equivalent
+ to the previous syntax but has the advantage of giving you all the information
+ in the transition table.</p><p>The second difference is that as we now have a transition defined, this
+ transition can play in the resolution of <span class="command"><strong><a class="command" href="ar01s03.html#transition-conflict">transition conflicts</a></strong></span>. For
+ example, we could model an "if (condition2) move to Playing else if (condition1)
+ defer play event":</p><p>
+ <code class="code">Row < Empty , play , none , Defer , condition1 >,</code></p><p><code class="code">g_row < Empty , play , Playing , &player_::condition2
+ ></code></p><p>Please have a look at <a class="link" href="examples/Orthogonal-deferred2.cpp" target="_top">this possible implementation</a>.</p></div><div class="sect3" title="History"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1361"></a>History</h4></div></div></div><p>UML defines two types of history, Shallow History and Deep History. What is it
+ and when do you need it? In the previous examples, if the player was playing the
+ second song and the user pressed pause, leaving Playing, at the next press on
+ the play button, the Playing state would become active and the first song would
+ play again. Soon would the first client complaints follow. They'd of course
+ demand, that if the player was paused, then it should remember which song was
+ playing. But it the player was stopped, then it should restart from the first
+ song. Now, how can it be done? Of course, you could add a bit of programming
+ logic and generate extra events to make the second song start if coming from
+ Pause. Something like: </p><p><code class="code">if (Event == end_pause) { for (int i=0;i< song number;++i) {
+ player.process_event(NextSong()); } } </code></p><p>Not much to like in this example, isn't it? To solve this problem, you define
+ what is called a shallow or a deep history. A shallow history reactivates the
+ last active state of a submachine when this state machine becomes active again.
+ The deep history does the same recursively, so if this last active state of the
+ submachine was itself a submachine, its last active state would become active
+ and this will continue until an active state is a normal state. For example, let
+ us have a look at the following UML diagram: </p><p><span class="inlinemediaobject"><img src="../images/HistoryTutorial.jpg"></span></p><p>Notice that the main difference compared to previous diagrams is that the
+ initial state is gone and replaced by a History symbol (the H inside a
+ circle).</p><p>As explained in the <span class="command"><strong><a class="command" href="ar01s03.html#uml-history">small UML
+ tutorial</a></strong></span>, History is a good concept with a not completely
+ satisfying specification. MSM kept the concept but not the specification. Msm
+ goes another way and makes this a policy so you can define your own history
+ types. Furthermore, History is a backend policy. This allows you to reuse the
+ same state machine frontend with different history policies.</p><p>Concretely, your frontend stays unchanged:</p><p><code class="code">struct Playing_ : public
+ msm::front::state_machine_def<Playing_></code></p><p>You then add the policy to the backend:</p><p><code class="code">typedef
+ msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause>
+ > > Playing;</code></p><p>This states that a shallow history must be activated if the Playing state
+ machine gets activated by the end_pause event and only this one (or any other
+ event added to the mpl::vector). If the state machine was in the Stopped state
+ and the event play was generated, the history would not be activated and the
+ normal initial state would become active. By default, history is disabled. For
+ your convenience the library provides in addition to ShallowHistory a non-UML
+ standard AlwaysHistory policy (likely to be your main choice) which always
+ activates history, whatever event triggers the submachine activation. Deep
+ history is not directly available. The reason is that it would conflict with
+ policies which submachines could define. Of course, if for example, Song1 were a
+ state machine itself, it could use the ShallowHistory policy itself thus
+ creating Deep History. </p></div><div class="sect3" title="Anonymous transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1394"></a>Anonymous transitions</h4></div></div></div><p><span class="command"><strong><a name="anonymous-transitions"></a></strong></span>The following diagram shows an
+ example making use of this feature:</p><p><span class="inlinemediaobject"><img src="../images/Anonymous.jpg"></span></p><p>Anonymous transitions are transitions without a named event. This means that
+ the transition automatically fires when the predecessor state is entered (to be
+ exact, after the entry action). Otherwise it is a normal transition with actions
+ and guards. Why would you need something like that? A possible case would be if
+ a part of your state machine implements some algorithm, where states are steps
+ of the algorithm implementation. Then, using several anonymous transitions with
+ different guard conditions, you are actually implementing some if/else
+ statement. Another possible use would be a real-time system called at regular
+ intervals and always doing the same thing, meaning implementing the same
+ algorithm. The advantage is that once you know how long a transition takes to
+ execute on the system, by calculating the longest path (the number of
+ transitions from start to end), you can pretty much know how long your algorithm
+ will take in the worst case, which in turns tells you how big of a time frame
+ you are to request from a scheduler. </p><p>If you are using Executable UML (a good book describing it is "Executable UML,
+ a foundation for Model-Driven Architecture"), you will notice that it is common
+ for a state machine to generate an event to itself only to leave a state.
+ Anonymous transitions free you from this constraint.</p><p>If you do not use this feature in a concrete state machine, MSM will
+ deactivate it and you will not pay for it. If you use it, there is however a
+ small performance penalty as MSM will try to fire a compound event (the other
+ UML name for anonymous transitions) after every taken transition. This will
+ therefore double the event processing cost, which is not as bad as it sounds as
+ MSM’s execution speed is very high anyway.</p><p>To define such a transition, use “none” as event in the transition table, for
+ example:</p><p><code class="code">row < State3 , none , State4 , &p::State3ToState4 ,
+ &p::always_true ></code></p><p><a class="link" href="examples/AnonymousTutorial.cpp" target="_top">An implementation</a> of
+ the state machine diagram is also provided.</p></div><div class="sect3" title="Internal transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1419"></a><span class="command"><strong><a name="internal-transitions"></a></strong></span>Internal transitions</h4></div></div></div><p>Internal transitions are transitions executing in the scope of the active
+ state, being a simple state or a submachine. One can see them as a
+ self-transition of this state, without an entry or exit action called. This is
+ useful when all you want is to execute some code for a given event in a given
+ state.</p><p>Internal transitions are specified as having a higher priority than normal
+ transitions. While it makes sense for a submachine with exit points, it is
+ surprising for a simple state. MSM lets you define the transition priority by
+ setting the transition’s position inside the transition table (see <span class="command"><strong><a class="command" href="ar01s07.html#run-to-completion">internals</a></strong></span> ). The difference
+ between "normal" and internal transitions is that internal transitions have no
+ target state, therefore we need new row types. We had a_row, g_row, _row and
+ row, we now add a_irow, g_irow, _irow and irow which are like normal transitions
+ but define no target state. For, example an internal transition with a guard
+ condition could be:</p><p><code class="code">g_irow < Empty /*state*/ , cd_detected
+ /*event*/,&p::internal_guard /* guard */ ></code></p><p>These new row types can be placed anywhere in the transition table so that you
+ can still have your state machine structure grouped together. The only
+ difference of behavior with the UML standard is the missing notion of priority.
+ Please have a look at <a class="link" href="examples/SimpleTutorialInternal.cpp" target="_top">the
+ example</a>.</p><p>It is also possible to do it the UML-conform way by declaring a transition
+ table called <code class="code">internal transition_table</code> inside the state itself and
+ using internal row types. For example:</p><p><code class="code">struct Empty : public msm::front::state<> {</code></p><p><code class="code">struct internal_transition_table : mpl::vector<</code></p><p><code class="code">a_internal < cd_detected , Empty, &Empty::internal_action
+ ></code></p><p><code class="code">> {};</code></p><p><code class="code">};</code></p><p>This declares an internal transition table called internal_transition_table
+ and reacting on the event cd_detected by calling internal_action on Empty. Let
+ us note a few points:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>internal tables are NOT called transition_table but
+ internal_transition_table</p></li><li class="listitem"><p>they use different but similar row types: a_internal, g_internal,
+ _internal and internal.</p></li><li class="listitem"><p>These types take as first template argument the triggering event
+ and then the action and guard method. Note that the only real
+ difference to classical rows is the extra argument before the
+ function pointer. This is the type on which the function will be
+ called.</p></li><li class="listitem"><p>This also allows you, if you wish, to define actions and guards in
+ another state of the state machine or in the state machine
+ itself.</p></li><li class="listitem"><p>submachines can have an internal transition table and a classical
+ transition table.</p></li></ul></div><p>The <a class="link" href="examples/TestInternal.cpp" target="_top">following example</a>
+ makes use of an a_internal. It also uses functor-based internal transitions
+ which will be explained in <span class="command"><strong><a class="command" href="ar01s04.html#functor-internal-transitions">the functor front-end</a></strong></span>, please ignore them for the moment. Also
+ note that the state-defined internal transitions, having following the UML
+ standard the highest priority, are tried before those defined inside the state
+ machine transition table.</p><p>Which method should you use? It depends on what you need:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>the first version (using irow) is simpler and likely to compile
+ faster. It also lets you choose the priority of your internal
+ transition.</p></li><li class="listitem"><p>the second version is more logical from a UML perspective and lets
+ you make states more useful and reusable. It also allows you to call
+ actions and guards on any state of the state machine</p></li></ul></div><p>
+ <span class="command"><strong><a name="internal-transitions-note"></a></strong></span><span class="underline"><span class="bold"><strong>Note</strong></span></span>: There is an added
+ possibility coming from this feature. The <code class="code">internal_transition_table</code>
+ transitions being added directly inside the main state machine's transition
+ table, it is possible, if it is more to your state, to distribute your state
+ machine definition a bit like Boost.Statechart, leaving the state machine itself
+ the only task of declaring the states it wants to use using the
+ <code class="code">explicit_creation</code> type definition. While this is not the
+ author's favorite way, it is still possible. A simplified example using only two
+ states will make it clearer:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><a class="link" href="examples/distributed_table/DistributedTable.cpp" target="_top">state machine definition</a></p></li><li class="listitem"><p>Empty <a class="link" href="examples/distributed_table/Empty.hpp" target="_top">header</a> and <a class="link" href="examples/distributed_table/Empty.cpp" target="_top">cpp</a></p></li><li class="listitem"><p>Open <a class="link" href="examples/distributed_table/Open.hpp" target="_top">header</a> and <a class="link" href="examples/distributed_table/Open.cpp" target="_top">cpp</a></p></li><li class="listitem"><p><a class="link" href="examples/distributed_table/Events.hpp" target="_top">events
+ definition</a></p></li></ul></div><p>There is an added bonus offered for submachines, which can have both the
+ standard transition_table and an internal_transition_table (which has higher
+ priority). This makes it easier if you decide to make a full submachine from a
+ state. It is also slightly faster than the standard alternative, adding
+ orthogonal regions, because event dispatching will, if accepted by the internal
+ table, not continue to the subregions. This gives you a O(1) dispatch instead of
+ O(number of regions). While the example is with eUML, the same is also possible
+ with this front-end.</p></div><div class="sect3" title="more row types"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1532"></a>more row types</h4></div></div></div><p>It is also possible to write transitions using actions and guard conditions
+ not just from the state machine but also from its contained states. In this
+ case, one must specify not just a method pointer but also the object on which to
+ call it. This transition row is called, not very originally, <code class="code">row2</code>.
+ They come, like normal transitions in four flavors: <code class="code">a_row2, g_row2, _row2
+ and row2</code>. For example, a transition calling an action from the state
+ Empty could be:</p><p><code class="code">a_row2 < Stopped , open_close , Open , Empty /*action source*/ ,
+ &Empty::open_drawer /*action*/></code></p><p>The same capabilities are also available for internal transitions so that we
+ have: <code class="code">a_irow2, g_irow2, _irow2 and row2</code>. For transitions defined as
+ part of the <code class="code">internal_transition_table</code>, you can use the <span class="command"><strong><a class="command" href="ar01s04.html#internal-transitions">a_internal, g_internal, _internal,
+ internal</a></strong></span> row types.</p><p>These row types allow us to distribute the state machine code among states,
+ making them reusable and more valuable. Using transition tables inside states
+ also contributes to this possibility. An <a class="link" href="examples/SimpleTutorial2.cpp" target="_top">example</a> of these new tows
+ is also provided.</p></div><div class="sect3" title="Explicit entry / entry and exit pseudo-state / fork"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1562"></a>Explicit entry / entry and exit pseudo-state / fork</h4></div></div></div><p>MSM (almost) fully supports these features described in the <span class="command"><strong><a class="command" href="ar01s03.html#uml-history">small UML tutorial</a></strong></span>. Almost because there
+ are currently two limitations: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>it is only possible to explicitly enter a sub- state of the target
+ but not a sub-sub state.</p></li><li class="listitem"><p>it is not possible to explicitly exit. Exit points must be
+ used.</p></li></ul></div><p>Let us see a concrete example:</p><p><span class="inlinemediaobject"><img src="../images/entry%20tutorial.jpg"></span></p><p>We find in this diagram:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>A “normal” entering into SubFsm2 triggered by event1 and back to
+ State1 using the same event. In each zone is the initial state
+ activated, i.e. SubState1 and SubState1b.</p></li><li class="listitem"><p>An explicit entry into SubFsm2::SubState2 for zone “a” with event2
+ as trigger, meaning that in region “b” the initial state,
+ SubState1b, activated.</p></li><li class="listitem"><p>A fork into zones “a” and “b” to the explicit entries SubState2
+ and SubState2b, triggered by event3. Both states become active so no
+ zone is default activated (if we had a third zone, it would
+ be).</p></li><li class="listitem"><p>A connection of two transitions through an entry pseudo state,
+ SubFsm2::PseudoEntry1, triggered by event4 and triggering also the
+ second transition on the same event (both transitions must be
+ triggered by the same event). Zone “b” gets default-activated and
+ SubState1b becomes active.</p></li><li class="listitem"><p>An exit from SubFsm2 using an exit pseudo-state, PseudoExit1,
+ triggered by event5 and connecting two transitions using the same
+ event. Again, the event is forwarded to the second transition and
+ both regions are exited, as SubFsm2 becomes inactive. Note that if
+ no transition is defined from PseudoExit1, an error (as defined in
+ the UML standard) will be detected and no_transition called.</p></li></ul></div><p>The example is also <a class="link" href="examples/DirectEntryTutorial.cpp" target="_top">fully
+ implemented</a>.</p><p>This sounds complicated but the syntax is simple.</p><div class="sect4" title="Explicit entry"><div class="titlepage"><div><div><h5 class="title"><a name="d0e1608"></a>Explicit entry</h5></div></div></div><p>First, to define that a state is an explicit entry, you have to make it a
+ state and mark it as explicit, giving as template parameters the zone id
+ (the zone id starts with 0 and corresponds to the first initial state of the
+ initial_state type sequence).</p><p><code class="code">struct SubState2 : public msm::front::state<> , public
+ msm::front::explicit_entry<0></code></p><p>And define the submachine as:</p><p><code class="code">typedef msm::back::state_machine<SubFsm2_> SubFsm2;</code></p><p>You can then use it as target in a transition with State1 as
+ source:</p><p><code class="code">_row < State1, Event2, SubFsm2::direct< SubFsm2_::SubState2>
+ ></code></p><p>The syntax deserves some explanation. SubFsm2_ is a front end. SubState2
+ is a nested state, therefore the SubFsm2_::SubState2 syntax. The containing
+ machine (containing State1 and SubFsm2) refers to the backend instance
+ (SubFsm2). SubFsm2::direct states that a direct entry is desired.</p><p><span class="underline">Note (also valid for forks)</span>: in
+ order to make compile time more bearable for the more standard cases, and
+ unlike initial states, explicit entry states which are also not found in the
+ transition table of the entered submachine (a rare case) do NOT get
+ automatically created. To explicitly create such states, you need to add in
+ the state machine containing the explicit states a simple typedef giving a
+ sequence of states to be explicitly created like:</p><p><code class="code">typedef mpl::vector<SubState2,SubState2b>
+ explicit_creation;</code></p></div><div class="sect4" title="Fork"><div class="titlepage"><div><div><h5 class="title"><a name="d0e1635"></a>Fork</h5></div></div></div><p>Need a fork instead of an explicit entry? Then, as a fork is an explicit
+ entry into states of different regions, we do not change the state
+ definition compared to the explicit entry and specify as target a list of
+ explicit entry states:</p><p><code class="code">_row < State1, Event3, mpl::vector<SubFsm2::direct<
+ SubFsm2_::SubState2>, SubFsm2::direct <SubFsm2_::SubState2b>
+ ></code></p><p>With SubState2 defined as before and SubState2b defined as being in the
+ second region (Caution: MSM does not check that the region is
+ correct):</p><p><code class="code">struct SubState2b : public msm::front::state<> , public
+ msm::front::explicit_entry<1></code></p></div><div class="sect4" title="Entry pseudo states"><div class="titlepage"><div><div><h5 class="title"><a name="d0e1648"></a>Entry pseudo states</h5></div></div></div><p> To define an entry pseudo state, you need derive from the corresponding
+ class and give the region id:</p><p><code class="code">struct PseudoEntry1 : public
+ msm::front::entry_pseudo_state<0></code></p><p>And add the corresponding transition in Fsm's transition table:</p><p><code class="code">_row < State1, Event4,
+ SubFsm2::entry_pt<SubFsm2_::PseudoEntry1> ></code></p><p>And another in the SubFsm2_ submachine definition (remember that UML
+ defines an entry point as a connection between two transitions), for example
+ this time with an action method:</p><p><code class="code">_row < PseudoEntry1, Event4, SubState3,
+ &SubFsm2_::entry_action ></code></p></div><div class="sect4" title="Exit pseudo states"><div class="titlepage"><div><div><h5 class="title"><a name="d0e1666"></a> Exit pseudo states </h5></div></div></div><p>And finally, exit pseudo states are to be used almost the same way, but
+ defined differently: it takes as template argument the event to be forwarded
+ (no region id is necessary):</p><p><code class="code">struct PseudoExit1 : public
+ exit_pseudo_state<event6></code></p><p>And you need, as for entry pseudo states, two transitions, one in the
+ submachine:</p><p><code class="code">_row < SubState3, Event5, PseudoExit1 ></code></p><p>And one in the containing state machine:</p><p><code class="code">_row < SubFsm2::exit_pt<SubFsm2_::PseudoExit1>, Event6, State2
+ ></code></p><p><span class="underline">Important note 1:</span> UML defines
+ transiting to an entry pseudo state and having either no second transition
+ or one with a guard as an error but defines no error handling. MSM will
+ tolerate this behavior; the entry pseudo state will simply be the newly
+ active state.</p><p><span class="underline">Important note 2</span>: UML defines
+ transiting to an exit pseudo state and having no second transition as an
+ error, and also defines no error handling. Therefore, it was decided to
+ implement exit pseudo state as terminate states and the containing composite
+ not properly exited will stay terminated as it was technically
+ “exited”.</p><p><span class="underline">Important note 3:</span> UML states that
+ for the exit point, the same event must be used in both transitions. MSM
+ relaxes this rule and only wants the event on the inside transition to be
+ convertible to the one of the outside transition. In our case, event6 is
+ convertible from event5. Notice that the forwarded event must be named in
+ the exit point definition. For example, we could define event6 as simply
+ as:</p><p><code class="code">struct event6 { event6(){} template <class Event> event6(Event
+ const&){} };//convertible from any event</code>
+ </p></div></div><div class="sect3" title="Flags"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1700"></a>Flags</h4></div></div></div><p>This <a class="link" href="examples/Flags.cpp" target="_top">tutorial</a> is devoted to a
+ concept not defined in UML: flags. It has been added into MSM after proving
+ itself useful on many occasions. Please, do not be frightened as we are not
+ talking about ugly shortcuts made of an improbable collusion of Booleans.</p><p>If you look into the Boost.Statechart documentation you'll find some code
+ like:</p><p><code class="code">if ( ( state_downcast< const NumLockOff * >() != 0 ) &&
+ </code></p><p><code class="code">( state_downcast< const CapsLockOff * >() != 0 ) &&
+ </code></p><p><code class="code">( state_downcast< const ScrollLockOff * >() != 0 ) ) </code></p><p>While correct and found in many UML books, this can be error-prone and a
+ potential time-bomb when your state machine grows and you add new states or
+ orthogonal regions.</p><p>And most of all, it hides the real question, which would be “does my state
+ machine's current state define a special property”? In this special case “are my
+ keys in a lock state”? So let's apply the Fundamental Theorem of Software
+ Engineering and move one level of abstraction higher.</p><p>In our player example, let's say we need to know if the player has a loaded
+ CD. We could do the same:</p><p><code class="code">if ( ( state_downcast< const Stopped * >() != 0 ) &&
+ </code></p><p><code class="code">( state_downcast< const Open * >() != 0 ) && </code></p><p><code class="code">( state_downcast< const Paused * >() != 0 ) &&</code></p><p><code class="code">( state_downcast< const Playing * >() != 0 )</code></p><p><code class="code"> ) </code></p><p>Or flag these 4 states as CDLoaded-able. You add a flag_list type into each
+ flagged state:</p><p><code class="code">typedef mpl::vector1<CDLoaded> flag_list;</code></p><p>You can even define a list of flags, for example in Playing:</p><p><code class="code">typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;</code></p><p>This means that Playing supports both properties. Now to check if your player
+ has a loaded CD, check if your flag is active in the current state:</p><p><code class="code">player p; if (p.is_flag_active<CDLoaded>()) ... </code></p><p>And what if you have orthogonal regions? How to decide if a state machine is
+ in a flagged state? By default, you keep the same code and the current states
+ will be OR'ed, meaning if one of the active states has the flag, then
+ is_flag_active returns true. Of course, in some cases, you might want that all
+ of the active states are flagged for the state to be active. You can also AND
+ the active states:</p><p><code class="code">if (p.is_flag_active<CDLoaded,player::Flag_AND>()) ...</code></p><p>The following diagram displays the flag situation in the tutorial.</p><p><span class="inlinemediaobject"><img src="../images/FlagsTutorial.jpg"></span></p></div><div class="sect3" title="Event Hierarchy"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1766"></a>Event Hierarchy</h4></div></div></div><p>There are cases where transitions with many related but different events are
+ needed. An example is text parsing. Let's say you want to parse a string and use
+ a state machine to handle you parsing state. You want to parse 4 digits and
+ decide to use a state for every matched digit. Your state machine could look
+ like:</p><p><span class="inlinemediaobject"><img src="../images/ParsingDigits.jpg"></span></p><p>But how to detect the digit event? We would like to avoid having to define 10
+ transitions on char_0, char_1... between two states as it would force us to
+ write 4 x 10 transitions and the compile-time would suffer. To solve this
+ problem, MSM supports the triggering of a transition on a subclass event. For
+ example, if we define digits as: </p><p><code class="code">struct digit {};</code></p><p><code class="code">struct char_0 : public digit {}; </code></p><p>And to the same for other digits, we can now fire char_0, char_1 events and
+ this will cause a transition with "digit" as trigger to be taken.</p><p>An example with performance measurement, taken from the documentation of
+ Boost.Xpressive illustrates this example (TODO). You might notice that the
+ performance is actually very good (better).</p></div><div class="sect3" title="Containing state machine (deprecated)"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1787"></a> Containing state machine (deprecated)</h4></div></div></div><p>This feature is still supported in MSM for backward compatibility but made
+ obsolete by the fact that every guard/action/entry action/exit action get the
+ state machine passed as argument and might be removed at a later time.</p><p>All of the states defined in the state machine are created upon state machine
+ construction. This has the huge advantage of a reduced syntactic noise. The cost
+ is a small loss of control of the user on the state creation and access. But
+ sometimes you needed a way for a state to get access to its containing state
+ machine. Basically, a state needs to change its declaration to:</p><p><code class="code">struct Stopped : public msm::front::state<sm_ptr></code></p><p>And to provide a set_sm_ptr function: <code class="code">void set_sm_ptr(player*
+ pl)</code></p><p>to get a pointer to the containing state machine. The same applies to
+ terminate_state / interrupt_state and entry_pseudo_state / exit_pseudo_state.
+ </p></div></div><div class="sect2" title="Functor front-end"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1803"></a><span class="command"><strong><a name="functor-front-end"></a></strong></span>Functor front-end</h3></div></div></div><p>The functor front-end is the preferred front-end at the moment. It is more
+ powerful than the standard front-end, slightly faster and has a more readable
+ transition table. It also makes it easier to reuse parts of state machines. Like
+ <span class="command"><strong><a class="command" href="ar01s04.html#eUML-front-end">eUML</a></strong></span>, il also comes with a good
+ deal of predefined actions. Actually, eUML generates a functor front-end through
+ Boost.Typeof and Boost.Proto so both offer the same functionality.</p><p>The rows which MSM offers come in different flavors. We saw the a_row, g_row,
+ _row, row, not counting internal rows. This is already much to know, so why define
+ new rows? These types have some disadvantages: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>They are more typing and information than we would wish. This means
+ syntactic noise.</p></li><li class="listitem"><p>Function pointers are weird in C++.</p></li><li class="listitem"><p>The action/guard signature is limited and does not allow for more
+ variations of parameters (source state, target state, current state
+ machine, etc.)</p></li><li class="listitem"><p>It is not easy to reuse action code from a state machine to
+ another.</p></li></ul></div><div class="sect3" title="Transition table"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1827"></a> Transition table </h4></div></div></div><p>We can change the definition of the simple tutorial's transition table
+ to:</p><p>
+ </p><table id="d0e1834"><tbody><tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>play,</td>
+ <td>Playing,</td>
+ <td>start_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>open_close,</td>
+ <td>Open,</td>
+ <td>open_drawer,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>stop,</td>
+ <td>Stopped,</td>
+ <td> </td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Open ,</td>
+ <td>open_close ,</td>
+ <td>Empty ,</td>
+ <td>close_drawer,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Empty ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Stopped ,</td>
+ <td>store_cd_info ,</td>
+ <td>good_disk_format</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>g_row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Playing ,</td>
+ <td>store_cd_info ,</td>
+ <td>&player_::auto_start</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>stop_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>pause ,</td>
+ <td>Paused ,</td>
+ <td>pause_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>stop_and_open,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>end_pause ,</td>
+ <td>Playing ,</td>
+ <td>resume_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>stop_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>stop_and_open,</td>
+ <td> none</td>
+ <td>></td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>Transitions are now of type "Row" with exactly 5 template arguments: source
+ state, event, target state, action and guard. Wherever there is nothing (for
+ example actions and guards), write "none". Actions and guards are no more
+ methods but functors getting as arguments the detected event, the state machine,
+ source and target state:</p><p><code class="code">struct store_cd_info { </code></p><p><code class="code">template <class Fsm,class Evt,class SourceState,class TargetState>
+ </code></p><p><code class="code">void operator()(Evt const&, Fsm& fsm, SourceState&,
+ TargetState& ) </code></p><p><code class="code"> {</code></p><p><code class="code"> cout << "player::store_cd_info" << endl;
+ fsm.process_event(play()); </code></p><p><code class="code"> } </code></p><p><code class="code">}; </code></p><p>The advantage to functors compared to functions are that they are generic and
+ reusable. They also allow passing more parameters than just events. The guard
+ functors are the same but have an operator() returning a bool.</p><p>It is also possible to mix rows from different front-ends. To show this, a
+ g_row has been left in the transition table. <span class="underline">Note:</span> in case the action functor is used in the transition table
+ of a state machine contained inside a top-level state machine, the “fsm”
+ parameter refers to the lowest-level state machine (referencing this action),
+ not the top-level one.</p><p>To illustrate the reusable point, MSM comes with a whole set of predefined
+ functors. Please refer to eUML for the full list (TODO). For example, we are
+ going to replace the first action by an action sequence and the guard by a more
+ complex functor.</p><p>We decide we now want to execute 2 actions in the first transition (Stopped ->
+ Playing). We only need to change the action start_playback to (TODO)
+ <code class="code">ActionSequence_< mpl::vector<some_action, start_playback> >
+ </code> and now will execute some_action and start_playback every time the
+ transition is taken. ActionSequence_ is a functor callinng each element of the
+ mpl::vector in sequence.</p><p>We also want to replace good_disk_format by a condition of the type:
+ “good_disk_format && (some_condition || some_other_condition)”. We can
+ achieve this using And_ and Or_ functors: <code class="code">And_<good_disk_format,Or_<
+ some_condition , some_other_condition></code>. It even starts looking like
+ functional programming. MSM ships with functors for operators, state machine
+ usage, STL algorithms or container methods.</p></div><div class="sect3" title="Defining states with entry/exit actions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2362"></a>Defining states with entry/exit actions</h4></div></div></div><p>You probably noticed that we just showed a different transition table and that
+ we even mixed rows from different front-ends. This means that you can do this
+ and leave the definitions for states unchanged. Most examples are doing this as
+ it is the simplest solution. You still enjoy the simplicity of the first
+ front-end with the extended power of the new transition types. This <a class="link" href="examples/SimpleWithFunctors.cpp" target="_top">tutorial</a>, adapted from
+ the earlier example does just this.</p><p>Of course, it is also possible to define states where entry and exit actions
+ are also provided as functors as these are generated by eUML and both front-ends
+ are equivalent. For example, we can define a state as:</p><p><code class="code">struct Empty_Entry { </code></p><p><code class="code">template <class Event,class Fsm,class State> </code></p><p><code class="code">void operator()(Event const&,Fsm&,State&) </code></p><p><code class="code"> {</code></p><p><code class="code"> ... </code></p><p><code class="code"> } </code></p><p><code class="code">}; // same for Empty_Exit</code></p><p><code class="code">struct Empty : public
+ msm::front::euml::func_state<Empty_Entry,Empty_Exit>{};</code></p><p>This also means that you can, like in the transition table, write entry / exit
+ actions made of more complicated action combinations. The previous example can
+ therefore <a class="link" href="examples/SimpleWithFunctors2.cpp" target="_top">be
+ rewritten</a>.</p><p>Usually, however, one will probably use the standard state definition as it
+ provides the same capabilities as this front-end state definition, unless one
+ needs some of the shipped predefined functors.</p></div><div class="sect3" title="Defining a simple state machine"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2403"></a>Defining a simple state machine</h4></div></div></div><p>Like states, state machines can be defined using the previous front-end, as
+ the previous example showed, or with the functor front-end, which allows you to
+ define a state machine entry and exit functions as functors, as in <a class="link" href="examples/SimpleWithFunctors2.cpp" target="_top">this example</a>.</p></div><div class="sect3" title="Anonymous transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2411"></a>Anonymous transitions</h4></div></div></div><p>Anonymous (compound) transitions are transition withour a named event, taken
+ automatically. We saw how this front-end uses <code class="code">none</code> when no action
+ or guard is required. We can also use <code class="code">none</code> instead of an event to
+ mark an anonymous transition. For example, the following transition makes an
+ immediate transition from State1 to State2:</p><p>Row < State1 , none , State2 ></p><p>The following transition does the same but calling an action in the
+ process:</p><p>Row < State1 , none , State2 , State1ToState2, none ></p><p>The following diagram shows an example and its <a class="link" href="examples/AnonymousTutorialWithFunctors.cpp" target="_top">implementation</a>:</p><p><span class="inlinemediaobject"><img src="../images/Anonymous.jpg"></span></p></div><div class="sect3" title="Internal transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2437"></a><span class="command"><strong><a name="functor-internal-transitions"></a></strong></span>Internal transitions</h4></div></div></div><p>The <a class="link" href="examples/SimpleTutorialInternalFunctors.cpp" target="_top">following
+ example</a> uses internal transitions with the functor front-end. As for
+ the simple standard front-end, both methods of defining internal transitions are supported:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>defining a <code class="code">Row</code> in the state machine's transition
+ table with <code class="code">none</code> as target state defines an internal
+ transition</p></li><li class="listitem"><p>defining an <code class="code">internal_transition_table</code> made of
+ <code class="code">Internal</code> rows inside a state defines UML-conform
+ internal transitions with higher priority</p></li><li class="listitem"><p>transitions defined inside <code class="code">internal_transition_table</code>
+ require no source state either as the source state is known.</p></li></ul></div><p>Like for the <span class="command"><strong><a class="command" href="ar01s04.html#internal-transitions-note">standard front-end internal transitions</a></strong></span>, internal transition
+ tables are added into the main state machine's table, thus allowing you to
+ distribute the transition table definition and reuse states.</p><p>There is an added bonus offered for submachines, which can have both the
+ standard transition_table and an internal_transition_table (which has higher
+ priority). This makes it easier if you decide to make a full submachine from a
+ state. It is also slightly faster than the standard alternative, adding
+ orthogonal regions, because event dispatching will, if accepted by the internal
+ table, not continue to the subregions. This gives you a O(1) dispatch instead of
+ O(number of regions). While the example is with eUML, the same is also possible
+ with this front-end.</p></div></div><div class="sect2" title="eUML (experimental)"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2477"></a><span class="command"><strong><a name="eUML-front-end"></a></strong></span>eUML (experimental)</h3></div></div></div><p><span class="underline">Important note</span>: eUML requires a compiler
+ supporting the C++0x decltype/typeof feature (from example VC >= 9, g++ >= 4.3. VC8
+ is partially supported). More generally, eUML has experimental status because most
+ compilers will start crashing when a state machine becomes too big. Only g++ 4.3
+ (unfortunately not 4.4 which shows a serious regression) seems perfectly
+ resilient.</p><p>The previous front-ends are simple to write but still force an amount of noise,
+ mostly MPL types, so it would be nice to write code looking like C++ (with a C++
+ action language) directly inside the transition table, like UML designers like to do
+ on their state machine diagrams. This is what eUML is for.</p><p>eUML is a Boost.Proto-based compile-time domain specific embedded language. It
+ provides grammars which allow the definition of actions/guards directly inside the
+ transition table or entry/exit in the state definition. It is defined in the
+ namespace msm::front::euml. There are grammars for actions, guards, flags,
+ attributes, deferred events, initial states.</p><p>It also relies on Boost.Typeof as a wrapper around the new decltype C++0x feature
+ to provide a compile-time evaluation of all the grammars. Unfortunately, all the
+ underlying Boost libraries are not Typeof-enabled, so for the moment, you will need
+ a compiler where Typeof is natively implemented (like VC8-9-10, g++ >= 4.3).</p><p>Examples will be provided in the next paragraphs. You need to include eUML basic
+ features: </p><p><code class="code">#include <msm/front/euml/euml.hpp></code></p><p>To add STL support (at possible cost of longer compilation times), include: </p><p><code class="code">#include <msm/front/euml/stl.hpp></code></p><div class="sect3" title="Transition table"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2501"></a>Transition table</h4></div></div></div><p>A transition can be defined using eUML as: </p><p><code class="code">source + event [guard] / action == target</code> or as</p><p><code class="code">target == source + event [guard] / action</code></p><p>The first version looks like a drawn transition in a diagram, the second one
+ seems natural to a C++ developper.</p><p>The simple transition table written with the <span class="command"><strong><a class="command" href="ar01s04.html#functor-front-end">previous front-end</a></strong></span> can now be
+ written as:</p><p>
+ </p><table frame="void" id="d0e2522"><tbody><tr>
+ <td>typedef BOOST_TYPEOF(build_stt((</td>
+ <td> </td>
+ <td> </td>
+ </tr><tr>
+ <td>Stopped +</td>
+ <td>play [DummyGuard] / (TestFct,start_playback)</td>
+ <td>== Playing</td>
+ </tr><tr>
+ <td>Stopped +</td>
+ <td>open_close/ open_drawer</td>
+ <td>== Open</td>
+ </tr><tr>
+ <td>Stopped +</td>
+ <td>stop</td>
+ <td>== Stopped</td>
+ </tr><tr>
+ <td>Open +</td>
+ <td>open_close / close_drawer</td>
+ <td>== Empty</td>
+ </tr><tr>
+ <td>Empty +</td>
+ <td>open_close / open_drawer </td>
+ <td>== Open</td>
+ </tr><tr>
+ <td>Empty +</td>
+ <td>cd_detected [good_disk_format] / store_cd_info </td>
+ <td>== Stopped</td>
+ </tr><tr>
+ <td> ) ) ) transition_table;</td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>Or, using the alternative notation, it can be:</p><p>
+ </p><table id="d0e2617"><tbody><tr>
+ <td>typedef BOOST_TYPEOF(build_stt((</td>
+ <td> </td>
+ <td> </td>
+ </tr><tr>
+ <td>Playing == </td>
+ <td>Stopped +</td>
+ <td>play [DummyGuard] / (TestFct,start_playback)</td>
+ </tr><tr>
+ <td>Open ==</td>
+ <td>Stopped +</td>
+ <td>open_close/ open_drawer</td>
+ </tr><tr>
+ <td>Stopped ==</td>
+ <td>Stopped +</td>
+ <td>stop</td>
+ </tr><tr>
+ <td>Empty ==</td>
+ <td>Open +</td>
+ <td>open_close / close_drawer</td>
+ </tr><tr>
+ <td>Open ==</td>
+ <td>Empty +</td>
+ <td>open_close / open_drawer</td>
+ </tr><tr>
+ <td>Stopped ==</td>
+ <td>Empty +</td>
+ <td>cd_detected [good_disk_format] / store_cd_info </td>
+ </tr><tr>
+ <td> ) ) ) transition_table;</td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>The transition table now looks like a list of (readable) rules with little
+ noise.</p><p>UML defines guards between “[ ]” and actions after a “/”, so this is already
+ more readable for UML designers. UML also allows designers to define several
+ actions sequentially (our previous ActionSequence) separated by a comma. The
+ first transition does just this: two actions separated by a comma and enclosed
+ inside parenthesis to respect C++ operator precedence.</p><p>If this seems to you like it will cost you run-time performance, don't worry,
+ typeof (decltype) only evaluates the build_stt function and no run-time cost
+ occurs. Actually, eUML is only a metaprogramming layer on top of "standard" MSM
+ metaprogramming and this first layer generates the previously-presented <span class="command"><strong><a class="command" href="ar01s04.html#functor-front-end">functor front-end</a></strong></span>.</p><p>UML also allows designers to define more complicated guards, like
+ [good_disk_format && (some_condition || some_other_condition)]. This was
+ possible with our previously defined functors, but using a complicated template
+ syntax. This syntax is now possible exactly as written, which means without
+ syntactic noise.</p></div><div class="sect3" title="Defining events, actions and states with entry/exit actions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2719"></a>Defining events, actions and states with entry/exit actions</h4></div></div></div><p>Events must be proto-enabled. To achieve this, they must inherit from
+ euml_event:</p><p><code class="code">struct play : euml_event<play>{};</code></p><p>Actions (returning void) and guards (returning a bool) are defined like
+ previous functors, with the difference that they also must be
+ proto-enabled:</p><p><code class="code">struct some_condition : euml_action< some_condition ></code></p><p><code class="code">{ </code></p><p><code class="code">template <class Fsm,class Evt,class SourceState,class
+ TargetState></code></p><p><code class="code">bool operator()(Evt const& ,Fsm& ,SourceState&
+ ,TargetState& ) { return true; } </code></p><p><code class="code">}; </code></p><p>It is also possible to use the same action grammar as for the transition table
+ for state entry and exit actions:</p><p><code class="code">typedef BOOST_TYPEOF(euml::build_state( (Empty_Entry,Dummy_Entry)/*2
+ entry actions*/,Empty_Exit/*1 exit action*/ )) Empty;</code></p><p>This means that Empty is defined as a state with an entry action made of two
+ sub-actions, Empty_Entry and Dummy_Entry (enclosed inside parenthesis), and an
+ exit action, Empty_Exit.</p><p>There are several overloads of the <span class="command"><strong><a name="eUML-build-state"></a></strong></span>build_state function:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>build_state(): state without entry or exit action.</p></li><li class="listitem"><p>build_state(Expr1): state with entry but no exit action.</p></li><li class="listitem"><p>build_state(Expr1,Expr2): state with entry and exit action.</p></li><li class="listitem"><p>build_state(Expr1,Expr2,Attributes): state with entry and exit
+ action, defining some attributes (read further on).</p></li><li class="listitem"><p>build_state(Expr1,Expr2,Attributes,Configure): state with entry
+ and exit action, defining some attributes (read further on) and
+ flags (standard MSM flags) or deferred events (standard MSM deferred
+ events).</p></li><li class="listitem"><p>build_state(Expr1,Expr2,Attributes,Configure,Base): state with
+ entry and exit action, defining some attributes (read further on),
+ flags and deferred events (plain msm deferred events) and a
+ non-default base state (as defined in standard MSM).</p></li></ul></div><p>A NoAction is also defined, which does, well, nothing except being a
+ placeholder (needed for example as entry action if we have no entry but an
+ exit). Expr1 and Expr2 are a sequence of actions, obeying the same action
+ grammar as in the transition table (following the “/” symbol).</p><p>The state functors have a slightly different signature as there is no source
+ and target state but only a current state (entry/exit actions are
+ transition-independent), for example:</p><p><code class="code">struct Empty_Entry : euml_action< Empty_Entry ></code></p><p><code class="code">{ </code></p><p><code class="code">template <class Evt,class Fsm,class State></code></p><p><code class="code">void operator()(Evt const& ,Fsm& ,State& ) { ... }
+ </code></p><p><code class="code">}; </code></p><p>Notice again the euml_action, to make the functor play nice with the grammar.
+ </p></div><div class="sect3" title="Defining a simple state machine"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2795"></a>Defining a simple state machine</h4></div></div></div><p>Like for a functor front-end, you can reuse the state machine definition
+ method from the standard front-end. You can also use eUML to define a state
+ machine "on the fly" (if, for example, you need to provide an on_entry/on_exit
+ for this state machine as a functor). For this, there is also a function,
+ <span class="command"><strong><a name="eUML-build-sm"></a></strong></span>build_sm, which has up to 8 arguments:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>build_sm(Stt, Init): simplest state machine where only the
+ transition table and initial state(s) are defined.</p></li><li class="listitem"><p>build_sm(Stt, Init, Expr1): state machine where the transition
+ table, initial state and entry action are defined.</p></li><li class="listitem"><p>build_sm(Stt, Init, Expr1, Expr2): state machine where the
+ transition table, initial state, entry and exit actions are
+ defined.</p></li><li class="listitem"><p>build_sm(Stt, Init, Expr1, Expr2, Attributes): state machine where
+ the transition table, initial state, entry and exit actions are
+ defined. Furthermore, some attributes are added (read further
+ on).</p></li><li class="listitem"><p>build_sm(Stt, Init, Expr1, Expr2, Attributes, Configure): state
+ machine where the transition table, initial state, entry and exit
+ actions are defined. Furthermore, some attributes (read further on),
+ flags, deferred events and configuration capabilities TODO link (no
+ message queue / no exception catching) are added.</p></li><li class="listitem"><p>build_sm(Stt, Init, Expr1, Expr2, Attributes, Flags, Deferred ,
+ Base): state machine where the transition table, initial state,
+ entry and exit actions are defined. Furthermore, attributes (read
+ further on), flags , deferred events and configuration capabilities
+ (no message queue / no exception catching) are added and a
+ non-default base state (see base state TODO) is defined.</p></li></ul></div><p>For example, a minimum state machine could be defined
+ like:</p><p>
+ </p><table id="d0e2824"><tbody><tr>
+ <td>typedef BOOST_TYPEOF(build_stt((</td>
+ <td> </td>
+ <td> </td>
+ </tr><tr>
+ <td>... ) ) ) transition_table;</td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p><code class="code">typedef BOOST_TYPEOF(build_sm( transition_table(),init_ << Empty
+ )) player_;</code></p><p><span class="underline">Note for VC9</span>: This defined build_sm
+ syntax works most of the time. But once in a while, VC9 will display the problem
+ shown in the next section (not enough heap space). For example, this simple
+ performance test (TODO link), while really simple, will display the bug. To
+ correct it, the following solution works: </p><p><code class="code">#ifndef BOOST_MSVC</code></p><p><code class="code">typedef BOOST_TYPEOF(build_sm( transition_table(),init_ << Empty
+ << AllOk )) player_;</code></p><p><code class="code">#else</code></p><p><code class="code">struct player_ : public BOOST_TYPEOF(build_sm( transition_table(),init_
+ << Empty << AllOk )) {};</code></p><p><code class="code">#endif</code></p><p>Please have a look at the player tutorial written using eUML's <a class="link" href="examples/SimpleTutorialEuml2.cpp" target="_top">first</a> and <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">second</a> syntax. Please
+ ignore for the moment the BOOST_MSM_EUML_DECLARE_ATTRIBUTE macros, we come back
+ to it very soon.</p></div><div class="sect3" title="Defining a submachine"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2879"></a>Defining a submachine</h4></div></div></div><p>Defining a submachine (see <a class="link" href="examples/CompositeTutorialEuml.cpp" target="_top">tutorial</a>) with other
+ front-ends simply means using a state which is a state machine in the transition
+ table of another state machine. This is the same with eUML. One only needs
+ define a second state machine and reference it in the transition table of the
+ containing state machine.</p><p><span class="underline">Note</span>: the previous #ifdef trick has to
+ be used for submachine definition because the VC9 bug occurs more often when
+ submachines are involved.</p></div><div class="sect3" title="Attributes / Function call"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2891"></a> Attributes / Function call</h4></div></div></div><p>We now want to make our grammar more useful. Very often, one needs only very
+ simple action methods, for example ++Counter or Counter > 5 where Counter is
+ usually defined as some attribute of the class containing the state machine.
+ Furthermore, unlike many expensive tools which are on the market, states within
+ MSM are also classes so they can have attributes, and we would also like to
+ provide them with attributes. </p><p>If you look back at our examples using the <a class="link" href="examples/SimpleTutorialEuml2.cpp" target="_top">first</a> and <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">second</a> syntaxes, you
+ will find some unexplained BOOST_MSM_EUML_DECLARE_ATTRIBUTE macros. Let us go
+ back to them. We have:</p><p><code class="code">BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)</code></p><p><code class="code">BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)</code></p><p>This declares two attributes: cd_name of type std::string and cd_type of type
+ DiskTypeEnum. These attributes are not part of any event or state in particular,
+ we just declared a name and a type. Now, we can add attributes to our
+ cd_detected event:</p><p><code class="code">typedef BOOST_TYPEOF(build_attributes(attributes_ << cd_name
+ << cd_type )) cd_detected_attributes;</code></p><p><code class="code">struct cd_detected : euml_event<cd_detected>,cd_detected_attributes
+ {</code></p><p><code class="code">cd_detected(std::string name, DiskTypeEnum diskType) {</code></p><p><code class="code">get_attribute(cd_name)=name;get_attribute(cd_type)=diskType;}</code></p><p><code class="code">};</code></p><p>The two left shift of the first line add both attributes into the helper
+ cd_detected_attributes structure. As cd_detected inherits from the helper, it
+ now has these two attributes. The function get_attribute returns a reference to
+ the required attributes so that we can easily write and set them.</p><p>Ok, great, we now have a two liner to add attributes to a class, which we
+ could have done more easily, so what is the point? The point is that we can now
+ do what was not possible, reference these attributes directly, at compile-time,
+ in the transition table. For example, in the example, you will find this
+ transition:</p><p><code class="code">Stopped == Empty + cd_detected [good_disk_format &&
+ (event_(cd_type)==Int_<DISK_CD>())] </code></p><p>Read event_(cd_type) as event_->cd_type with event_ a type generic for events,
+ whatever the concrete event is (in this particular case, it happens to be a
+ cd_detected as the transition shows).</p><p>The main advantage of this feature is that you do not need to define a new
+ functor and you do not need to look inside the functor to know what it does, you
+ have all at hand.</p><p>MSM provides more generic objects for state machine types:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>event_ : used inside any action, the event triggering the
+ transition</p></li><li class="listitem"><p>state_: used inside entry and exit actions, the entered / exited
+ state</p></li><li class="listitem"><p>source_: used inside a transition action, the source state</p></li><li class="listitem"><p>target_: used inside a transition action, the target state</p></li><li class="listitem"><p>fsm_: used inside any action, the (lowest-level) state machine
+ processing the transition</p></li><li class="listitem"><p>Int_<int value>: a functor representing an int</p></li><li class="listitem"><p>Char_<value>: a functor representing a char</p></li><li class="listitem"><p>Size_t_<value>: a functor representing a size_t</p></li><li class="listitem"><p>String_<mpl::string> (boost >= 1.40): a functor representing a
+ string.</p></li></ul></div><p>These helpers can be used in two different ways:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>helper(attribute_name) returns the attribute with name
+ attribute_name</p></li><li class="listitem"><p>helper returns the state / event type itself.</p></li></ul></div><p>The second form is helpful if you want to use states with self-created
+ functors. In the <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">above
+ tutorial</a>, we provide Empty with an activate_empty method. We would
+ like to create a eUML functor and call it from inside the transition table. This
+ is done using the MSM_EUML_METHOD / MSM_EUML_FUNCTION macros. The first creates
+ a functor to a method, the second to a free function. In the tutorial, we
+ write:</p><p><code class="code">MSM_EUML_METHOD(ActivateEmpty_ , activate_empty , activate_empty_ , void
+ , void )</code></p><p>The first parameter is the functor name, for use either directly or with the
+ functor front-end. The second is the name of the method which will be called.
+ The third is the function name for use in the transition table, the fourth is
+ the return type of the function if used in the context of a transition action,
+ the fifth is the result type if used in the context of a state entry / exit
+ action (usually fourth and fifth are the same). We now have a new eUML function
+ calling a method of "something", and this "something" is one of the five
+ previously explained helpers. We can now use this in a transition, for
+ example:</p><p><code class="code">Empty == Open + open_close /
+ (close_drawer,activate_empty_(target_))</code></p><p>The action is now defined as a sequence of two actions: close_drawer and
+ activate_empty called on the target itself. The target being Empty (the state
+ defined left), this really will call Empty.activate_empty(). This method could
+ also have an (or several) argument(s), for example the event, we could then call
+ activate_empty_(target_ , event_).</p><p>More examples can be found in the <a class="link" href="examples/CompilerStressTestEuml.cpp" target="_top">terrible compiler stress
+ test</a>, the <a class="link" href="examples/SimpleTimer.cpp" target="_top">timer
+ example</a> or in the <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">iPodSearch with eUML</a> (for String_ and more).</p></div><div class="sect3" title="Orthogonal regions, flags, event deferring"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3003"></a>Orthogonal regions, flags, event deferring</h4></div></div></div><p>To define orthogonal regions really means defining more initial states. To add
+ more initial states, “shift left” some, for example, if we had another initial
+ state named AllOk :</p><p><code class="code">typedef BOOST_TYPEOF(build_sm( transition_table(),init_ << Empty
+ << AllOk )) player_;</code></p><p>You remember from the <span class="command"><strong><a class="command" href="ar01s04.html#eUML-build-state">build_state</a></strong></span> and <span class="command"><strong><a class="command" href="ar01s04.html#eUML-build-sm">build_sm</a></strong></span> signatures that just after attributes, we can define
+ flags, like in the basic MSM frontend. To do this, we have another "shift-left"
+ grammar, for example:</p><p><code class="code">typedef BOOST_TYPEOF(build_state(NoAction,NoAction, attributes_ <<
+ no_attributes_, </code></p><p><code class="code">/* flags */ configure_<< PlayingPaused << CDLoaded ))
+ Paused; </code></p><p>We now defined that Paused will get two flags, PlayingPaused and CDLoaded,
+ defined, for example as:</p><p><code class="code">struct CDLoaded : euml_flag<CDLoaded> {};</code></p><p>This corresponds to the following basic front-end definition of Paused:</p><p><code class="code">struct Paused : public msm::front::state<> </code></p><p><code class="code">{ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list; };
+ </code></p><p>Under the hood, what you get really is a mpl::vector2.</p><p><span class="underline">Note</span>: As we use the version of
+ build_state with 4 arguments, we need to tell eUML that we need no attributes.
+ Similarly to a <code class="code">cout << endl</code>, we need a <code class="code">attributes_
+ << no_attributes_</code> syntax.</p><p>You can use the flag with the is_flag_active method of a state machine. You
+ can also use the provided helper function is_flag_ (returning a bool) for state
+ and transition actions. For example, in the iPod implementation with eUML (TODO
+ link), you find the following transition:</p><p><code class="code">ForwardPressed == NoForward + EastPressed
+ [!is_flag_(NoFastFwd)]</code></p><p>The function also has an optional second parameter which is the state machine
+ on which the function is called. by default, fsm_ is used (the current state
+ machine) but you could provide a functor returning a reference to another state
+ machine.</p><p>eUML also supports defining deferred events in the state (state machine)
+ definition. To this aim, we can reuse the flag grammar. For example:</p><p><code class="code">typedef BOOST_TYPEOF(build_state(Empty_Entry,Empty_Exit, attributes_
+ << no_attributes_, </code></p><p><code class="code">/* flags */ configure_<< play )) Empty; </code></p><p>The configure_ left shift is also responsible for deferring events. Shit
+ inside a flag and it will be seen as a flag, shift an event and it will be a
+ deferred event. This replaces the basic front-end definition:</p><p><code class="code">typedef mpl::vector<play> deferred_events;</code></p><p>In <a class="link" href="examples/OrthogonalDeferredEuml.cpp" target="_top">this
+ tutorial</a>, player is defining a second orthogonal region with AllOk as
+ initial state. The <code class="code">Empty</code> and <code class="code">Open</code> states also defer
+ the event <code class="code">play</code>. <code class="code">Open</code>, <code class="code">Stopped</code> and
+ <code class="code">Pause</code> also support the flag <code class="code">CDLoaded</code> using the
+ same left shift into <code class="code">configure_</code>.</p><p>In the functor front_end, we also had the possibility to defer an event inside
+ a transition, which makes possible conditional deferring. This is also possible
+ with eUML through the use of the defer_ order, as shown in <a class="link" href="examples/OrthogonalDeferredEuml.cpp" target="_top">this tutorial</a>. You
+ will find the foillowing transition:</p><p><code class="code">Open + play / defer_</code></p><p>This is an <span class="command"><strong><a class="command" href="ar01s04.html#eUML-internal">internal transition</a></strong></span>.
+ Ignore it for the moment. Interesting is, that when the event <code class="code">play</code>
+ is fired and <code class="code">Open</code> is active, the event will be deferred. Now add a
+ guard and you can conditionally defer the event, for example:</p><p><code class="code">Open + play [ some_condition ] / defer_</code></p><p>This is similar to what we did with the functor front-end. This means that we
+ have the same limitations. Using defer_ instead of a state declaration, we need
+ to tell MSM that we have deferred events in this state machine. We do this
+ (again) using a configure_ declaration in the state machine definition in which
+ we shift the deferred_events configuration flag using the build_sm
+ function:</p><p><code class="code">typedef BOOST_TYPEOF(build_sm( transition_table(),init_ << Empty
+ << AllOk,</code></p><p><code class="code">Entry_Action, Exit_Action, attributes_ << no_attributes_,
+ configure_<< deferred_events )) player_;</code></p><p>A <a class="link" href="examples/OrthogonalDeferredEuml2.cpp" target="_top">tutorial</a>
+ illsutrates this possibility.</p></div><div class="sect3" title="Customizing a state machine / Getting more speed"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3134"></a> Customizing a state machine / Getting more speed</h4></div></div></div><p>We just saw how to use configure_ to define deferred events or flags. We can
+ also use it to configure our state machine like we did with other front-ends
+ (TODO add in standard):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>configure_ << no_exception: disables exception
+ handling</p></li><li class="listitem"><p>configure_ << no_msg_queue deactivates the message
+ queue</p></li></ul></div><p>Deactivating these features if not needed greatly improves the event
+ dispatching speed of your state machine. Our <a class="link" href="examples/EumlSimple.cpp" target="_top">speed testing</a> example with eUML
+ use this feature.</p></div><div class="sect3" title="Anonymous transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3151"></a>Anonymous transitions</h4></div></div></div><p>Anonymous transitions (See <span class="command"><strong><a class="command" href="ar01s03.html#uml-anonymous">UML
+ tutorial</a></strong></span>) are transitions without a named event which are
+ therefore triggered immediately when the source state becomre active, provided a
+ guard allows it. As there is no event, to define such a transition, simply omit
+ the “+” part of the transition (the event), for example: </p><p><code class="code">State3 == State4 [always_true] / State3ToState4</code></p><p><code class="code">State4 [always_true] / State3ToState4 == State3</code></p><p>Please have a look at <a class="link" href="examples/AnonymousTutorialEuml.cpp" target="_top">this example</a>, which implements the <span class="command"><strong><a class="command" href="ar01s04.html#anonymous-transitions">previously defined</a></strong></span> state
+ machine with eUML.</p></div><div class="sect3" title="Internal transitions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3173"></a><span class="command"><strong><a name="eUML-internal"></a></strong></span>Internal transitions</h4></div></div></div><p>Like both other front-ends, eUML supports two ways of defining internal transitions:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>in the state machine's transition table. In this case, you need to
+ specify a source state, event, actions and guards but no target
+ state, which eUML will interpret as an internal transition, for
+ example this defines a transition internal to Open, on the event
+ open_close:</p><p><code class="code">Open + open_close [internal_guard1] /
+ internal_action1</code></p><p><a class="link" href="examples/EumlInternal.cpp" target="_top">A full example</a>
+ is also provided.</p></li><li class="listitem"><p>in a state's <code class="code">internal_transition_table</code>. For
+ example:</p><p><code class="code">typedef BOOST_TYPEOF(build_state( Open_Entry(),Open_Exit()
+ )) Open_def;</code></p><p><code class="code">struct Open : public Open_def {</code></p><p><code class="code">typedef BOOST_TYPEOF(build_internal_stt((</code></p><p><code class="code">open_close [internal_guard1] /
+ internal_action1</code></p><p><code class="code">) ) ) internal_transition_table;</code></p><p><code class="code">};</code></p><p>Notice how we do not need to repeat that the transition originates
+ from Open as we already are in the context of Open. </p><p>The <a class="link" href="examples/EumlInternalDistributed.cpp" target="_top">implementation</a> also shows the added bonus offered for
+ submachines, which can have both the standard transition_table and
+ an internal_transition_table (which has higher priority). This makes
+ it easier if you decide to make a full submachine from a state. It
+ is also slightly faster than the standard alternative, adding
+ orthogonal regions, because event dispatching will, if accepted by
+ the internal table, not continue to the subregions. This gives you a
+ O(1) dispatch instead of O(number of regions).</p></li></ul></div></div><div class="sect3" title="Direct entry / entry and exit pseudo-state / fork"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3221"></a>Direct entry / entry and exit pseudo-state / fork</h4></div></div></div><p>We saw the <span class="command"><strong><a class="command" href="ar01s04.html#eUML-build-state">build_state</a></strong></span>
+ function, which creates a simple state. Likewise, eUML provides other
+ state-building functions for other types of states:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>build_terminal_state takes the same arguments as build_state and
+ defines, well, a terminate state.</p></li><li class="listitem"><p>build_interrupt_state takes the same arguments as build_state and
+ defines an interrupt state.</p></li><li class="listitem"><p>build_exit_state takes the same arguments as build_state and
+ defines an exit pseudo state.</p></li><li class="listitem"><p>build_entry_state takes the same arguments as build_state and
+ defines an interrupt state. The region index to be entered is
+ defined as an int template argument, so build_entry_state<0>
+ defines an entry state into the first region of a submachine.</p></li><li class="listitem"><p>build_explicit_entry_state takes the same arguments as build_state
+ and defines an explicit entry state. The region index to be entered
+ is defined as an int template argument, so
+ build_explicit_entry_state<0> defines an explicit entry state
+ into the first region of a submachine.</p></li></ul></div><p>Using these states in the transition table is like in any other front end
+ using fsm_name::exit_pt<>, fsm_name::direct<> and fsm_name::entry_pt<>.
+ For example, a direct entry could be:</p><p><code class="code">SubFsm2::direct<SubState2> == State1 + event2</code></p><p>Forks being a list on direct entries, eUML supports a logical syntax (state1,
+ state2, ...), for example:</p><p><code class="code">(SubFsm2::direct<SubState2>, SubFsm2::direct<SubState2b>,
+ SubFsm2::direct<SubState2c>) == State1 + event3</code></p><p>The <a class="link" href="examples/DirectEntryEuml.cpp" target="_top">entry tutorial</a> is
+ also available with eUML.</p></div><div class="sect3" title="Helper functions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3260"></a>Helper functions</h4></div></div></div><p>We saw a few helpers but there are more, so let us have a more complete description:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>event_ : used inside any action, the event triggering the
+ transition</p></li><li class="listitem"><p>state_: used inside entry and exit actions, the entered / exited
+ state</p></li><li class="listitem"><p>source_: used inside a transition action, the source state</p></li><li class="listitem"><p>target_: used inside a transition action, the target state</p></li><li class="listitem"><p>fsm_: used inside any action, the (lowest-level) state machine
+ processing the transition</p></li><li class="listitem"><p>The previous objects can also return an attribute, for example
+ event_(cd_name)</p></li><li class="listitem"><p>Int_<int value>: a functor representing an int</p></li><li class="listitem"><p>Char_<value>: a functor representing a char</p></li><li class="listitem"><p>Size_t_<value>: a functor representing a size_t</p></li><li class="listitem"><p>True_ and False_ functors returning true and false
+ respectively</p></li><li class="listitem"><p>String_<mpl::string> (boost >= 1.40): a functor representing a
+ string.</p></li><li class="listitem"><p>if_then_else_(guard, action, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>if_then_(guard, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>while_(guard, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>do_while_(guard, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>for_(action, guard, action, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>process_(some_event [, some state machine] [, some state machine]
+ [, some state machine] [, some state machine]) will call
+ process_event (some_event) on the current state machine or on the
+ one(s) passed as 2nd , 3rd, 4th, 5th argument. This allow sending
+ events to several external machines</p></li><li class="listitem"><p>process2_(some_event,Value [, some state machine] [, some state
+ machine] [, some state machine]) will call process_event
+ (some_event(Value)) on the current state machine or on the one(s)
+ passed as 3rd, 4th, 5th argument</p></li><li class="listitem"><p>is_ flag_(some_flag[, some state machine]) will call
+ is_flag_active on the current state machine or on the one passed as
+ 2nd argument</p></li><li class="listitem"><p>Predicate_<some predicate>: Used in STL algorithms. Wraps
+ unary/binary functions to make them eUML-compatible so that they can
+ be used in STL algorithms</p></li></ul></div><p>This can make for quite some fun. For example, </p><p><code class="code">/( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(),/*if
+ clause*/</code></p><p><code class="code">show_playing_song(), /*then clause*/</code></p><p><code class="code">(fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay())) /*else clause*/ )
+ )</code> means:</p><p>if (fsm.SongIndex > 0, call show_playing_song else {fsm.SongIndex=1; process
+ EndPlay on fsm;}</p><p>A few examples are using these features:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>the iPod example introduced at the BoostCon09 <a class="link" href="examples/iPodEuml.cpp" target="_top">has been rewritten</a>
+ with eUML (weak compilers please move on...)</p></li><li class="listitem"><p>the iPodSearch example also introduced at the BoostCon09 <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">has been
+ rewritten</a> with eUML. In this example, you will also find
+ some examples of STL functor usage.</p></li><li class="listitem"><p><a class="link" href="examples/SimpleTimer.cpp" target="_top">A simpler timer</a>
+ example is a good starting point. </p></li></ul></div><p>There is unfortunately a small catch. Defining a functor using MSM_EUML_METHOD
+ or MSM_EUML_FUNCTION will create a correct functor. Your own eUML functors
+ written as described at the beginning of this section will also work well,
+ <span class="underline">except</span> with the while_, if_then_,
+ if_then_else_ functions which will require a bit of writing. TODO macro.</p></div><div class="sect3" title="Phoenix-like STL support"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3365"></a>Phoenix-like STL support</h4></div></div></div><p>As we saw, eUML supports most C++ operators (except address-of). For example
+ it is possible to write event_(some_attribute)++ or [source_(some_bool)
+ && fsm_(some_other_bool)]. But a programmer needs more than operators in
+ his daily programming. The STL is clearly a must have. Therefore, eUML comes in
+ with a lot of functors to simplify your day-to-day programming. For almost every
+ algorithm or container method of the STL, a corresponding eUML function is
+ defined. Like Boost.Phoenix, “.” And “->” of call on objects are replaced by a
+ functional programming paradigm, for example:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>begin_(container), end_(container): returns iterators of a
+ container.</p></li><li class="listitem"><p>empty_(container): returns container.empty()</p></li><li class="listitem"><p>clear_(container): container.clear()</p></li><li class="listitem"><p>transform_ : std::transform</p></li></ul></div><p>In a nutshell, almost every STL method or algorithm is matched by a
+ corresponding functor, which can then be used in the transition table or state
+ actions. The reference (TODO link) explains in detail the usage and the
+ underlying functor (so that this possibility is not reserved to eUML but also to
+ the functor-based front-end). The file structure of this Phoenix-like library
+ matches the one of Boost.Phoenix. All STL algorithm functors are to be found
+ in:</p><p><code class="code">#include <msm/front/euml/algorithm.hpp></code></p><p>The algorithms are also divided into sub-headers, matching the phoenix
+ structure for simplicity:</p><p><code class="code">#include < msm/front/euml/iteration.hpp> </code></p><p><code class="code">#include < msm/front/euml/transformation.hpp> </code></p><p><code class="code">#include < msm/front/euml/querying.hpp> </code></p><p>Container methods can be found in:</p><p><code class="code">#include < msm/front/euml/container.hpp></code></p><p>Or one can simply include the whole STL support (you will also need to include
+ euml.hpp):</p><p><code class="code">#include < msm/front/euml/stl.hpp></code></p><p>A few examples (to be found in <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">this tutorial</a>):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">push_back_(fsm_(m_tgt_container),event_(m_song))</code>: the
+ state machine has an attribute m_tgt_container of type
+ std::vector<OneSong> and the event has an attribute m_song of
+ type OneSong. The line therefore pushes m_song at the end of
+ m_tgt_container</p></li><li class="listitem"><p><code class="code">if_then_( state_(m_src_it) != end_(fsm_(m_src_container)),
+ process2_(OneSong(),*(state_(m_src_it)++)) )</code>: the current
+ state has an attribute m_src_it (an iterator). If this iterator !=
+ fsm.m_src_container.end(), process OneSong on fsm, copy-constructed
+ from state.m_src_it which we post-increment</p></li></ul></div></div></div><div class="sect2" title="Back-end"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3425"></a>Back-end</h3></div></div></div><p>There is, at the moment, one back-end. This back-end contains the library engine
+ and defines the performance and functionality tradeoffs. The currently available
+ back-end implements most of the functionality defined by the UML 2.0 standard at
+ very high runtime speed, in exchange for longer compile-time. The runtime speed is
+ due to a constant-time double-dispatch and self-adapting capabilities allowing the
+ framework to adapt itself to the features used by a given concrete state machine.
+ All unneeded features either disable themselves or can be manually disabled. See
+ section 5.1 for a complete description of the run-to-completion algorithm.</p><div class="sect3" title="MSM Backend features"><div class="titlepage"><div><div><h4 class="title"><a name="d0e3430"></a> MSM Backend features </h4></div></div></div><p>TODO</p><p></p><div class="sect4" title="Creation"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3436"></a> Creation </h5></div></div></div><p> MSM being divided betwenn front and back-end, one needs to first define a
+ front-end. Then, to create a real state machine, the back-end must be
+ created: <code class="code">typedef msm::back::state_machine<my_front_end>
+ my_fsm;</code>
+ </p><p>We now have a fully functional state machine. The next sections will
+ describe what can be done with it.</p></div><div class="sect4" title="Event dispatching"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3446"></a>Event dispatching</h5></div></div></div><p>The main reason to exist for a state machine is to dispatch events. For
+ MSM, events are objects of a given event type. The object itself can contain
+ data, but the event type is what decides of the transition to be taken. For
+ MSM, if some_event is a given type (a simple struct for example) and e1 and
+ e2 concrete events, e1 and e2 are equivalent, from a transition perspective.
+ Of course, e1 and e2 can have different values and you can use them inside
+ actions. Events are dispatched as const reference, so actions cannot modify
+ events for obvious side-effect reasons. To dispatch an event of type
+ some_event, you can simply write: </p><p><code class="code">my_fsm fsm; fsm.process_event(some_event());</code></p><p><code class="code">some_event e1; fsm.process_event(e1)</code></p><p>Creating an event on the fly will be optimized by the compiler so the
+ performance will not degrade.</p></div><div class="sect4" title="Active state(s)"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3459"></a>Active state(s)</h5></div></div></div><p>The backend also offers a way to know which state is active, though you
+ will normally only need this for debugging purposes. If what you need simply
+ is doing something with the active state, <span class="command"><strong><a class="command" href="ar01s03.html#UML-internal-transition">internal transitions</a></strong></span> or
+ <span class="command"><strong><a class="command" href="ar01s04.html#backend-visitor">visitors</a></strong></span> are a better
+ alternative. If you need to know what state is active, const int*
+ current_state() will return an array of state ids. Please refer to the
+ <span class="command"><strong><a class="command" href="ar01s07.html#internals-state-id">internals section</a></strong></span> to
+ know how state ids are generated.</p></div><div class="sect4" title="Base state type"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3473"></a> Base state type </h5></div></div></div><p>Sometimes, one needs to customize states to avoid repetition and provide a
+ common functionality, for example in the form of a virtual method. You might
+ also want to make your states polymorphic so that you can call typeid on
+ them for logging or debugging. It is also useful if you need a visitor, like
+ the next section will show. You will notice that all front-ends offer the
+ possibility of adding a base type. Not that all states and state machines
+ must have the same base state, so this could reduce reuse. For example,
+ using the basic front end, you need to:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Add the non-default base state in your msm::front::state<>
+ definition, as first template argument (except for
+ interrupt_states for which it is the second argument, the first
+ one being the event ending the interrupt), for example,
+ my_base_state being your new base state for all states in a
+ given state machine: <code class="code">struct Empty : public
+ msm::front::state<my_base_state></code> Now,
+ my_base_state is your new base state. If it has a virtual
+ function, your states become polymorphic. MSM also provides a
+ default polymorphic base type for your convenience,
+ <code class="code">msm::front::polymorphic_state</code>
+ </p></li><li class="listitem"><p>Add the user-defined base state in the state machine frontend
+ definition, as a second template argument, for example:
+ <code class="code">struct player_ : public
+ msm::front::state_machine<player_,my_base_state>
+ </code></p></li></ul></div><p>You can also ask for a state with a given id (which you might have gotten
+ from current_state()) using <code class="code">const base_state* get_state_by_id(int id)
+ const</code> where base_state is the one you just defined. You can now
+ do something ploymorphically. For example using the visitor.</p></div><div class="sect4" title="Visitor"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3498"></a><span class="command"><strong><a name="backend-visitor"></a></strong></span>Visitor</h5></div></div></div><p>In some cases, having a pointer-to-base of the currently active states is
+ not enough. You might want to call non-virtually a method of the currently
+ active states. It will not be said that MSM forces the virtual keyword down
+ your throat!</p><p>To achieve this goal, MSM provides its own variation of a visitor pattern
+ using the previously described user-defined state technique. If you add to
+ your user-defined base state an <code class="code">accept_sig</code> typedef giving the
+ return value (unused for the moment) and signature and provide an accept
+ method with this signature, calling visit_current_states will cause accept
+ to be called on the currently active states. Typically, you will also want
+ to provide an empty default accept in your base state in order in order not
+ to force all your states to implement accept. For example your base state
+ could be:</p><p><code class="code">struct my_visitable_state{</code></p><p><code class="code">// signature of the accept function</code></p><p><code class="code">typedef args<void> accept_sig;</code></p><p><code class="code">// we also want polymorphic states</code></p><p><code class="code">virtual ~my_visitable_state() {}</code></p><p><code class="code">// default implementation for states who do not need to be
+ visited</code></p><p><code class="code">void accept() const {}</code></p><p><code class="code">};</code></p><p>This makes your states polymorphic and visitable. In this case, accept is
+ made const and takes no argument. It could also be:</p><p><code class="code">struct SomeVisitor {…};</code></p><p><code class="code">struct my_visitable_state{</code></p><p><code class="code">// signature of the accept function</code></p><p><code class="code">typedef args<void,SomeVisitor&> accept_sig;</code></p><p><code class="code">// we also want polymorphic states</code></p><p><code class="code">virtual ~my_visitable_state() {}</code></p><p><code class="code">// default implementation for states who do not need to be
+ visited</code></p><p><code class="code">void accept(SomeVisitor&) const {}</code></p><p><code class="code">};</code></p><p>And now, accept will take one argument (it could also be non-const). By
+ default, accept takes up to 2 arguments. To get more, add a #define
+ BOOST_MSM_VISITOR_ARG_SIZE to another value before including
+ state_machine.hpp. For example:</p><p><code class="code">#define BOOST_MSM_VISITOR_ARG_SIZE 3</code></p><p><code class="code">#include <boost/msm/back/state_machine.hpp></code></p><p>Note that accept will be called on ALL active states <span class="underline">and also automatically on sub-states of a
+ submachine</span>.</p><p><span class="underline">Important warning</span>: The method
+ visit_current_states takes its parameter by value, so if the signature of
+ the accept function is to contain a parameter passed by reference, pass this
+ parameter with a boost:ref/cref to avoid undesired copies or slicing. So,
+ for example, in the above case, call:</p><p><code class="code">SomeVisitor vis; sm.visit_current_states(boost::ref(vis));
+ </code></p><p>This <a class="link" href="examples/SM-2Arg.cpp" target="_top">example</a> uses a
+ visiting function with 2 arguments.</p></div><div class="sect4" title="Flags"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3587"></a>Flags</h5></div></div></div><p>Flags is a MSM-only concept, supported by all front-ends, which base
+ themselves on the functions: </p><p><code class="code">template <class Flag> bool is_flag_active()</code> and</p><p><code class="code">template <class Flag,class BinaryOp> bool is_flag_active()</code>
+ </p><p>These functions return true if the currently active state(s) support the
+ Flag property. The first variant ORs the result if there are several
+ orthogonal regions, the second one expects OR or AND, for example:</p><p><code class="code">my_fsm.is_flag_active<MyFlag>()</code></p><p><code class="code">my_fsm.is_flag_active<MyFlag,my_fsm_type::Flag_OR>()</code></p><p>Please refer to the front-ends sections for more information.</p></div><div class="sect4" title="Getting a state"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3610"></a>Getting a state</h5></div></div></div><p>It is sometimes necessary to have the client code get access to the
+ states' data. After all, the states are created once for good and hang
+ around as long as the state machine does so why not use it? You simply just
+ need sometimes to get information about any state, even inactive ones. An
+ example is if you want to write a coverage tool and know how many times a
+ state was visited. To get a state, use the get_state method giving the state
+ name, for example: </p><p><code class="code">player::Stopped* tempstate =
+ p.get_state<player::Stopped*>();</code> or </p><p><code class="code">player::Stopped& tempstate2 =
+ p.get_state<player::Stopped&>();</code> depending on your
+ personal taste. </p></div><div class="sect4" title="State machine constructor with arguments"><div class="titlepage"><div><div><h5 class="title"><a name="d0e3623"></a> State machine constructor with arguments </h5></div></div></div><p>You might want to define a state machine with a non-default constructor.
+ For example, you might want to write: </p><p><code class="code">struct player_ : public msm::front::state_machine_def<player_> {
+ player_(int some_value){…} } </code></p><p>This is possible, using the back-end as forwarding object: </p><p><code class="code">typedef msm::back::state_machine<player_ > player; player
+ p(3);</code> The back-end will call the corresponding front-end
+ constructor upon creation.</p><p>You can pass arguments up to the value of the
+ BOOST_MSM_CONSTRUCTOR_ARG_SIZE macro (currently 5) arguments. Change this
+ value before including any header if you need to change it. </p></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s03.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">UML Short Guide </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Performance / Compilers</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ar01s05.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s05.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,69 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Performance / Compilers</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="ar01s04.html" title="User's Guide"><link rel="next" href="ar01s06.html" title="Questions & Answers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center"> Performance / Compilers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s04.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s06.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Performance / Compilers"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3639"></a> Performance / Compilers</h2></div></di
v></div><p>Tests were made on different PCs running Windows XP and Vista and compiled with VC9
+ SP1 or Ubuntu and compiled with g++ 4.2 and 4.3. For these tests, the same player state
+ machine was written using Boost.Statechart, as a <a class="link" href="examples/SC Simple.cpp" target="_top">state machine with only simple states</a> and
+ as a <a class="link" href="examples/SC Composite.cpp" target="_top">state machine with a composite
+ state</a>. The same simple and composite state machines are implemented with MSM
+ with a standard frontend <a class="link" href="examples/MsmSimple.cpp" target="_top">(simple)</a><a class="link" href="examples/MsmComposite.cpp" target="_top">(composite)</a>, the simple one also with
+ <a class="link" href="examples/MsmSimpleFunctors.cpp" target="_top">functors</a> and with <a class="link" href="examples/EumlSimple.cpp" target="_top">eUML</a>. As these simple machines need no
+ terminate/interrupt states, no message queue and have no-throw guarantee on their
+ actions, the MSM state machines are defined with minimum functionality.</p><div class="sect2" title="Speed"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3661"></a>Speed</h3></div></div></div><p>VC9:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>The simple test completes 36 times faster with Msm than with
+ Boost.Statechart</p></li><li class="listitem"><p>The composite test completes 18 times faster with MSM</p></li><li class="listitem"><p>The fastest version is with eUML/functors. It completes 58 times
+ faster than Boost.Statechart. A transition costs 4.5ns on a
+ Q6600.</p></li></ul></div><p>gcc 4.2.3:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>The simple test completes 54 times faster with Msm (with
+ functors)</p></li><li class="listitem"><p>The composite test completes 25 times faster with Msm</p></li></ul></div></div><div class="sect2" title="Executable size"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3685"></a>Executable size</h3></div></div></div><p>There are some worries that MSM generates huge code. Is it true? The 2 compilers I
+ tested disagree with this claim. On VC9, the test state machines used in the
+ performance section produce executables of 14kB (for simple and eUML) and 21kB (for
+ the composite). This includes the test code and iostreams. By comparison, an empty
+ executable with iostreams generated by VC9 has a size of 7kB. Boost.Statechart
+ generates executables of 43kB and 54kB. As a bonus, eUML comes for “free” in terms
+ of executable size. You even get a speed gain. With g++ 4.3, it strongly depends on
+ the compiler options (much more than VC). A good size state machine with –O3 can
+ generate an executable of 600kB, and with eUML you can get to 1.5MB. Trying with –Os
+ –s I come down to 18kB and 30kB for the test state machines, while eUML will go down
+ to 1MB (which is still big), so in this case eUML does not come for free.</p></div><div class="sect2" title="Supported compilers"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3690"></a>Supported compilers</h3></div></div></div><p> MSM was successfully tested with: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>VC8 (please read further), VC9SP1, VC10 Beta 1 and 2</p></li><li class="listitem"><p>g++ 4.1 and higher</p></li><li class="listitem"><p>Green Hills Software MULTI for ARM v5.0.5 patch 4416 (Simple and
+ Composite tutorials)</p></li></ul></div><p> eUML will only work with: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>VC8 (partly). You cannot, however use any overloaded function (like
+ splice) and compile times and RAM consumption explode</p></li><li class="listitem"><p>VC9SP1, VC10 Beta1-2</p></li><li class="listitem"><p>g++ 4.3 and higher (previous versions lack native typeof
+ support)</p></li></ul></div><p>VC8 and to some lesser extent VC9 suffer from a bug. Enabling the option "Enable
+ Minimal Rebuild" (/Gm) will cause much higher compile-time (up to three times with
+ VC8!). This option being activated per default in Debug mode, this can be a big
+ problem.</p></div><div class="sect2" title="Limitations"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3719"></a> Limitations </h3></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Compilation times of state machines with > 80 transitions that are
+ going to make you storm the CFO's office and make sure you get a shiny
+ octocore with 8GB RAM by next week, unless he's interested in paying you
+ watch the compiler agonize for hours... (Make sure you ask for dual 24"
+ as well, it doesn't hurt).</p></li><li class="listitem"><p>eUML allows very long constructs but will also quickly increase your
+ compile time on some compilers (VC9, VC10 Beta1) with buggy decltype
+ support (I suspect some at least quadratic algorithms there). Even g++
+ 4.4 shows some regression compared to 4.3 and will crash if the
+ constructs become too big.</p></li><li class="listitem"><p>Need to overwrite the mpl::vector/list default-size-limit of 20 and
+ fusion default vector size of 10 if more than 10 states found in a state
+ machine</p></li></ul></div><p>
+ </p></div><div class="sect2" title="Compilers corner"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3735"></a> Compilers corner </h3></div></div></div><p>Compilers are sometimes full of surprises and such strange errors happened in the
+ course of the development that I wanted to list the most fun for readers’
+ entertainment.</p><p><span class="underline">VC8</span>: </p><p><code class="code">template <class StateType> </code></p><p><code class="code">typename ::boost::enable_if< </code></p><p><code class="code">typename ::boost::mpl::and_<</code></p><p><code class="code">typename ::boost::mpl::not_<typename
+ has_exit_pseudo_states<StateType>::type>::type, </code></p><p><code class="code">typename ::boost::mpl::not_<typename
+ is_pseudo_exit<StateType>::type>::type >::type,BaseState*>::type
+ </code></p><p>I get the following error:</p><p>error C2770: invalid explicit template argument(s) for '`global
+ namespace'::boost::enable_if<is_pseudo_exit<StateType>::type,BaseState*>::type
+ boost::msm::state_machine<Derived,HistoryPolicy,BaseState>::add_state<ContainingSM>::new_state_helper(boost::msm::dummy<__formal>)
+ const' </p><p>If I now remove the first “::” in ::boost::mpl , the compiler shuts up. So in this
+ case, it is not possible to follow Boost’s guidelines.</p><p><span class="underline">VC9</span>:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>This one is my all times’ favorite. Do you know why the exit pseudo
+ states are referenced in the transition table with a
+ “submachine::exit_pt” ? Because “exit” will crash the compiler. “Exit”
+ is not possible either because it will crash the compiler on one
+ machine, but not on another (the compiler was installed from the same
+ disk).</p></li><li class="listitem"><p>Sometimes, removing a policy crashes the compiler, so some versions
+ are defining a dummy policy called WorkaroundVC9.</p></li><li class="listitem"><p>Typeof: While g++ and VC9 compile “standard” state machines in
+ comparable times, Typeof (while in both ways natively supported) seems
+ to behave in a quadratic complexity with VC9 and VC10.</p></li><li class="listitem"><p>eUML: in case of a compiler crash, changing the order of state
+ definitions (first states without entry or exit) sometimes solves the
+ problem.</p></li></ul></div><p><span class="underline">g++ 4.x</span>: Boring compiler, almost all is
+ working almost as expected. Being not a language lawyer I am unsure about the
+ following “Typeof problem”. VC9 and g++ disagree on the question if you can derive
+ from the BOOST_TYPEOF generated type without first defining a typedef. I will be
+ thankful for an answer on this. I only found two ways to break the compiler:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Add more eUML constructs until something explodes (especially with
+ g++-4.4) </p></li><li class="listitem"><p>The build_terminate function uses 2 mpl::push_back instead of
+ mpl::insert_range because g++ would not accept insert_range.</p></li></ul></div><p>You can test your compiler’s decltype implementation with the <a class="link" href="examples/CompilerStressTestEuml.cpp" target="_top">following stress test</a>
+ and reactivate the commented-out code until the compiler crashes.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s04.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">User's Guide </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Questions & Answers</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ar01s06.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s06.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,29 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Questions & Answers</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="ar01s05.html" title="Performance / Compilers"><link rel="next" href="ar01s07.html" title="Internals"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Questions & Answers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Questions & Answers"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3798"></a>Questions & Answers</h2></div></div></d
iv><p><span class="underline">Question</span>: on_entry gets as argument, the sent
+ event. What event do I get when the state becomes default-activated (because it is an
+ initial state)?</p><p>
+ <span class="underline">Answer</span>: To allow you to know that the state was
+ default-activated, MSM generates a boost::msm::InitEvent default event. </p><p><span class="underline">Question</span>: Why do I see no call to no_transition
+ in my composite state? </p><p><span class="underline">Answer</span>: Because of the priority rule defined by
+ UML. It says that in case of transition conflict, the most inner state has a higher
+ priority. So after asking the inner state, the containing composite has to be also asked
+ to handle the transition and could find a possible transition.</p><p><span class="underline">Question</span>: Why do I get a compile error saying
+ the compiler cannot convert to a function ...Fsm::*(some_event)? </p><p><span class="underline">Answer</span>: You probably defined a transition
+ triggered by the event some_event, but used a guard/action method taking another event. </p><p><span class="underline">Question</span>: Why do I get a compile error saying
+ something like “too few” or “too many” template arguments? </p><p><span class="underline">Answer</span>: You probably defined a transition in
+ form of a a_row or g_row where you wanted just a _row or the other way around. With Row,
+ it could mean that you forgot a "none". </p><p><span class="underline">Question</span>: Why do I get a very long compile error
+ when I define more than 20 rows in the transition table? </p><p><span class="underline">Answer</span>: MSM uses Boost.MPL under the hood and
+ this is the default maximum size. Please define the following 3 macros before including
+ any MSM headers: </p><p><code class="code">#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS </code></p><p><code class="code">#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 // or whatever you need </code></p><p><code class="code">#define BOOST_MPL_LIMIT_MAP_SIZE 30 // or whatever you need </code></p><p><span class="underline">Question</span>: Why do I get this error: ”error C2977:
+ 'boost::mpl::vector' : too many template arguments”? </p><p><span class="underline">Answer</span>: The first possibility is that you
+ defined a transition table as, say, vector17 and have 18 entries. The second is that you
+ have 17 entries and have a composite state. Under the hood, MSM adds a row for every
+ event in the composite transition table. The third one is that you used a mpl::vector
+ without the number of entries but are close to the MPL default of 50 and have a
+ composite, thus pushing you above 50. Then you need mpl/vector60/70….hpp and a
+ mpl/map60/70….hpp </p><p><span class="underline">Question</span>: Why do I get a very long compile error
+ when I define more than 10 states in a state machine? </p><p><span class="underline">Answer</span>: Msm uses Boost.Fusion under the hood and
+ this is the default maximum size. Please define the following macro before including any
+ MSM headers: </p><p><code class="code">#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need </code></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s05.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> Performance / Compilers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Internals</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ar01s07.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s07.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,149 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Internals</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="ar01s06.html" title="Questions & Answers"><link rel="next" href="ar01s08.html" title="Acknowledgements"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Internals</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s06.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s08.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Internals"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3870"></a>Internals</h2></div></div></div><p>This chapter describes the internal machine
ry of the back-end, which can be useful for
+ UML experts but can be safely ignored for most users. For implementers, the interface
+ between front- and back- end is also described in detail.</p><div class="sect2" title="Backend: Run To Completion"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3875"></a><span class="command"><strong><a name="run-to-completion"></a></strong></span>Backend: Run To Completion</h3></div></div></div><p>The back-end implements the following run-to completion algorithm:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Check if one region of the concrete state machine is in a terminate or
+ interrupt state. If yes, event processing is disabled while the
+ condition perdures (forever for a terminate pseudo-state, while active
+ for an interrupt pseudo-state).</p></li><li class="listitem"><p>If the message queue feature is enabled and if the state machine is
+ already processing an event, push the currently processed event into the
+ queue and end processing. Otherwise, notice that the state machine is
+ now processing an event and continue.</p></li><li class="listitem"><p>If the state machine detected that no deferred event is used, skip
+ this step. Otherwise, mark the first deferred event from the deferred
+ queue as active.</p></li><li class="listitem"><p>Now start the core of event dispatching. If exception handling is
+ activated, this will happen inside a try/catch block and the front-end
+ <code class="code">exception_caught</code> is called if an exception occurs.
+ </p></li><li class="listitem"><p>The event is now dispatched in turn to every region, in the order
+ defined by the initial state front-end definition. This will, for every
+ region, call the corresponding front-end transition definition (the
+ "row" or "Row" of the transition table).</p></li><li class="listitem"><p>Without transition conflict, if for a given region a transition is
+ possible, the guard condition is checked. If it returns
+ <code class="code">true</code>, the transition processing continues and the
+ current state's exit action is called, followed by the transition action
+ and the new active state's entry action.</p></li><li class="listitem"><p>With transition conflicts (several possible transitions, disambiguated
+ by mutually exclusive guard conditions), the guard conditions are tried
+ in reverse order of their transition definition in the transition table.
+ The first one returning <code class="code">true</code> selects its transition. Note
+ that this is not defined by the UML standard, which simply specifies
+ that if the guard conditions are not mutually exclusive, the state
+ machine is ill-formed and the behaviour undefined. Relying on this
+ implementation-specific behaviour will make it harder for the developer
+ to support another state machine framework.</p></li><li class="listitem"><p>If at least one region processes the event, this event is seen as
+ having been accepted. If not, the library calls
+ <code class="code">no_transition</code> on the state machine for every contained
+ region.</p></li><li class="listitem"><p>If the currently active state is a submachine, the behaviour is
+ slightly different. The UML standard specifies that internal transitions
+ have to be tried first, so the event is first dispatched to the
+ submachine. Only if the submachine does not accept the event are other
+ (non internal) transitions tried.</p></li><li class="listitem"><p>This back-end supports simple states' and submachines' internal
+ transitions. These are provided in the state's
+ <code class="code">internal_transition_table</code> type. Transitions defined in
+ this table are added at the end of the main state machine's transition
+ table, but with a lesser priority than the submachine's transitions
+ (defined in <code class="code">transition_table</code>). This means, for simple
+ states, that these transitions have higher priority than non-internal
+ transitions, conform to the UML standard which gives higher priority to
+ deeper-level transitions. For submachines, this is a non-standard
+ addition which can help make event processing faster by giving a chance
+ to bypass subregion processing. With standard UML, one would need to add
+ a subregion only to process these internal transitions, which would be
+ slower.</p></li><li class="listitem"><p>After the dispatching itself, the deferred event marked in step 3 (if
+ any) now gets a chance of processing.</p></li><li class="listitem"><p>Then, events queued in the message queue also get a dispatching
+ chance</p></li><li class="listitem"><p>Finally, compound events (transitions without a named event), if to be
+ found in the transition table, also get their dispatching chance.</p></li></ul></div><p>This algorithm illustrates how the back-end configures itself at compile-time as
+ much as possible. Every feature not found in a given state machine definition is
+ deactivated and has therefore no runtime cost. Compound events, deferred events,
+ terminate states, dispatching to several regions, internal transitions are all
+ deactivated if not used. Only for exception handling and message queue is user
+ configuration necessary.</p></div><div class="sect2" title="Frontend / Backend interface"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3941"></a>Frontend / Backend interface</h3></div></div></div><p>The design of MSM tries to make front-ends and back-ends (later) to be as
+ interchangeable as possible. Of course, Of course, no back-end will ever implement
+ every feature defined by any possible front-end and inversely, but the goal is to
+ make it as easy as possible to extend the current state of the library.</p><p>To achieve this, MSM divides the functionality between both sides: the front-end
+ is a sort of user interface and is descriptive, the back-end implements the state
+ machine engine.</p><p>MSM being based on a transition table, a concrete state machine (or a given
+ front-end) must provide a transition_table. This transition table must be made of
+ rows. And each row must tell what kind of transition it is and implement the calls
+ to the actions and guards. A state machine must also define its regions (marked by
+ initial states) And that is about the only constraints for front-ends. How the rows
+ are described is implementer's choice. </p><p>Every row must provide:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>A <code class="code">Source</code> typedef indicating, well, the type of the source
+ state.</p></li><li class="listitem"><p>A <code class="code">Target</code> typedef indicating, well, the type of the target
+ state.</p></li><li class="listitem"><p>A <code class="code">Evt</code> typedef indicating the type of the event triggering the
+ transition.</p></li><li class="listitem"><p>A <code class="code">row_type_tag</code> typedef indicating the type of the
+ transition.</p></li><li class="listitem"><p>Rows having a type requiring transition actions must provide a static
+ function <code class="code">action_call</code> with the following signature: <code class="code">
+ template <class Fsm,class SourceState,class TargetState,class
+ AllStates> </code></p><p><code class="code">static void action_call (Fsm& fsm, Event const& evt,
+ SourceState&, TargetState&, AllStates&) </code></p><p>The function gets as parameters the (back-end) state machine, the event,
+ source and target states and a container (in the current back-end, a
+ fusion::set) of all the states defined in the state machine. For example, as
+ the back-end has the front-end as basic class, <code class="code">action_call</code> is
+ simply defined as <code class="code">(fsm.*action)(evt)</code>.</p></li><li class="listitem"><p>Rows having a type requiring a guard must provide a static function
+ <code class="code">guard_call</code> with the following signature:<code class="code"> </code></p><p><code class="code">template <class Fsm,class SourceState,class TargetState,class
+ AllStates></code></p><p><code class="code">static bool guard_call (Fsm&, Event const&,
+ SourceState&, TargetState&, AllStates&)</code></p></li><li class="listitem"><p>The possible transition (row) types are:</p><div class="itemizedlist"><ul class="itemizedlist" type="circle"><li class="listitem"><p>a_row_tag: a transition with actions and no guard</p></li><li class="listitem"><p>g_row_type: a transition with a guard and no actions</p></li><li class="listitem"><p>_row_tag: a transition without actions or guard</p></li><li class="listitem"><p>row_tag: a transition with guard and actions</p></li><li class="listitem"><p>a_irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) with actions</p></li><li class="listitem"><p>g_irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) with guard</p></li><li class="listitem"><p>irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) with actions and
+ guards</p></li><li class="listitem"><p>_irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) without action or guard. Due
+ to higher priority for internal transitions, this is quivalent
+ to a "ignore event"</p></li><li class="listitem"><p>sm_a_i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) with actions</p></li><li class="listitem"><p>sm_g_i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) with guard</p></li><li class="listitem"><p>sm_i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) with actions and
+ guards</p></li><li class="listitem"><p>sm__i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) without action or
+ guard. Due to higher priority for internal transitions, this is
+ quivalent to a "ignore event"</p></li></ul></div></li></ul></div><p>Furthermore, a front-end must provide the definition of states and state machines.
+ State machine definitions must provide (the implementer is free to provide it or let
+ it be done by every concrete state machine. Different MSM front-ends took one or the
+ other approach):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">initial_state</code>: This typedef can be a single state or a
+ mpl container and provides the initial states defining one or several
+ orthogonal regions.</p></li><li class="listitem"><p><code class="code">transition_table</code>: This typedef is a MPL sequence of
+ rows.</p></li><li class="listitem"><p><code class="code">configuration</code>: this typedef is a MPL sequence of known
+ types triggering special behavior in the back-end, for example if a
+ concrete fsm requires a message queue or exception catching.</p></li></ul></div><p>States and state machines must both provide a (possibly empty) definition of:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">flag_list</code>: the flags being active when this state or
+ state machine become the current state of the fsm.</p></li><li class="listitem"><p><code class="code">deferred_events</code>: events being automatically deferred when
+ the state is the current state of the fsm.</p></li><li class="listitem"><p><code class="code">internal_transition_table</code>: the internal transitions of
+ this state.</p></li><li class="listitem"><p><code class="code">on_entry</code> and <code class="code">on_exit</code> methods.</p></li></ul></div></div><div class="sect2" title="Generated state ids"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4118"></a><span class="command"><strong><a name="internals-state-id"></a></strong></span> Generated state ids </h3></div></div></div><p>Normally, one does not need to know the ids generated for all the states of a
+ state machine, unless for debugging purposes, like the pstate function does in the
+ tutorials in order to display the name of the current state. This section will show
+ how to automatically display typeid-generated names, but these are not very readable
+ on all platforms, so it can help to know how the ids are generated. The ids are
+ generated using the transition table, from the “Start” column up to down, then from
+ the “Next” column, up to down, as shown in the next image: </p><p><span class="inlinemediaobject"><img src="../images/AnnexA.jpg"></span></p><p>Stopped will get id 0, Open id 1, ErrorMode id 6 and SleepMode (seen only in the
+ “Next” column) id 7. If you have some implicitly created states, like
+ transition-less initial states or states created using the explicit_creation
+ typedef, these will be added as a source at the end of the transition table. If you
+ have submachine states, a row will be added for them at the end of the table, after
+ the automatically or explicitly created states, which can change their id. The next
+ help you will need for debugging would be to call the current_state method of the
+ state_machine class, then the display_type helper to generate a readable name from
+ the id. If you do not want to go through the transition table to fill an array of
+ names, the library provides another helper, fill_state_names, which, given an array
+ of sufficient size (please see next section to know how many states are defined in
+ the state machine), will fill it with typeid-generated names. </p></div><div class="sect2" title="Metaprogramming tools"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4130"></a>Metaprogramming tools</h3></div></div></div><p>We can find for the transition table more uses than what we have seen so far.
+ Let's suppose you need to write a coverage tool. A state machine would be perfect
+ for such a job, if only it could provide some information about its structure. It is
+ especially relevant if you are working with Executable UML, which bases most of its
+ dynamic behaviour on state machines.As a matter of fact, thanks to the transition
+ table and Boost.MPL, it does.</p><p>What is needed for a coverage tool? You need to know how many states are defined
+ in the state machine, and how many events can be fired. This way you can log the
+ fired events and the states visited in the life of a concrete machine and be able to
+ perform some coverage analysis, like “fired 65% of all possible events and visited
+ 80% of the states defined in the state machine”. To achieve this, MSM provides a few
+ useful tools:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>generate_state_set<transition table>: returns a mpl::set of all the
+ states defined in the table.</p></li><li class="listitem"><p>generate_event_set<transition table>: returns a mpl::set of all the
+ events defined in the table.</p></li><li class="listitem"><p>using mpl::size<>::value you can get the number of elements in the
+ set.</p></li><li class="listitem"><p>display_type defines an operator() sending typeid(Type).name() to
+ cout.</p></li><li class="listitem"><p>fill_state_names fills an array of char const* with names of all
+ states (found by typeid)</p></li><li class="listitem"><p>using mpl::for_each on the result of generate_state_set and
+ generate_event_set passing display_type as argument will display all the
+ states of the state machine.</p></li><li class="listitem"><p>let's suppose you need to recursively find the states and events
+ defined in the composite states and thus also having a transition table.
+ Calling recursive_get_transition_table<Composite> will return you the
+ transition table of the composite state, recursively adding the
+ transition tables of all sub-state machines and sub-sub...-sub-state
+ machines. Then call generate_state_set or generate_event_set on the
+ result to get the full list of states and events. </p></li></ul></div><p> An <a class="link" href="examples/BoostCon09Full.cpp" target="_top">example</a> shows the tools
+ in action. </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s06.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s08.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Questions & Answers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Acknowledgements</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ar01s08.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s08.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,20 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Acknowledgements</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="ar01s07.html" title="Internals"><link rel="next" href="ar01s09.html" title="Reference"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Acknowledgements</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s07.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ar01s09.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Acknowledgements"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e4164"></a>Acknowledgements</h2></div></div></div><p>I am in debt to the following people
who helped MSM along the way.</p><div class="sect2" title="MSM v2"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4169"></a>MSM v2</h3></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Thanks to Dave Abrahams for managing the review</p></li><li class="listitem"><p>Thanks to Eric Niebler for his patience correcting my grammar
+ errors</p></li><li class="listitem"><p>Special thanks to Joel de Guzman who gave me very good ideas at the
+ BoostCon09. These ideas were the starting point of the redesign. Any
+ time again, Joel ☺</p></li><li class="listitem"><p>Thanks to Richard O’Hara for making Green Hills bring a patch in less
+ than 1 week, thus adding one more compiler to the supported list.</p></li><li class="listitem"><p>Big thanks to those who took the time to write a review: Franz Alt,
+ David Bergman, Michael Caisse, Barend Gehrels, Darryl Greene, Juraj
+ Ivancic, Erik Nelson, Kenny Riddile.</p></li><li class="listitem"><p>Thanks to Matt Calabrese and Juraj Ivancic for reporting bugs.</p></li></ul></div><p>
+ </p></div><div class="sect2" title="MSM v1"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4194"></a> MSM v1</h3></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>The original version of this framework is based on the brilliant work
+ of David Abrahams and Aleksey Gurtovoy who laid down the base and the
+ principles of the framework in their excellent book, “C++ template
+ Metaprogramming”. The implementation also makes heavy use of the
+ boost::mpl.</p></li><li class="listitem"><p>Thanks to Jeff Flinn for his idea of the user-defined base state and
+ his review which allowed MSM to be presented at the BoostCon09.</p></li><li class="listitem"><p>Thanks to my Msm v1beta testers, Christoph Woskowski and Franz Alt for
+ using the framework with little documentation and to my private
+ reviewer, Edouard Alligand</p></li></ul></div><p>
+ </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s07.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ar01s09.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Internals </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Reference</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ar01s09.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ar01s09.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,120 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Reference</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="index.html" title="Meta State Machine (MSM)"><link rel="prev" href="ar01s08.html" title="Acknowledgements"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Reference</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ar01s08.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> </td></tr></table><hr></div><div class="sect1" title="Reference"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e4210"></a>Reference</h2></div></div></div><p> todo </p><div class="sect2" title="Back-end"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4215"></a> Back-end </h3></div></div></div><p>to
do</p><div class="sect3" title="File: <boost/msm/back/state_machine.hpp>"><div class="titlepage"><div><div><h4 class="title"><a name="d0e4220"></a>File: <boost/msm/back/state_machine.hpp></h4></div></div></div><pre class="synopsis">
+ <code class="filename">boost/msm/back/state_machine.hpp</code>
+ <code class="classname">fff</code>
+ <code class="methodname">void start</code>
+ <code class="methodname">template <class Event> HandledEnum process_event</code>
+ <code class="methodname">const int* current_state const</code>
+ </pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Derived,class HistoryPolicy=NoHistory,class
+ CompilePolicy=favor_runtime_speed> state_machine</span></span> {<br><code class="methodsynopsis"> <span class="methodname">void start</span>(<span class="methodparam"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">template <class Event> HandledEnum process_event</span>(<span class="methodparam">Event const&</span>);</code><br><code class="methodsynopsis"> <span class="methodname">const int* current_state const</span>(<span class="methodparam"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">const BaseState* get_state_by_id const</span>(<span class="methodparam">int id</span>);</code><br><code class="methodsynopsis"> <span class="methodname">bool is_contained const</span>(<span class="methodparam"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">template <class State> State* get_state</span>(<span class="methodpar
am"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">template <class State> State& get_state</span>(<span class="methodparam"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">template <class Flag,class BinaryOp> bool
+ is_flag_active</span>(<span class="methodparam"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">template <class Flag> bool is_flag_active</span>(<span class="methodparam"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">void visit_current_states</span>(<span class="methodparam"></span>);</code><br><code class="methodsynopsis"> <span class="methodname">void visit_current_states</span>(<span class="methodparam">any-type param1, any-type param2,...</span>);</code><br><code class="methodsynopsis"> <span class="methodname">template <class Event> void defer_event</span>(<span class="methodparam">Event const&</span>);</code><br>}</pre></div></div><div class="sect2" title="eUML functions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4309"></a>eUML functions</h3></div></div></div><p>The following table lists the supported operators: </p><p>
+ </p><div class="table"><a name="d0e4316"></a><p class="title"><b>Table 1. Operators and state machine helpers</b></p><div class="table-contents"><table summary="Operators and state machine helpers" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>eUML function / operator</th><th>Description</th><th>Functor</th></tr></thead><tbody><tr><td>&&</td><td>Calls lazily Action1&& Action2</td><td>And_</td></tr><tr><td>||</td><td>Calls lazily Action1|| Action2</td><td>Or_</td></tr><tr><td>!</td><td>Calls lazily !Action1</td><td>Not_</td></tr><tr><td>!=</td><td>Calls lazily Action1 != Action2</td><td>NotEqualTo_</td></tr><tr><td>==</td><td>Calls lazily Action1 == Action2</td><td>EqualTo_</td></tr><tr><td>></td><td>Calls lazily Action1 > Action2</td><td>Greater_</td></tr><tr><td>>=</td><td>Calls lazily Action1 >= Action2</td><td>Greater_Equal_</td></tr><tr><td><</td><td>Calls lazily Action1 < Action2</td><td>Less_</td></tr><tr><td><=</td><td>Cal
ls lazily Action1 <= Action2</td><td>Less_Equal_</td></tr><tr><td>&</td><td>Calls lazily Action1 & Action2</td><td>Bitwise_And_</td></tr><tr><td>|</td><td>Calls lazily Action1 | Action2</td><td>Bitwise_Or_</td></tr><tr><td>^</td><td>Calls lazily Action1 ^ Action2</td><td>Bitwise_Xor_</td></tr><tr><td>--</td><td>Calls lazily --Action1 / Action1--</td><td>Pre_Dec_ / Post_Dec_</td></tr><tr><td>++</td><td>Calls lazily ++Action1 / Action1++</td><td>Pre_Inc_ / Post_Inc_</td></tr><tr><td>/</td><td>Calls lazily Action1 / Action2</td><td>Divides_</td></tr><tr><td>/=</td><td>Calls lazily Action1 /= Action2</td><td>Divides_Assign_</td></tr><tr><td>*</td><td>Calls lazily Action1 * Action2</td><td>Multiplies_</td></tr><tr><td>*=</td><td>Calls lazily Action1 *= Action2</td><td>Multiplies_Assign_</td></tr><tr><td>+ (binary)</td><td>Calls lazily Action1 + Action2</td><td>Plus_</td></tr><tr><td>+ (unary)</td><td>Calls lazily +Action1</td><td>Unary_Plus_</td></tr><tr><td>+=</td><td>Calls lazily Action1 += Action2</
td><td>Plus_Assign_</td></tr><tr><td>- (binary)</td><td>Calls lazily Action1 - Action2</td><td>Minus_</td></tr><tr><td>- (unary)</td><td>Calls lazily -Action1</td><td>Unary_Minus_</td></tr><tr><td>-=</td><td>Calls lazily Action1 -= Action2</td><td>Minus_Assign_</td></tr><tr><td>%</td><td>Calls lazily Action1 % Action2</td><td>Modulus_</td></tr><tr><td>%=</td><td>Calls lazily Action1 %= Action2</td><td>Modulus_Assign_</td></tr><tr><td>>></td><td>Calls lazily Action1 >> Action2</td><td>ShiftRight_</td></tr><tr><td>>>=</td><td>Calls lazily Action1 >>= Action2</td><td>ShiftRight_Assign_</td></tr><tr><td><<</td><td>Calls lazily Action1 << Action2</td><td>ShiftLeft_</td></tr><tr><td><<=</td><td>Calls lazily Action1 <<= Action2</td><td>ShiftLeft_Assign_</td></tr><tr><td>[] (works on vector, map, arrays)</td><td>Calls lazily Action1 [Action2]</td><td>Subscript_</td></tr><tr><td>if_then_else_(Condition,Action1,Action2)</td><td>Returns either the result of calling Action
1 or the result of
+ calling Action2</td><td>If_Else_</td></tr><tr><td>if_then_(Condition,Action)</td><td>Returns the result of calling Action if Condition</td><td>If_Then_</td></tr><tr><td>while_(Condition, Body)</td><td>While Condition(), calls Body(). Returns nothing</td><td>While_Do_</td></tr><tr><td>do_while_(Condition, Body)</td><td>Calls Body() while Condition(). Returns nothing</td><td>Do_While_</td></tr><tr><td>for_(Begin,Stop,EndLoop,Body)</td><td>Calls for(Begin;Stop;EndLoop){Body;}</td><td>For_Loop_</td></tr><tr><td>process_(Event [,fsm1] [,fsm2] [,fsm3] [,fsm4])</td><td>Processes Event on the current state machine (if no fsm
+ specified) or on up to 4 state machines returned by an
+ appropriate functor.</td><td>Process_</td></tr><tr><td>process2_(Event, Data [,fsm1] [,fsm2] [,fsm3])</td><td>Processes Event on the current state machine (if no fsm
+ specified) or on up to 2 state machines returned by an
+ appropriate functor. The event is copy-constructed from what
+ Data() returns.</td><td>Process2_</td></tr><tr><td>is_flag_(Flag [,fsm])</td><td>Calls is_flag_active() on the current state machine or the
+ one returned by calling fsm.</td><td>Get_Flag_</td></tr><tr><td>event_ [(attribute name)]</td><td>Returns the current event (as const reference)</td><td>GetEvent_</td></tr><tr><td>source_ [(attribute name)]</td><td>Returns the source state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</td><td>GetSource_</td></tr><tr><td>target_ [(attribute name)]</td><td>Returns the target state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</td><td>GetTarget_</td></tr><tr><td>state_ [(attribute name)]</td><td>Returns the source state of the currently active state (as
+ reference). Valid inside a state entry/exit action. If an
+ attribute name is provided, returns the attribute by
+ reference.</td><td>GetState_</td></tr><tr><td>fsm_ [(attribute name)]</td><td>Returns the current state machine (as reference). Valid
+ inside a state entry/exit action or a transition. If an
+ attribute name is provided, returns the attribute by
+ reference.</td><td>GetFsm_</td></tr><tr><td>substate_(state_name [,fsm])</td><td>Returns (as reference) the state state_name referenced in the
+ current state machine or the one given as argument.</td><td>SubState_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>TODO macro for functor def</p><p>To use these functions, you need to include: </p><p><code class="code">#include <msm/front/euml/euml.hpp></code></p></div><div class="sect2" title="Functional programming"><div class="titlepage"><div><div><h3 class="title"><a name="d0e4655"></a> Functional programming </h3></div></div></div><p>To use these functions, you need to include: </p><p><code class="code">#include <msm/front/euml/stl.hpp></code></p><p>or the specified header in the following tables.</p><p>The following table lists the supported STL algorithms: </p><p>
+ </p><div class="table"><a name="d0e4669"></a><p class="title"><b>Table 2. STL algorithms</b></p><div class="table-contents"><table summary="STL algorithms" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL algorithms in querying.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>find_(first, last, value)</td><td>Find_</td></tr><tr><td>find_if_(first, last, value)</td><td>FindIf_</td></tr><tr><td>lower_bound_(first, last, value [,opᵃ])</td><td>LowerBound_</td></tr><tr><td>upper_bound_(first, last, value [,opᵃ])</td><td>UpperBound_</td></tr><tr><td>equal_range_(first, last, value [,opᵃ])</td><td>EqualRange_</td></tr><tr><td>binary_search_(first, last, value [,opᵃ])</td><td>BinarySearch_</td></tr><tr><td>min_element_(first, last[,opᵃ])</td><td>MinElement_</td></tr><tr><td>max_element_(first, last[,opᵃ])</td><td>MaxElement_</td></tr><tr><td>adjacent_find_(first, last[,opᵃ])</td><td>AdjacentFind_</td></tr><tr><td>find_end_( first1, l
ast1, first2, last2 [,op ᵃ])</td><td>FindEnd_</td></tr><tr><td>find_first_of_( first1, last1, first2, last2 [,op ᵃ])</td><td>FindFirstOf_</td></tr><tr><td>equal_( first1, last1, first2 [,op ᵃ])</td><td>Equal_</td></tr><tr><td>search_( first1, last1, first2, last2 [,op ᵃ])</td><td>Search_</td></tr><tr><td>includes_( first1, last1, first2, last2 [,op ᵃ])</td><td>Includes_</td></tr><tr><td>lexicographical_compare_ ( first1, last1, first2, last2 [,op
+ ᵃ]) </td><td>LexicographicalCompare_</td></tr><tr><td>count_(first, last, value [,size])</td><td>Count_</td></tr><tr><td>count_if_(first, last, op ᵃ [,size])</td><td>CountIf_</td></tr><tr><td>distance_(first, last)</td><td>Distance_</td></tr><tr><td>mismatch _( first1, last1, first2 [,op ᵃ])</td><td>Mismatch_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e4780"></a><p class="title"><b>Table 3. STL algorithms</b></p><div class="table-contents"><table summary="STL algorithms" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL algorithms in transformation.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>copy_(first, last, result)</td><td>Copy_</td></tr><tr><td>copy_backward_(first, last, result)</td><td>CopyBackward_</td></tr><tr><td>reverse_(first, last)</td><td>Reverse_</td></tr><tr><td>reverse_copy_(first, last , result)</td><td>ReverseCopy_</td></tr><tr><td>remove_(first, last, value)</td><td>Remove_</td></tr><tr><td>remove_if_(first, last , opᵃ)</td><td>RemoveIf_</td></tr><tr><td>remove_copy_(first, last , output, value)</td><td>RemoveCopy_</td></tr><tr><td>remove_copy_if_(first, last, output, opᵃ)</td><td>RemoveCopyIf_</td></tr><tr><td>fill_(first, last, value)</td><td>Fill_</td></tr><tr><td>fill_n_(first, size, value)ᵇ</td><td>FillN_</td></tr><tr><td>generate_(fir
st, last, generatorᵃ)</td><td>Generate_</td></tr><tr><td>generate_(first, size, generatorᵃ)ᵇ</td><td>GenerateN_</td></tr><tr><td>unique_(first, last [,opᵃ])</td><td>Unique_</td></tr><tr><td>unique_copy_(first, last, output [,opᵃ])</td><td>UniqueCopy_</td></tr><tr><td>random_shuffle_(first, last [,opᵃ])</td><td>RandomShuffle_</td></tr><tr><td>rotate_copy_(first, middle, last, output)</td><td>RotateCopy_</td></tr><tr><td>partition_ (first, last [,opᵃ])</td><td>Partition_</td></tr><tr><td>stable_partition_ (first, last [,opᵃ])</td><td>StablePartition_</td></tr><tr><td>stable_sort_(first, last [,opᵃ])</td><td>StableSort_</td></tr><tr><td>sort_(first, last [,opᵃ])</td><td>Sort_</td></tr><tr><td>partial_sort_(first, middle, last [,opᵃ])</td><td>PartialSort_</td></tr><tr><td>partial_sort_copy_ (first, last, res_first, res_last [,opᵃ]) </td><td>PartialSortCopy_</td></tr><tr><td>nth_element_(first, nth, last [,opᵃ])</td><td>NthElement_</td>
</tr><tr><td>merge_( first1, last1, first2, last2, output [,op ᵃ])</td><td>Merge_</td></tr><tr><td>inplace_merge_(first, middle, last [,opᵃ])</td><td>InplaceMerge_</td></tr><tr><td>set_union_(first1, last1, first2, last2, output [,op
+ ᵃ])</td><td>SetUnion_</td></tr><tr><td>push_heap_(first, last [,op ᵃ])</td><td>PushHeap_</td></tr><tr><td>pop_heap_(first, last [,op ᵃ])</td><td>PopHeap_</td></tr><tr><td>make_heap_(first, last [,op ᵃ])</td><td>MakeHeap_</td></tr><tr><td>sort_heap_(first, last [,op ᵃ])</td><td>SortHeap_</td></tr><tr><td>next_permutation_(first, last [,op ᵃ])</td><td>NextPermutation_</td></tr><tr><td>prev_permutation_(first, last [,op ᵃ])</td><td>PrevPermutation_</td></tr><tr><td>inner_product_(first1, last1, first2, init [,op1ᵃ] [,op2ᵃ]) </td><td>InnerProduct_</td></tr><tr><td>partial_sum_(first, last, output [,opᵃ])</td><td>PartialSum_</td></tr><tr><td>adjacent_difference_(first, last, output [,opᵃ])</td><td>AdjacentDifference_</td></tr><tr><td>replace_(first, last, old_value, new_value)</td><td>Replace_</td></tr><tr><td>replace_if_(first, last, opᵃ, new_value)</td><td>ReplaceIf_</td></tr><tr><td>replace_copy_(first,
last, result, old_value,
+ new_value)</td><td>ReplaceCopy_</td></tr><tr><td>replace_copy_if_(first, last, result, opᵃ, new_value)</td><td>ReplaceCopyIf_</td></tr><tr><td>rotate_(first, middle, last)ᵇ</td><td>Rotate_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e4996"></a><p class="title"><b>Table 4. STL container methods</b></p><div class="table-contents"><table summary="STL container methods" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL container methods(common) in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>container::reference front_(container)</td><td>Front_</td></tr><tr><td>container::reference back_(container)</td><td>Back_</td></tr><tr><td>container::iterator begin_(container)</td><td>Begin_</td></tr><tr><td>container::iterator end_(container)</td><td>End_</td></tr><tr><td>container::reverse_iterator rbegin_(container)</td><td>RBegin_</td></tr><tr><td>container::reverse_iterator rend_(container)</td><td>REnd_</td></tr><tr><td>void push_back_(container, value)</td><td>Push_Back_</td></tr><tr><td>void pop_back_(container, value)</td><td>Pop_Back_</td></tr><tr><td>void push_front_(container, value)</td><td>Push_Front_</td></tr><tr><td>void pop_front_(container, value
)</td><td>Pop_Front_</td></tr><tr><td>void clear_(container)</td><td>Clear_</td></tr><tr><td>size_type capacity_(container)</td><td>Capacity_</td></tr><tr><td>size_type size_(container)</td><td>Size_</td></tr><tr><td>size_type max_size_(container)</td><td>Max_Size_</td></tr><tr><td>void reserve_(container, value)</td><td>Reserve _</td></tr><tr><td>void resize_(container, value)</td><td>Resize _</td></tr><tr><td>iterator insert_(container, pos, value)</td><td>Insert_</td></tr><tr><td>void insert_( container , pos, first, last)</td><td>Insert_</td></tr><tr><td>void insert_( container , pos, number, value)</td><td>Insert_</td></tr><tr><td>void swap_( container , other_container)</td><td>Swap_</td></tr><tr><td>void erase_( container , pos)</td><td>Erase_</td></tr><tr><td>void erase_( container , first, last) </td><td>Erase_</td></tr><tr><td>bool empty_( container)</td><td>Empty_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5127"></a><p class="title"><b>Table 5. STL list methods</b></p><div class="table-contents"><table summary="STL list methods" border="1"><colgroup><col><col></colgroup><thead><tr><th>std::list methods in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>void list_remove_(container, value)</td><td>ListRemove_</td></tr><tr><td>void list_remove_if_(container, opᵃ)</td><td>ListRemove_If_</td></tr><tr><td>void list_merge_(container, other_list)</td><td>ListMerge_</td></tr><tr><td>void list_merge_(container, other_list, opᵃ)</td><td>ListMerge_</td></tr><tr><td>void splice_(container, iterator, other_list)</td><td>Splice_</td></tr><tr><td>void splice_(container, iterator, other_list,
+ iterator)</td><td>Splice_</td></tr><tr><td>void splice_(container, iterator, other_list, first,
+ last)</td><td>Splice_</td></tr><tr><td>void list_reverse_(container)</td><td>ListReverse_</td></tr><tr><td>void list_unique_(container)</td><td>ListUnique_</td></tr><tr><td>void list_unique_(container, opᵃ)</td><td>ListUnique_</td></tr><tr><td>void list_sort_(container)</td><td>ListSort_</td></tr><tr><td>void list_sort_(container, opᵃ)</td><td>ListSort_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5203"></a><p class="title"><b>Table 6. STL associative container methods </b></p><div class="table-contents"><table summary="STL associative container methods " border="1"><colgroup><col><col></colgroup><thead><tr><th>Associative container methods in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>iterator insert_(container, pos, value)</td><td>Insert_</td></tr><tr><td>void insert_( container , first, last)</td><td>Insert_</td></tr><tr><td>pair<iterator, bool> insert_( container , value)</td><td>Insert_</td></tr><tr><td>void associative_erase_( container , pos)</td><td>Associative_Erase_</td></tr><tr><td>void associative_erase_( container , first, last)</td><td>Associative_Erase_</td></tr><tr><td>size_type associative_erase_( container , key)</td><td>Associative_Erase_</td></tr><tr><td>iterator associative_find_( container , key)</td><td>Associative_Find_</td></tr><tr><td>size_type associative_count_( container , key)</td><td>A
ssociativeCount_</td></tr><tr><td>iterator associative_lower_bound_( container , key)</td><td>Associative_Lower_Bound_</td></tr><tr><td>iterator associative_upper_bound_( container , key)</td><td>Associative_Upper_Bound_</td></tr><tr><td>pair<iterator, iterator> associative_equal_range_(
+ container , key)</td><td>Associative_Equal_Range_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5274"></a><p class="title"><b>Table 7. STL pair</b></p><div class="table-contents"><table summary="STL pair" border="1"><colgroup><col><col></colgroup><thead><tr><th>std::pair in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>first_type first_(pair<T1, T2>)</td><td>First_</td></tr><tr><td>second_type second_(pair<T1, T2>)</td><td>Second_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5300"></a><p class="title"><b>Table 8. STL string</b></p><div class="table-contents"><table summary="STL string" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>STL string method</th><th>std::string method in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>substr (size_type pos, size_type size)</td><td>string substr_(container, pos, length)</td><td>Substr_</td></tr><tr><td>int compare(string)</td><td>int string_compare_(container, another_string)</td><td>StringCompare_</td></tr><tr><td>int compare(char*)</td><td>int string_compare_(container, another_string)</td><td>StringCompare_</td></tr><tr><td>int compare(size_type pos, size_type size, string)</td><td>int string_compare_(container, pos, size,
+ another_string)</td><td>StringCompare_</td></tr><tr><td>int compare (size_type pos, size_type size, string, size_type
+ length)</td><td>int string_compare_(container, pos, size, another_string,
+ length)</td><td>StringCompare_</td></tr><tr><td>string& append(const string&)</td><td>string& append_(container, another_string)</td><td>Append_</td></tr><tr><td>string& append (charT*)</td><td>string& append_(container, another_string)</td><td>Append_</td></tr><tr><td>string& append (string , size_type pos, size_type
+ size)</td><td>string& append_(container, other_string, pos,
+ size)</td><td>Append_</td></tr><tr><td>string& append (charT*, size_type size)</td><td>string& append_(container, another_string,
+ length)</td><td>Append_</td></tr><tr><td>string& append (size_type size, charT)</td><td>string& append_(container, size, char)</td><td>Append_</td></tr><tr><td>string& append (iterator begin, iterator end)</td><td>string& append_(container, begin, end)</td><td>Append_</td></tr><tr><td>string& insert (size_type pos, charT*)</td><td>string& string_insert_(container, pos,
+ other_string)</td><td>StringInsert_</td></tr><tr><td>string& insert(size_type pos, charT*,size_type n)</td><td>string& string_insert_(container, pos, other_string,
+ n)</td><td>StringInsert_</td></tr><tr><td>string& insert(size_type pos,size_type n, charT
+ c)</td><td>string& string_insert_(container, pos, n, c)</td><td>StringInsert_</td></tr><tr><td>string& insert (size_type pos, const string&)</td><td>string& string_insert_(container, pos,
+ other_string)</td><td>StringInsert_</td></tr><tr><td>string& insert (size_type pos, const string&,
+ size_type pos1, size_type n)</td><td>string& string_insert_(container, pos, other_string,
+ pos1, n)</td><td>StringInsert_</td></tr><tr><td>string& erase(size_type pos=0, size_type n=npos)</td><td>string& string_erase_(container, pos, n)</td><td>StringErase_</td></tr><tr><td>string& assign(const string&)</td><td>string& string_assign_(container, another_string)</td><td>StringAssign_</td></tr><tr><td>string& assign(const charT*)</td><td>string& string_assign_(container, another_string)</td><td>StringAssign_</td></tr><tr><td>string& assign(const string&, size_type pos,
+ size_type n)</td><td>string& string_assign_(container, another_string, pos,
+ n)</td><td>StringAssign_</td></tr><tr><td>string& assign(const charT*, size_type n)</td><td>string& string_assign_(container, another_string,
+ n)</td><td>StringAssign_</td></tr><tr><td>string& assign(size_type n, charT c)</td><td>string& string_assign_(container, n, c)</td><td>StringAssign_</td></tr><tr><td>string& assign(iterator first, iterator last)</td><td>string& string_assign_(container, first, last)</td><td>StringAssign_</td></tr><tr><td>string& replace(size_type pos, size_type n, const
+ string&)</td><td>string& string_replace_(container, pos, n,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, const charT*,
+ size_type n1)</td><td>string& string_replace_(container, pos, n,
+ another_string, n1)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, const
+ charT*)</td><td>string& string_replace_(container, pos, n,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, size_type n1,
+ charT c)</td><td>string& string_replace_(container, pos, n, n1, c)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ string&)</td><td>string& string_replace_(container, first, last,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ charT*, size_type n)</td><td>string& string_replace_(container, first, last,
+ another_string, n)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ charT*)</td><td>string& string_replace_(container, first, last,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, size_type
+ n, charT c)</td><td>string& string_replace_(container, first, last, n,
+ c)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, iterator
+ f, iterator l)</td><td>string& string_replace_(container, first, last, f,
+ l)</td><td>StringReplace_</td></tr><tr><td>const charT* c_str()</td><td>const charT* c_str_(container)</td><td>CStr_</td></tr><tr><td>const charT* data()</td><td>const charT* string_data_(container)</td><td>StringData_</td></tr><tr><td>size_type copy(charT* buf, size_type n, size_type pos =
+ 0)</td><td>size_type string_copy_(container, buf, n, pos); size_type
+ string_copy_(container, buf, n) </td><td>StringCopy_</td></tr><tr><td>size_type find(charT* s, size_type pos, size_type n)</td><td>size_type string_find_(container, s, pos, n)</td><td>StringFind_</td></tr><tr><td>size_type find(charT* s, size_type pos=0)</td><td>size_type string_find_(container, s, pos); size_type
+ string_find_(container, s) </td><td>StringFind_</td></tr><tr><td>size_type find(const string& s, size_type pos=0)</td><td>size_type string_find_(container, s, pos) size_type
+ string_find_(container, s) </td><td>StringFind_</td></tr><tr><td>size_type find(charT c, size_type pos=0)</td><td>size_type string_find_(container, c, pos) size_type
+ string_find_(container, c) </td><td>StringFind_</td></tr><tr><td>size_type rfind(charT* s, size_type pos, size_type n)</td><td>size_type string_rfind_(container, s, pos, n)</td><td>StringRFind_</td></tr><tr><td>size_type rfind(charT* s, size_type pos=npos)</td><td>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </td><td>StringRFind_</td></tr><tr><td>size_type rfind(const string& s, size_type
+ pos=npos)</td><td>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </td><td>StringRFind_</td></tr><tr><td>size_type rfind(charT c, size_type pos=npos)</td><td>size_type string_rfind_(container, c, pos) size_type
+ string_rfind_(container, c) </td><td>StringRFind_</td></tr><tr><td>size_type find_first_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_first_of_(container, s, pos, n)</td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (charT* s, size_type pos=0)</td><td>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (const string& s, size_type
+ pos=0)</td><td>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (charT c, size_type pos=0)</td><td>size_type find_first_of_(container, c, pos) size_type
+ find_first_of_(container, c) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_not_of(charT* s, size_type pos,
+ size_type n)</td><td>size_type find_first_not_of_(container, s, pos, n)</td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (charT* s, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (const string& s, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (charT c, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, c, pos); size_type
+ find_first_not_of_(container, c) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_last_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_last_of_(container, s, pos, n)</td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (charT* s, size_type pos=npos)</td><td>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (const string& s, size_type
+ pos=npos)</td><td>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (charT c, size_type pos=npos)</td><td>size_type find_last_of_(container, c, pos); size_type
+ find_last_of_(container, c) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_not_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_last_not_of_(container, s, pos, n)</td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (charT* s, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (const string& s, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_not_of_(container, s) </td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (charT c, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, c, pos); size_type
+ find_last_not_of_(container, c) </td><td>StringFindLastNotOf_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p><span class="underline">Notes</span>: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>ᵃ: algorithms requiring a predicate need to make them eUML compatible
+ by wrapping them inside a Predicate_ functor. For example,
+ std::less<int> => Predicate_<std::less<int> >()</p></li><li class="listitem"><p>ᵇ: If using the SGI STL implementation, these functors use the SGI
+ return value</p></li></ul></div><p>
+ </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ar01s08.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Acknowledgements </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/boost.css
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/boost.css 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,66 @@
+/*=============================================================================
+ Copyright 2002 William E. Kempf
+ 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)
+=============================================================================*/
+
+H1
+{
+ FONT-SIZE: 200%;
+ COLOR: #00008B;
+}
+H2
+{
+ FONT-SIZE: 150%;
+}
+H3
+{
+ FONT-SIZE: 125%;
+}
+H4
+{
+ FONT-SIZE: 108%;
+}
+BODY
+{
+ FONT-SIZE: 100%;
+ BACKGROUND-COLOR: #ffffff;
+ COLOR: #000000;
+}
+PRE
+{
+ MARGIN-LEFT: 2em;
+ FONT-FAMILY: Courier,
+ monospace;
+}
+CODE
+{
+ FONT-FAMILY: Courier,
+ monospace;
+}
+CODE.as_pre
+{
+ white-space: pre;
+}
+.index
+{
+ TEXT-ALIGN: left;
+}
+.page-index
+{
+ TEXT-ALIGN: left;
+}
+.definition
+{
+ TEXT-ALIGN: left;
+}
+.footnote
+{
+ FONT-SIZE: 66%;
+ VERTICAL-ALIGN: super;
+ TEXT-DECORATION: none;
+}
+.function-semantics
+{
+ CLEAR: left;
+}
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/boostbook.css
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/boostbook.css 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,594 @@
+/*=============================================================================
+ Copyright (c) 2004 Joel de Guzman
+ http://spirit.sourceforge.net/
+
+ 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)
+=============================================================================*/
+
+/*=============================================================================
+ Body defaults
+=============================================================================*/
+
+ body
+ {
+ margin: 1em;
+ font-family: sans-serif;
+ }
+
+/*=============================================================================
+ Paragraphs
+=============================================================================*/
+
+ p
+ {
+ text-align: left;
+ font-size: 10pt;
+ line-height: 1.15;
+ }
+
+/*=============================================================================
+ Program listings
+=============================================================================*/
+
+ /* Code on paragraphs */
+ p tt.computeroutput
+ {
+ font-size: 9pt;
+ }
+
+ pre.synopsis
+ {
+ font-size: 90%;
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.5pc 0.5pc 0.5pc 0.5pc;
+ }
+
+ .programlisting,
+ .screen
+ {
+ font-size: 9pt;
+ display: block;
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.5pc 0.5pc 0.5pc 0.5pc;
+ }
+
+ /* Program listings in tables don't get borders */
+ td .programlisting,
+ td .screen
+ {
+ margin: 0pc 0pc 0pc 0pc;
+ padding: 0pc 0pc 0pc 0pc;
+ }
+
+/*=============================================================================
+ Headings
+=============================================================================*/
+
+ h1, h2, h3, h4, h5, h6
+ {
+ text-align: left;
+ margin: 1em 0em 0.5em 0em;
+ font-weight: bold;
+ }
+
+ h1 { font: 140% }
+ h2 { font: bold 140% }
+ h3 { font: bold 130% }
+ h4 { font: bold 120% }
+ h5 { font: italic 110% }
+ h6 { font: italic 100% }
+
+ /* Top page titles */
+ title,
+ h1.title,
+ h2.title
+ h3.title,
+ h4.title,
+ h5.title,
+ h6.title,
+ .refentrytitle
+ {
+ font-weight: bold;
+ margin-bottom: 1pc;
+ }
+
+ h1.title { font-size: 140% }
+ h2.title { font-size: 140% }
+ h3.title { font-size: 130% }
+ h4.title { font-size: 120% }
+ h5.title { font-size: 110% }
+ h6.title { font-size: 100% }
+
+ .section h1
+ {
+ margin: 0em 0em 0.5em 0em;
+ font-size: 140%;
+ }
+
+ .section h2 { font-size: 140% }
+ .section h3 { font-size: 130% }
+ .section h4 { font-size: 120% }
+ .section h5 { font-size: 110% }
+ .section h6 { font-size: 100% }
+
+ /* Code on titles */
+ h1 tt.computeroutput { font-size: 140% }
+ h2 tt.computeroutput { font-size: 140% }
+ h3 tt.computeroutput { font-size: 130% }
+ h4 tt.computeroutput { font-size: 120% }
+ h5 tt.computeroutput { font-size: 110% }
+ h6 tt.computeroutput { font-size: 100% }
+
+/*=============================================================================
+ Author
+=============================================================================*/
+
+ h3.author
+ {
+ font-size: 100%
+ }
+
+/*=============================================================================
+ Lists
+=============================================================================*/
+
+ li
+ {
+ font-size: 10pt;
+ line-height: 1.3;
+ }
+
+ /* Unordered lists */
+ ul
+ {
+ text-align: left;
+ }
+
+ /* Ordered lists */
+ ol
+ {
+ text-align: left;
+ }
+
+/*=============================================================================
+ Links
+=============================================================================*/
+
+ a
+ {
+ text-decoration: none; /* no underline */
+ }
+
+ a:hover
+ {
+ text-decoration: underline;
+ }
+
+/*=============================================================================
+ Spirit style navigation
+=============================================================================*/
+
+ .spirit-nav
+ {
+ text-align: right;
+ }
+
+ .spirit-nav a
+ {
+ color: white;
+ padding-left: 0.5em;
+ }
+
+ .spirit-nav img
+ {
+ border-width: 0px;
+ }
+
+/*=============================================================================
+ Copyright footer
+=============================================================================*/
+ .copyright-footer
+ {
+ text-align: right;
+ font-size: 70%;
+ }
+
+ .copyright-footer p
+ {
+ text-align: right;
+ font-size: 80%;
+ }
+
+/*=============================================================================
+ Table of contents
+=============================================================================*/
+
+ .toc
+ {
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.1pc 1pc 0.1pc 1pc;
+ font-size: 80%;
+ line-height: 1.15;
+ }
+
+ .boost-toc
+ {
+ float: right;
+ padding: 0.5pc;
+ }
+
+/*=============================================================================
+ Tables
+=============================================================================*/
+
+ .table-title,
+ div.table p.title
+ {
+ margin-left: 4%;
+ padding-right: 0.5em;
+ padding-left: 0.5em;
+ }
+
+ .informaltable table,
+ .table table
+ {
+ width: 92%;
+ margin-left: 4%;
+ margin-right: 4%;
+ }
+
+ div.informaltable table,
+ div.table table
+ {
+ padding: 4px;
+ }
+
+ /* Table Cells */
+ div.informaltable table tr td,
+ div.table table tr td
+ {
+ padding: 0.5em;
+ text-align: left;
+ font-size: 9pt;
+ }
+
+ div.informaltable table tr th,
+ div.table table tr th
+ {
+ padding: 0.5em 0.5em 0.5em 0.5em;
+ border: 1pt solid white;
+ font-size: 80%;
+ }
+
+ table.simplelist
+ {
+ width: auto !important;
+ margin: 0em !important;
+ padding: 0em !important;
+ border: none !important;
+ }
+ table.simplelist td
+ {
+ margin: 0em !important;
+ padding: 0em !important;
+ text-align: left !important;
+ font-size: 9pt !important;
+ border: none !important;
+ }
+
+/*=============================================================================
+ Blurbs
+=============================================================================*/
+
+ div.note,
+ div.tip,
+ div.important,
+ div.caution,
+ div.warning,
+ p.blurb
+ {
+ font-size: 9pt; /* A little bit smaller than the main text */
+ line-height: 1.2;
+ display: block;
+ margin: 1pc 4% 0pc 4%;
+ padding: 0.5pc 0.5pc 0.5pc 0.5pc;
+ }
+
+ p.blurb img
+ {
+ padding: 1pt;
+ }
+
+/*=============================================================================
+ Variable Lists
+=============================================================================*/
+
+ div.variablelist
+ {
+ margin: 1em 0;
+ }
+
+ /* Make the terms in definition lists bold */
+ div.variablelist dl dt,
+ span.term
+ {
+ font-weight: bold;
+ font-size: 10pt;
+ }
+
+ div.variablelist table tbody tr td
+ {
+ text-align: left;
+ vertical-align: top;
+ padding: 0em 2em 0em 0em;
+ font-size: 10pt;
+ margin: 0em 0em 0.5em 0em;
+ line-height: 1;
+ }
+
+ div.variablelist dl dt
+ {
+ margin-bottom: 0.2em;
+ }
+
+ div.variablelist dl dd
+ {
+ margin: 0em 0em 0.5em 2em;
+ font-size: 10pt;
+ }
+
+ div.variablelist table tbody tr td p,
+ div.variablelist dl dd p
+ {
+ margin: 0em 0em 0.5em 0em;
+ line-height: 1;
+ }
+
+/*=============================================================================
+ Misc
+=============================================================================*/
+
+ /* Title of books and articles in bibliographies */
+ span.title
+ {
+ font-style: italic;
+ }
+
+ span.underline
+ {
+ text-decoration: underline;
+ }
+
+ span.strikethrough
+ {
+ text-decoration: line-through;
+ }
+
+ /* Copyright, Legal Notice */
+ div div.legalnotice p
+ {
+ text-align: left
+ }
+
+/*=============================================================================
+ Colors
+=============================================================================*/
+
+ @media screen
+ {
+ body {
+ background-color: #FFFFFF;
+ color: #000000;
+ }
+
+ /* Links */
+ a
+ {
+ color: #005a9c;
+ }
+
+ a:visited
+ {
+ color: #9c5a9c;
+ }
+
+ h1 a, h2 a, h3 a, h4 a, h5 a, h6 a,
+ h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover,
+ h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited
+ {
+ text-decoration: none; /* no underline */
+ color: #000000;
+ }
+
+ /* Syntax Highlighting */
+ .keyword { color: #0000AA; }
+ .identifier { color: #000000; }
+ .special { color: #707070; }
+ .preprocessor { color: #402080; }
+ .char { color: teal; }
+ .comment { color: #800000; }
+ .string { color: teal; }
+ .number { color: teal; }
+ .white_bkd { background-color: #FFFFFF; }
+ .dk_grey_bkd { background-color: #999999; }
+
+ /* Copyright, Legal Notice */
+ .copyright
+ {
+ color: #666666;
+ font-size: small;
+ }
+
+ div div.legalnotice p
+ {
+ color: #666666;
+ }
+
+ /* Program listing */
+ pre.synopsis
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ .programlisting,
+ .screen
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ td .programlisting,
+ td .screen
+ {
+ border: 0px solid #DCDCDC;
+ }
+
+ /* Blurbs */
+ div.note,
+ div.tip,
+ div.important,
+ div.caution,
+ div.warning,
+ p.blurb
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ /* Table of contents */
+ .toc
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ /* Tables */
+ div.informaltable table tr td,
+ div.table table tr td
+ {
+ border: 1px solid #DCDCDC;
+ }
+
+ div.informaltable table tr th,
+ div.table table tr th
+ {
+ background-color: #F0F0F0;
+ border: 1px solid #DCDCDC;
+ }
+
+ .copyright-footer
+ {
+ color: #8F8F8F;
+ }
+
+ /* Misc */
+ span.highlight
+ {
+ color: #00A000;
+ }
+ }
+
+ @media print
+ {
+ /* Links */
+ a
+ {
+ color: black;
+ }
+
+ a:visited
+ {
+ color: black;
+ }
+
+ .spirit-nav
+ {
+ display: none;
+ }
+
+ /* Program listing */
+ pre.synopsis
+ {
+ border: 1px solid gray;
+ }
+
+ .programlisting,
+ .screen
+ {
+ border: 1px solid gray;
+ }
+
+ td .programlisting,
+ td .screen
+ {
+ border: 0px solid #DCDCDC;
+ }
+
+ /* Table of contents */
+ .toc
+ {
+ border: 1px solid gray;
+ }
+
+ .informaltable table,
+ .table table
+ {
+ border: 1px solid gray;
+ border-collapse: collapse;
+ }
+
+ /* Tables */
+ div.informaltable table tr td,
+ div.table table tr td
+ {
+ border: 1px solid gray;
+ }
+
+ div.informaltable table tr th,
+ div.table table tr th
+ {
+ border: 1px solid gray;
+ }
+
+ table.simplelist tr td
+ {
+ border: none !important;
+ }
+
+ /* Misc */
+ span.highlight
+ {
+ font-weight: bold;
+ }
+ }
+
+/*=============================================================================
+ Images
+=============================================================================*/
+
+ span.inlinemediaobject img
+ {
+ vertical-align: middle;
+ }
+
+/*==============================================================================
+ Super and Subscript: style so that line spacing isn't effected, see
+ http://www.adobe.com/cfusion/communityengine/index.cfm?event=showdetails&productId=1&postId=5341
+==============================================================================*/
+
+sup,
+sub {
+ height: 0;
+ line-height: 1;
+ vertical-align: baseline;
+ _vertical-align: bottom;
+ position: relative;
+
+}
+
+sup {
+ bottom: 1ex;
+}
+
+sub {
+ top: .5ex;
+}
+
Added: trunk/libs/msm/doc/HTML/ch01.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch01.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,23 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 1. Founding idea</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="pt01.html" title="Part I. User' guide"><link rel="next" href="ch02.html" title="Chapter 2. UML Short Guide"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 1. Founding idea</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="pt01.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="ch02.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 1. Fo
unding idea"><div class="titlepage"><div><div><h2 class="title"><a name="d0e99"></a>Chapter 1. Founding idea</h2></div></div></div><p>Let's start with an example taken from the C++ Template Metaprogramming
+ book:</p><p>
+ <code class="code">class player : public state_machine<player></code></p><p><code class="code">{ </code></p><p><code class="code">// The list of FSM states enum states { Empty, Open, Stopped, Playing,
+ Paused , initial_state = Empty }; </code></p><p><code class="code">// transition actions void start_playback(play const&) { std::cout
+ << "player::start_playback\n"; } </code></p><p><code class="code">void open_drawer(open_close const&) { std::cout <<
+ "player::open_drawer\n"; } </code></p><p><code class="code">void close_drawer(open_close const&) { std::cout <<
+ "player::close_drawer\n"; } </code></p><p><code class="code">void store_cd_info(cd_detected const&) { std::cout <<
+ "player::store_cd_info\n"; } </code></p><p><code class="code">void stop_playback(stop const&) { std::cout <<
+ "player::stop_playback\n"; } </code></p><p><code class="code">void pause_playback(pause const&) { std::cout <<
+ "player::pause_playback\n"; } </code></p><p><code class="code">void resume_playback(play const&) { std::cout <<
+ "player::resume_playback\n"; } </code></p><p><code class="code">void stop_and_open(open_close const&) { std::cout <<
+ "player::stop_and_open\n"; } </code></p><p><code class="code">friend class state_machine<player>; </code></p><p><code class="code">typedef player p; // makes transition table cleaner </code></p><p><code class="code">// Transition table </code></p><p><code class="code">struct transition_table : mpl::vector11< </code></p><p><code class="code">row < Stopped , play , Playing , &p::start_playback >, </code></p><p><code class="code">row < Stopped , open_close , Open , &p::open_drawer >, </code></p><p><code class="code">row < Open , open_close , Empty , &p::close_drawer >, </code></p><p><code class="code">row < Empty , open_close , Open , &p::open_drawer >, </code></p><p><code class="code">row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ </code></p><p><code class="code">row < Playing , stop , Stopped , &p::stop_playback >, </code></p><p><code class="code">row < Playing , pause , Paused , &p::pause_playback >, </code></p><p><code class="code">row < Playing , open_close , Open , &p::stop_and_open >,
+ </code></p><p><code class="code">row < Paused , play , Playing , &p::resume_playback >, </code></p><p><code class="code">row < Paused , stop , Stopped , &p::stop_playback >, </code></p><p><code class="code">row < Paused , open_close , Open , &p::stop_and_open > </code></p><p><code class="code">> {}; </code></p><p><code class="code">// Replaces the default no-transition response. </code></p><p><code class="code">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; } };</code>
+ </p><p><code class="code">void test() { player p; p.process_event(open_close());...}</code></p><p>This example is the foundation for the idea driving MSM: a descriptive and
+ expressive language based on a transition table with as little syntactic noise as
+ possible, all this while offering as many features from the UML 2.0 standard as
+ possible. MSM also offers several expressive state machine definition syntaxes with
+ different trade-offs.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="pt01.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part I. User' guide </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 2. UML Short Guide</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,9 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 2. UML Short Guide</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="ch01.html" title="Chapter 1. Founding idea"><link rel="next" href="ch02s02.html" title="Concepts"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 2. UML Short Guide</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch01.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="ch02s02.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 2. UML Short Guide
"><div class="titlepage"><div><div><h2 class="title"><a name="d0e198"></a>Chapter 2. UML Short Guide</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1">What are state machines?</span></dt><dt><span class="sect1">Concepts</span></dt><dd><dl><dt><span class="sect2">State machine, state, transition, event </span></dt><dt><span class="sect2">Submachines, orthogonal regions, pseudostates </span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e284">
+ History </a></span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e298">Completion transitions / anonymous
+ transitions</a></span></dt><dt><span class="sect2"> Internal transitions </span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e316">
+ Conflicting transitions </a></span></dt></dl></dd><dt><span class="sect1">State machine glossary</span></dt></dl></div><div class="sect1" title="What are state machines?"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e201"></a>What are state machines?</h2></div></div></div><p>State machines are the description of a thing's lifeline. They describe the
+ different stages of the lifeline, the events influencing it, and what it does
+ when a particular event is detected at a particular stage. They offer the
+ complete specification of the dynamic behavior of the thing.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch01.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch02s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 1. Founding idea </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Concepts</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch02s02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch02s02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,98 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Concepts</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch02.html" title="Chapter 2. UML Short Guide"><link rel="prev" href="ch02.html" title="Chapter 2. UML Short Guide"><link rel="next" href="ch02s03.html" title="State machine glossary"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Concepts</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02.html">Prev</a> </td><th width="60%" align="center">Chapter 2. UML Short Guide</th><td width="20%" align="right"> <a accesskey="n" href="ch02s03.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Concepts"><div class="titlepage"><div><div><h2 class="title" sty
le="clear: both"><a name="d0e206"></a>Concepts</h2></div></div></div><p>Thinking in terms of state machines is a bit surprising at first, so let us
+ have a quick glance at the concepts.</p><div class="sect2" title="State machine, state, transition, event"><div class="titlepage"><div><div><h3 class="title"><a name="d0e211"></a>State machine, state, transition, event </h3></div></div></div><p>A state machine is a concrete model describing the behavior of a system.
+ It is composed of a finite number of states and transitions.</p><p>
+ <span class="inlinemediaobject"><img src="../images/sm.gif"></span></p><p>A simple state has no sub states. It can have data, entry and exit
+ behaviors and deferred events. One can provide entry and exit behaviors
+ (also called actions) to states (or state machines), which are executed
+ whenever a state is entered or left, no matter how. A state can also have
+ internal transitions which cause no entry or exit behavior to be called. A
+ state can mark events as deferred. This means the event cannot be processed
+ if this state is active, but it must be retained. Next time a state not
+ deferring this event is active, the event will be processed, as if it had
+ just been fired. </p><p><span class="inlinemediaobject"><img src="../images/state.gif"></span></p><p>A transition is the switching between active states, triggered by an
+ event. Actions and guard conditions can be attached to the transition. The
+ action executes when the transition fires, the guard is a Boolean operation
+ executed first and which can prevent the transition from firing by returning
+ false.</p><p>
+ <span class="inlinemediaobject"><img src="../images/transition.jpg"></span></p><p>An initial state marks the first active state of a state machine. It has
+ no real existence and neither has the transition originating from it.</p><p>
+ <span class="inlinemediaobject"><img src="../images/init_state.gif"></span></p></div><div class="sect2" title="Submachines, orthogonal regions, pseudostates"><div class="titlepage"><div><div><h3 class="title"><a name="d0e241"></a>Submachines, orthogonal regions, pseudostates </h3></div></div></div><p>A composite state is a state containing a region or decomposed in two or
+ more regions. A composite state contains its own set of states and regions. </p><p>A submachine is a state machine inserted as a state in another state
+ machine. The same submachine can be inserted more than once. </p><p>Orthogonal regions are parts of a composite state or submachine, each
+ having its own set of mutually exclusive set of states and transitions. </p><p><span class="inlinemediaobject"><img src="../images/regions.gif" width="60%"></span></p><p>UML also defines a number of pseudo states, which are considered important
+ concepts to model, but not enough to make them first-class citizens. The
+ terminate pseudo state terminates the execution of a state machine (MSM
+ handles this slightly differently. The state machine is not destroyed but no
+ further event processing occurs.). </p><p><span class="inlinemediaobject"><img src="../images/terminate.gif"></span></p><p>An exit point pseudo state exits a composite state or a submachine and
+ forces termination of execution in all contained regions.</p><p><span class="inlinemediaobject"><img src="../images/exit.gif" width="60%"></span></p><p>An entry point pseudo state allows a kind of controlled entry inside a
+ composite. Precisely, it connects a transition outside the composite to a
+ transition inside the composite. An important point is that this mechanism
+ only allows a single region to be entered. In the above diagram, in region1,
+ the initial state would become active. </p><p><span class="inlinemediaobject"><img src="../images/entry_point.gif"></span></p><p>There are also two more ways to enter a submachine (apart the obvious and
+ more common case of a transition terminating on the submachine as shown in
+ the region case). An explicit entry means that an inside state is the target
+ of a transition. Unlike with direct entry, no tentative encapsulation is
+ made, and only one transition is executed. An explicit exit is a transition
+ from an inner state to a state outside the submachine (not supported by
+ MSM). I would not recommend using explicit entry or exit. </p><p><span class="inlinemediaobject"><img src="../images/explicit.gif"></span></p><p>The last entry possibility is using fork. A fork is an explicit entry into
+ one or more regions. Other regions are again activated using their initial
+ state. </p><p><span class="inlinemediaobject"><img src="../images/fork.gif" width="70%"></span></p></div><div class="sect2" title="History"><div class="titlepage"><div><div><h3 class="title"><a name="d0e284"></a>
+ <span class="command"><strong><a name="uml-history"></a></strong></span>History </h3></div></div></div><p>UML defines two kinds of history, shallow history and deep history.
+ Shallow history is a pseudo state representing the most recent substate of a
+ submachine. A submachine can have at most one shallow history. A transition
+ with a history pseudo state as target is equivalent to a transition with the
+ most recent substate as target. And very importantly, only one transition
+ may originate from the history. Deep history is a shallow history
+ recursively reactivating the substates of the most recent substate. It is
+ represented like the shallow history with a star (H* inside a
+ circle).</p><p>
+ <span class="inlinemediaobject"><img src="../images/history.gif" width="60%"></span></p><p>History is not a completely satisfying concept. First of all, there can be
+ just one history pseudo state and only one transition may originate from it.
+ So they do not mix well with orthogonal regions as only one region can be
+ “remembered”. Deep history is even worse and looks like a last-minute
+ addition. History has to be activated by a transition and only one
+ transition originates from it, so how to model the transition originating
+ from the deep history pseudo state and pointing to the most recent substate
+ of the substate? As a bonus, it is also inflexible and does not accept new
+ types of histories. Let's face it, history sounds great and is useful in
+ theory, but the UML version is not quite making the cut. And therefore, MSM
+ provides a different version of this useful concept. </p></div><div class="sect2" title="Completion transitions / anonymous transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e298"></a><span class="command"><strong><a name="uml-anonymous"></a></strong></span>Completion transitions / anonymous
+ transitions</h3></div></div></div><p>Completion events (or transitions), also called anonymous transitions, are
+ defined as transitions having no defined event triggering them. This means
+ that such transitions will immediately fire when a state being the source of
+ an anonymous transition becomes active, provided that a guard allows it.
+ They are useful in modeling algorithms as an activity diagram would normally
+ do. In the real-time world, they have the advantage of making it easier to
+ estimate how long a periodically executed action will last. For example,
+ consider the following diagram. </p><p><span class="inlinemediaobject"><img src="../images/completion.gif"></span></p><p>The designer now knows at any time that he will need a maximum of 4
+ transitions. Being able to estimate how long a transition takes, he can
+ estimate how much of a time frame he will need to require (real-time tasks
+ are often executed at regular intervals). If he can also estimate the
+ duration of actions, he can even use graph algorithms to better estimate his
+ timing requirements. </p></div><div class="sect2" title="Internal transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e310"></a><span class="command"><strong><a name="UML-internal-transition"></a></strong></span> Internal transitions </h3></div></div></div><p>Internal transitions are transitions executing in the scope of the active
+ state, being a simple state or a submachine. One can see them as a
+ self-transition of this state, without an entry or exit action
+ called.</p></div><div class="sect2" title="Conflicting transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e316"></a>
+ <span class="command"><strong><a name="transition-conflict"></a></strong></span>Conflicting transitions </h3></div></div></div><p>If, for a given event, several transitions are enabled, they are said to
+ be in conflict. There are two kinds of conflicts: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>For a given source state, several transitions are defined,
+ triggered by the same event. Normally, the guard condition in
+ each transition defines which one is fired.</p></li><li class="listitem"><p>The source state is a submachine or simple state and the
+ conflict is between a transition internal to this state and a
+ transition triggered by the same event and having as target
+ another state.</p></li></ul></div><p>The first one is simple; one only needs to define two or more
+ rows in the transition table, with the same source and trigger, with a
+ different guard condition. Beware, however, that the UML standard wants
+ these conditions to be not overlapping. If they do, the standard says
+ nothing except that this is incorrect, so the implementer is free to
+ implement it the way he sees fit. In the case of MSM, the transition
+ appearing last in the transition table gets selected first, if it returns
+ false (meaning disabled), the library tries with the previous one, and so
+ on.</p><p>
+ <span class="inlinemediaobject"><img src="../images/conflict1.gif"></span></p><p>In the second case, UML defines that the most inner transition gets
+ selected first, which makes sense, otherwise no exit point pseudo state
+ would be possible (the inner transition brings us to the exit point, from
+ where the containing state machine can take over). </p><p><span class="inlinemediaobject"><img src="../images/conflict2.gif" width="60%"></span></p><p>MSM handles both cases itself, so the designer needs only concentrate on
+ its state machine and the UML subtleties (not overlapping conditions), not
+ on implementing this behavior himself. </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch02s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 2. UML Short Guide </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> State machine glossary</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch02s03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch02s03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,37 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>State machine glossary</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch02.html" title="Chapter 2. UML Short Guide"><link rel="prev" href="ch02s02.html" title="Concepts"><link rel="next" href="ch03.html" title="Chapter 3. Tutorial"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">State machine glossary</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s02.html">Prev</a> </td><th width="60%" align="center">Chapter 2. UML Short Guide</th><td width="20%" align="right"> <a accesskey="n" href="ch03.html">Next</a></td></tr></table><hr></div><div class="sect1" title="State machine glossary"><div class="titlepage"><div><div>
<h2 class="title" style="clear: both"><a name="d0e344"></a>State machine glossary</h2></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>state machine: the life cycle of a thing. It is made of states,
+ regions, transitions and processes incoming events.</p></li><li class="listitem"><p>state: a stage in the life cycle of a state machine. A state (like
+ a submachine) can have an entry and exit behaviors.</p></li><li class="listitem"><p>event: an incident provoking (or not) a reaction of the state
+ machine</p></li><li class="listitem"><p>transition: a specification of how a state machine reacts to an
+ event. It specifies a source state, the event triggering the
+ transition, the target state (which will become the newly active
+ state if the transition is triggered), guard and actions.</p></li><li class="listitem"><p>action: an operation executed during the triggering of the
+ transition.</p></li><li class="listitem"><p>guard: a boolean operation being able to prevent the triggering of
+ a transition which would otherwise fire.</p></li><li class="listitem"><p>transition table: representation of a state machine. A state
+ machine diagram is a graphical, but incomplete representation of the
+ same model. A transition table, on the other hand, is a complete
+ representation.</p></li><li class="listitem"><p>initial state: The state in which the state machine starts. Having
+ several orthogonal regions means having as many initial
+ states.</p></li><li class="listitem"><p>submachine: A submachine is a state machine inserted as a state in
+ another state machine and can be found several times in a same state
+ machine.</p></li><li class="listitem"><p>orthogonal regions: (logical) parallel flow of execution of a
+ state machine. Every region of a state machine gets a chance to
+ process an incoming event.</p></li><li class="listitem"><p>terminate pseudo-state: when this state becomes active, it
+ terminates the execution of the whole state machine. MSM does not
+ destroy the state machine as required by the UML standard, however,
+ which lets you keep all the state machine's data.</p></li><li class="listitem"><p>entry/exit pseudo state: defined for submachines and are defined
+ as a connection between a transition outside of the submachine and a
+ transition inside the submachine. It is a way to enter or leave a
+ submachine through a predefined point.</p></li><li class="listitem"><p>fork: a fork allows explicit entry into several orthogonal regions
+ of a submachine.</p></li><li class="listitem"><p>history: a history is a way to remember the active state of a
+ submachine so that the submachine can proceed in its last active
+ state next time it becomes active.</p></li><li class="listitem"><p>completion events (also called completion/anonymous transitions):
+ when a transition has no named event triggering it, it automatically
+ fires when the source state is active, unless a guard forbids
+ it.</p></li><li class="listitem"><p>transition conflict: a conflict is present if for a given source
+ state and incoming event, several transitions are possible. UML
+ specifies that guard conditions have to solve the conflict.</p></li><li class="listitem"><p>internal transitions: transition from a state to itself without
+ having exit and entry actions being called.</p></li></ul></div><p>
+ </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch02.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Concepts </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 3. Tutorial</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,18 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 3. Tutorial</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="ch02s03.html" title="State machine glossary"><link rel="next" href="ch03s02.html" title="Basic front-end"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 3. Tutorial</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch02s03.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="ch03s02.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 3. Tutorial"><div class="titlep
age"><div><div><h2 class="title"><a name="d0e402"></a>Chapter 3. Tutorial</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1">Design</span></dt><dt><span class="sect1">Basic front-end</span></dt><dd><dl><dt><span class="sect2">A simple example</span></dt><dt><span class="sect2">Transition table</span></dt><dt><span class="sect2">Defining states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Defining a submachine</span></dt><dt><span class="sect2">Orthogonal regions, terminate state, event deferring</span></dt><dt><span class="sect2">History</span></dt><dt><span class="sect2"><a href
="ch03s02.html#d0e1396">Completion (anonymous) transitions</a></span></dt><dt><span class="sect2">Internal transitions</span></dt><dt><span class="sect2">more row types</span></dt><dt><span class="sect2">Explicit entry / entry and exit pseudo-state / fork</span></dt><dt><span class="sect2">Flags</span></dt><dt><span class="sect2">Event Hierarchy</span></dt><dt><span class="sect2">Customizing a state machine / Getting more speed</span></dt><dt><span class="sect2">Choosing the initial event</span></dt><dt><span class="sect2"> Containing state machine (deprecated)</span></dt></dl></dd><dt><span class="sect1">Functor front-end</span></dt><dd><dl><dt><span class="sect2"><a href="ch03s03.html#d0e1890"> Transition
table </a></span></dt><dt><span class="sect2">Defining states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Anonymous transitions</span></dt><dt><span class="sect2"><a href="ch03s03.html#d0e2462">Internal
+ transitions</a></span></dt></dl></dd><dt><span class="sect1">eUML (experimental)</span></dt><dd><dl><dt><span class="sect2">Transition table</span></dt><dt><span class="sect2">Defining events, actions and states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Defining a submachine</span></dt><dt><span class="sect2"><a href="ch03s04.html#d0e2958">
+ Attributes / Function call</a></span></dt><dt><span class="sect2">Orthogonal regions, flags, event deferring</span></dt><dt><span class="sect2"><a href="ch03s04.html#d0e3170">
+ Customizing a state machine / Getting
+ more speed</a></span></dt><dt><span class="sect2">Completion / Anonymous transitions</span></dt><dt><span class="sect2">Internal transitions</span></dt><dt><span class="sect2">Other state types</span></dt><dt><span class="sect2">Helper functions</span></dt><dt><span class="sect2">Phoenix-like STL support</span></dt></dl></dd><dt><span class="sect1">Back-end</span></dt><dd><dl><dt><span class="sect2">Creation </span></dt><dt><span class="sect2">Starting a state machine</span></dt><dt><span class="sect2">Event dispatching</span></dt><dt><span class="sect2">Active state(s)</span></dt><dt><span class="sect2"><a href="ch03s05.html#d0e3510">Base state ty
pe </a></span></dt><dt><span class="sect2">Visitor</span></dt><dt><span class="sect2">Flags</span></dt><dt><span class="sect2">Getting a state</span></dt><dt><span class="sect2"> State machine constructor with arguments </span></dt><dt><span class="sect2"><a href="ch03s05.html#d0e3620">Trading run-time speed for
+ better compile-time / multi-TU compilation</a></span></dt></dl></dd></dl></div><div class="sect1" title="Design"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e405"></a>Design</h2></div></div></div><p>MSM is divided between front–ends and back-ends. At the moment, there is just
+ one back-end. On the front-end side, you will find three of them which are as
+ many state machine description languages, with many more possible. For potential
+ language writers, this document contains a <a class="link" href="ch06s02.html#internals-front-back-interface">description of the interface
+ between front-end and back-end</a>.</p><p>The first front-end is an adaptation of the example provided in the <a class="link" href="http://boostpro.com/mplbook" target="_top">MPL book</a> with actions
+ defined as pointers to state or state machine methods. The second one is based
+ on functors. The third, eUML (embedded UML) is an experimental language based on
+ Boost.Proto and Boost.Typeof and hiding most of the metaprogramming to increase
+ readability. Both eUML and the functor front-end also offer a functional library
+ (a bit like Boost.Phoenix) for use as action language (UML defining
+ none).</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch02s03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">State machine glossary </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Basic front-end</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch03s02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch03s02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,750 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Basic front-end</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch03.html" title="Chapter 3. Tutorial"><link rel="prev" href="ch03.html" title="Chapter 3. Tutorial"><link rel="next" href="ch03s03.html" title="Functor front-end"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Basic front-end</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Tutorial</th><td width="20%" align="right"> <a accesskey="n" href="ch03s03.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Basic front-end"><div class="titlepage"><div><div><h2 class="title" style="c
lear: both"><a name="d0e418"></a><span class="command"><strong><a name="basic-front-end"></a></strong></span>Basic front-end</h2></div></div></div><p>This is the historical front-end, inherited from the MPL book. It provides a
+ transition table made of rows of different names and functionality. Actions and
+ guards are defined as methods and referenced through a pointer in the
+ transition. This front-end provides a simple interface making easy state
+ machines easy to define, but more complex state machines a bit harder.</p><div class="sect2" title="A simple example"><div class="titlepage"><div><div><h3 class="title"><a name="d0e424"></a>A simple example</h3></div></div></div><p>Let us have a look at a state machine diagram of the founding
+ example:</p><p><span class="inlinemediaobject"><img src="../images/SimpleTutorial.jpg" width="60%"></span></p><p>We are now going to build it with MSM's basic front-end. An <a class="link" href="examples/SimpleTutorial.cpp" target="_top">implementation</a> is also
+ provided.</p></div><div class="sect2" title="Transition table"><div class="titlepage"><div><div><h3 class="title"><a name="d0e438"></a>Transition table</h3></div></div></div><p>As previously stated, MSM is based on the transition table, so let us
+ define one:</p><p>struct transition_table : mpl::vector<</p><p>
+ </p><table frame="void" id="d0e447"><tbody><tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Stopped ,</td>
+ <td>play,</td>
+ <td>Playing,</td>
+ <td>&player_::start_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Stopped ,</td>
+ <td>open_close,</td>
+ <td>Open,</td>
+ <td>&player_::open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>_row <</td>
+ <td>Stopped ,</td>
+ <td>stop,</td>
+ <td>Stopped</td>
+ <td> </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Open ,</td>
+ <td>open_close ,</td>
+ <td>Empty ,</td>
+ <td>&player_::close_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Empty ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::store_cd_info ,</td>
+ <td>&player_::good_disk_format</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Playing ,</td>
+ <td>&player_::store_cd_info ,</td>
+ <td>&player_::auto_start</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::stop_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>pause ,</td>
+ <td>Paused ,</td>
+ <td>&player_::pause_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::stop_and_open</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>end_pause ,</td>
+ <td>Playing ,</td>
+ <td>&player_::resume_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::stop_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::stop_and_open</td>
+ <td> </td>
+ <td>></td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>You will notice that this is almost exactly our founding example. The only
+ change in the transition table is the different types of transitions (rows).
+ The founding example forces one to define an action method and offers no
+ guards. You have 4 basic row types:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">row</code> takes 5 arguments: start state, event, target
+ state, action and guard.</p></li><li class="listitem"><p><code class="code">a_row</code> (“a” for action) allows defining only the
+ action and omit the guard condition.</p></li><li class="listitem"><p><code class="code">g_row</code> (“g” for guard) allows omitting the action
+ behavior and defining only the guard.</p></li><li class="listitem"><p><code class="code">_row</code> allows omitting action and guard.</p></li></ul></div><p>The signature for an action methods is void method_name (event
+ const&), for example:</p><pre class="programlisting">void stop_playback(stop const&)</pre><p>Action methods return nothing and take the argument as const reference. Of
+ course nothing forbids you from using the same action for several
+ events:</p><pre class="programlisting">template <class Event> void stop_playback(Eventconst&)</pre><p>Guards have as only difference the return value, which is a
+ boolean:</p><pre class="programlisting">bool good_disk_format(cd_detected const& evt)</pre><p>The transition table is actually a MPL vector (or list), which brings the
+ limitation that the default maximum size of the table is 20. If you need
+ more transitions, overriding this default behavior is necessary, so you need
+ to add before any header:</p><pre class="programlisting">#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 //or whatever you need
+#define BOOST_MPL_LIMIT_MAP_SIZE 30 //or whatever you need </pre><p>The other limitation is that the MPL types are defined only up to 50
+ entries. For the moment, the only solution to achieve more is to add headers
+ to the MPL (luckily, this is not very complicated).</p></div><div class="sect2" title="Defining states with entry/exit actions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e974"></a>Defining states with entry/exit actions</h3></div></div></div><p>While states were enums in the MPL book, they now are classes, which
+ allows them to hold data, provide entry, exit behaviors and be reusable (as
+ they do not know anything about the containing state machine). To define a
+ state, inherit from the desired state type. You will mainly use simple
+ states:</p><p>struct Empty : public msm::front::state<> {};</p><p>They can optionally provide entry and exit behaviors:</p><pre class="programlisting">
+struct Empty : public msm::front::state<>
+{
+ template <class Event, class Fsm>
+ void on_entry(Event const&, Fsm& )
+ {std::cout <<"entering: Empty" << std::endl;}
+ template <class Event, class Fsm>
+ void on_exit(Event const&, Fsm& )
+ {std::cout <<"leaving: Empty" << std::endl;}
+};
+ </pre><p>Notice how the entry and exit behaviors are templatized on the event and
+ state machine. Being generic facilitates reuse. There are more state types
+ (terminate, interrupt, pseudo states, etc.) corresponding to the UML
+ standard state types. These will be described in details in the next
+ sections.</p></div><div class="sect2" title="Defining a simple state machine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e987"></a>Defining a simple state machine</h3></div></div></div><p>Declaring a state machine is straightforward and is done with a high
+ signal / noise ratio. In our player example, we declare the state machine
+ as:</p><pre class="programlisting">struct player_ : public msm::front::state_machine_def<player_>{
+ /* see below */}</pre><p>This declares a state machine using the basic front-end. We now declare
+ inside the state machine structure the initial state:</p><p>
+ </p><pre class="programlisting">typedef Empty initial_state;</pre><p>
+ </p><p>And that is about all of what is absolutely needed. In the example, the
+ states are declared inside the state machine for readability but this is not
+ a requirements, states can be declared wherever you like.</p><p>All what is left to do is to pick a back-end (which is quite simple as
+ there is only one at the moment):</p><p>
+ </p><pre class="programlisting">typedef msm::back::state_machine<player_> player;</pre><p>
+ </p><p>You now have a ready-to-use state machine with entry/exit actions, guards,
+ transition actions, a message queue so that processing an event can generate
+ another event. The state machine also adapted itself to your need and
+ removed almost all features we didn't use in this simple example. Note that
+ this is not per default the fastest possible state machine. See the section
+ "getting more speed" to know how to get the maximum speed. In a nutshell,
+ MSM cannot know about your usage of some features so you will have to
+ explicitly tell it.</p><p>State objects are built automatically with the state machine. They will
+ exist until state machine destruction. MSM is using Boost.Fusion behind the
+ hood. This unfortunately means that if you define more than 10 states, you
+ will need to extend the default:</p><p>
+ </p><pre class="programlisting">#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need
+ </pre><p>
+ </p><p>When an unexpected event is fired, the <code class="code">no_transition(event, state
+ machine, state id)</code> method of the state machine is called . By
+ default, this method simply asserts when called. It is possible to overwrite
+ the <code class="code">no_transition</code> method to define a different handling:</p><p>
+ </p><pre class="programlisting">template <class Fsm,class Event>
+void no_transition(Event const& e, Fsm& ,int state){...}</pre><p>
+ </p><p><span class="underline">Note</span>: you might have noticed that
+ the tutorial calls <code class="code">start()</code> on the state machine just after
+ creation. The start method will initiate the state machine, meaning it will
+ activate the initial state, which means in turn that the initial state's
+ entry behavior will be called. The reason why we need this will be explained
+ in the <a class="link" href="ch03s05.html#backend-start">back-end part</a>. After a call
+ to start, the state machine is ready to process events.</p></div><div class="sect2" title="Defining a submachine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1042"></a>Defining a submachine</h3></div></div></div><p>We now want to extend our last state machine by making the Playing state a
+ state machine itself (a submachine).</p><p><span class="inlinemediaobject"><img src="../images/CompositeTutorial.jpg" width="60%"></span></p><p>Again, an <a class="link" href="examples/CompositeTutorial.cpp" target="_top">example</a>
+ is also provided.</p><p>A submachine really is a state machine itself, so we declare Playing as
+ such, choosing a front-end and a back-end:</p><p>
+ </p><pre class="programlisting">struct Playing_ : public msm::front::state_machine_def<Playing_>{...}
+typedef msm::back::state_machine<Playing_> Playing;</pre><p>
+ </p><p>Like for any state machine, one also needs a transition table and an
+ initial state:</p><p> struct transition_table : mpl::vector<</p><table id="d0e1067"><tbody><tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>------------------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song1 ,</td>
+ <td>NextSong,</td>
+ <td>Song2,</td>
+ <td>&Playing_::start_next_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song2 ,</td>
+ <td>PreviousSong,</td>
+ <td>Song1,</td>
+ <td>&Playing_::start_prev_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song2 ,</td>
+ <td>NextSong,</td>
+ <td>Song3,</td>
+ <td>&Playing_::start_next_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>a_row <</td>
+ <td>Song3 ,</td>
+ <td>PreviousSong ,</td>
+ <td>Song2 ,</td>
+ <td>&Playing_::start_prev_song </td>
+ <td> </td>
+ <td>></td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>------------------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><pre class="programlisting">typedef Song1 initial_state; </pre><p>
+ </p><p>This is about all you need to do. MSM will now automatically recognize
+ Playing as a submachine and all events handled by Playing (NextSong and
+ PreviousSong) will now be automatically forwarded to Playing whenever this
+ state is active. All other state machine features described later are also
+ available. You can even decide to use a state machine sometimes as
+ submachine or sometimes as an independent state machine.</p></div><div class="sect2" title="Orthogonal regions, terminate state, event deferring"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1260"></a>Orthogonal regions, terminate state, event deferring</h3></div></div></div><p>It is a very common problem in many state machines to have to handle
+ errors. It usually involves defining a transition from all the states to a
+ special error state. Translation: not fun. It is also not practical to find
+ from which state the error originated. The following diagram shows an
+ example of what clearly becomes not very readable:</p><p><span class="inlinemediaobject"><img src="../images/error_no_regions.jpg" width="60%"></span></p><p>This is neither very readable nor beautiful. And we do not even have any
+ action on the transitions yet to make it even less readable.</p><p>Luckily, UML provides a helpful concept, orthogonal regions. See them as
+ lightweight state machines running at the same time inside a common state
+ machine and having the capability to influence one another. The effect is
+ that you have several active states at any time. We can therefore keep our
+ state machine from the previous example and just define a new region made of
+ two states, AllOk and ErrorMode. AllOk is most of the time active. But the
+ error_found error event makes the second region move to the new active state
+ ErrorMode. This event does not interest the main region so it will simply be
+ ignored. "<code class="code">no_transition</code>" will be called only if no region at
+ all handles the event. Also, as UML mandates, every region gets a chance of
+ handling the event, in the order as declared by the
+ <code class="code">initial_state</code> type.</p><p>Adding an orthogonal region is easy, one only needs to declare more states
+ in the <code class="code">initial_state</code> typedef. So, adding a new region with
+ AllOk as the region's initial state is:</p><p>
+ </p><pre class="programlisting">typedef mpl::vector<Empty,AllOk> initial_state;</pre><p>
+ </p><p><span class="inlinemediaobject"><img src="../images/Orthogonal-deferred.jpg" width="60%"></span></p><p>Furthermore, when you detect an error, you usually do not want events to
+ be further processed. To achieve this, we use another UML feature, terminate
+ states. When any region moves to a terminate state, the state machine
+ “terminates” (the state machine and all its states stay alive) and all
+ events are ignored. This is of course not mandatory, one can use orthogonal
+ regions without terminate states. MSM also provides a small extension to
+ UML, interrupt states. If you declare ErrorMode as interrupt state instead
+ of terminate state, the state machine will not handle any event other than
+ the one which ends the interrupt. So it's like a terminate state, with the
+ difference that you are allowed to resume the state machine when a condition
+ (like handling of the original error) is met. </p><p><span class="command"><strong><a name="basic-defer"></a></strong></span>Last but not least, this example also shows
+ here the handling of event deferring. Let's say someone puts a disc and
+ immediately presses play. The event cannot be handled, yet you'd want it to
+ be handled at a later point and not force the user to press play again. The
+ solution is to define it as deferred in the Empty and Open states and get it
+ handled in the first state where the event is not to be deferred. It can
+ then be handled or rejected. In this example, when Stopped becomes active,
+ the event will be handled because only Empty and Open defer the
+ event.</p><p>UML defines event deferring as a state property. To accommodate this, MSM
+ lets you specify this in states by providing a <code class="code">deferred_events</code>
+ type:</p><pre class="programlisting">struct Empty : public msm::front::state<>
+{
+ // if the play event is fired while in this state, defer it until a state
+ // handles or rejects it
+ typedef mpl::vector<play> deferred_events;
+...
+}; </pre><p>Please have a look at the <a class="link" href="examples/Orthogonal-deferred.cpp" target="_top">complete
+ example</a>.</p><p>While this is wanted by UML and is simple, it is not always practical
+ because one could wish to defer only in certain conditions. One could also
+ want to make this be part of a transition action with the added bonus of a
+ guard for more sophisticated behaviors. It would also be conform to the MSM
+ philosophy to get as much as possible in the transition table, where you
+ have the whole state machine structure. This is also possible but not
+ practical with this front-end so we will need to pick a different row from
+ the functor front-end. For a complete description of the <code class="code">Row</code>
+ type, please have a look at the <span class="command"><strong><a class="command" href="ch03s03.html#functor-front-end">functor front-end.</a></strong></span></p><p>First, as there is no state where MSM can automatically find out the usage
+ of this feature, we need to require deferred events capability explicitly,
+ by adding a type in the state machine definition:</p><pre class="programlisting">struct player_ : public msm::front::state_machine_def<player_>
+{
+ typedef int activate_deferred_events;
+...
+}; </pre><p>We can now defer an event in any transition of the transition table by
+ using as action the predefined <code class="code">msm::front::Defer</code> functor, for
+ example:</p><p>
+ </p><pre class="programlisting">Row < Empty , play , none , Defer , none ></pre><p>
+ </p><p>This is an internal transition row(see <span class="command"><strong><a class="command" href="ch03s02.html#internal-transitions">internal transitions</a></strong></span>) but
+ you can ignore this for the moment. It just means that we are not leaving
+ the Empty state. What matters is that we use Defer as action. This is
+ roughly equivalent to the previous syntax but has the advantage of giving
+ you all the information in the transition table with the added power of
+ transition behavior.</p><p>The second difference is that as we now have a transition defined, this
+ transition can play in the resolution of <span class="command"><strong><a class="command" href="ch02s02.html#transition-conflict">transition conflicts</a></strong></span>. For
+ example, we could model an "if (condition2) move to Playing else if
+ (condition1) defer play event":</p><p>
+ </p><pre class="programlisting">Row < Empty , play , none , Defer , condition1 >,
+g_row < Empty , play , Playing , &player_::condition2 ></pre><p>
+ </p><p>Please have a look at <a class="link" href="examples/Orthogonal-deferred2.cpp" target="_top">this possible implementation</a>.</p></div><div class="sect2" title="History"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1351"></a>History</h3></div></div></div><p>UML defines two types of history, Shallow History and Deep History. In the
+ previous examples, if the player was playing the second song and the user
+ pressed pause, leaving Playing, at the next press on the play button, the
+ Playing state would become active and the first song would play again. Soon
+ would the first client complaints follow. They'd of course demand, that if
+ the player was paused, then it should remember which song was playing. But
+ it the player was stopped, then it should restart from the first song. How
+ can it be done? Of course, you could add a bit of programming logic and
+ generate extra events to make the second song start if coming from Pause.
+ Something like: </p><p>
+ </p><pre class="programlisting">if (Event == end_pause)
+{
+ for (int i=0;i< song number;++i) {player.process_event(NextSong()); }
+} </pre><p>
+ </p><p>Not much to like in this example, isn't it? To solve this problem, you
+ define what is called a shallow or a deep history. A shallow history
+ reactivates the last active substate of a submachine when this submachine
+ becomes active again. The deep history does the same recursively, so if this
+ last active substate of the submachine was itself a submachine, its last
+ active substate would become active and this will continue recursively until
+ an active state is a normal state. For example, let us have a look at the
+ following UML diagram: </p><p><span class="inlinemediaobject"><img src="../images/HistoryTutorial.jpg" width="60%"></span></p><p>Notice that the main difference compared to previous diagrams is that the
+ initial state is gone and replaced by a History symbol (the H inside a
+ circle).</p><p>As explained in the <span class="command"><strong><a class="command" href="ch02s02.html#uml-history">small UML
+ tutorial</a></strong></span>, History is a good concept with a not completely
+ satisfying specification. MSM kept the concept but not the specification and
+ goes another way by making this a policy and you can add your own history
+ types (the <a class="link" href="re02.html#history-interface">reference</a> explains
+ what needs to be done). Furthermore, History is a backend policy. This
+ allows you to reuse the same state machine definition with different history
+ policies in different contexts.</p><p>Concretely, your frontend stays unchanged:</p><p>
+ </p><pre class="programlisting">struct Playing_ : public msm::front::state_machine_def<Playing_></pre><p>
+ </p><p>You then add the policy to the backend as second parameter:</p><p>
+ </p><pre class="programlisting">typedef msm::back::state_machine<Playing_,
+ msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;</pre><p>
+ </p><p>This states that a shallow history must be activated if the Playing state
+ machine gets activated by the end_pause event and only this one (or any
+ other event added to the mpl::vector). If the state machine was in the
+ Stopped state and the event play was generated, the history would not be
+ activated and the normal initial state would become active. By default,
+ history is disabled. For your convenience the library provides in addition
+ to ShallowHistory a non-UML standard AlwaysHistory policy (likely to be your
+ main choice) which always activates history, whatever event triggers the
+ submachine activation. Deep history is not available as a policy (but could
+ be added). The reason is that it would conflict with policies which
+ submachines could define. Of course, if for example, Song1 were a state
+ machine itself, it could use the ShallowHistory policy itself thus creating
+ Deep History for itself. An <a class="link" href="examples/History.cpp" target="_top">example</a> is also provided.</p></div><div class="sect2" title="Completion (anonymous) transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1396"></a>Completion (anonymous) transitions</h3></div></div></div><p><span class="command"><strong><a name="anonymous-transitions"></a></strong></span>The following diagram shows an
+ example making use of this feature:</p><p><span class="inlinemediaobject"><img src="../images/Anonymous.jpg" width="60%"></span></p><p>Anonymous transitions are transitions without a named event. This means
+ that the transition automatically fires when the predecessor state is
+ entered (to be exact, after the entry action). Otherwise it is a normal
+ transition with actions and guards. Why would you need something like that?
+ A possible case would be if a part of your state machine implements some
+ algorithm, where states are steps of the algorithm implementation. Then,
+ using several anonymous transitions with different guard conditions, you are
+ actually implementing some if/else statement. Another possible use would be
+ a real-time system called at regular intervals and always doing the same
+ thing, meaning implementing the same algorithm. The advantage is that once
+ you know how long a transition takes to execute on the system, by
+ calculating the longest path (the number of transitions from start to end),
+ you can pretty much know how long your algorithm will take in the worst
+ case, which in turns tells you how much of a time frame you are to request
+ from a scheduler. </p><p>If you are using Executable UML (a good book describing it is "Executable
+ UML, a foundation for Model-Driven Architecture"), you will notice that it
+ is common for a state machine to generate an event to itself only to force
+ leaving a state. Anonymous transitions free you from this constraint.</p><p>If you do not use this feature in a concrete state machine, MSM will
+ deactivate it and you will not pay for it. If you use it, there is however a
+ small performance penalty as MSM will try to fire a compound event (the
+ other UML name for anonymous transitions) after every taken transition. This
+ will therefore double the event processing cost, which is not as bad as it
+ sounds as MSM’s execution speed is very high anyway.</p><p>To define such a transition, use “none” as event in the transition table,
+ for example:</p><p>
+ </p><pre class="programlisting">row < State3 , none , State4 , &p::State3ToState4 , &p::always_true ></pre><p>
+ </p><p><a class="link" href="examples/AnonymousTutorial.cpp" target="_top">An implementation</a>
+ of the state machine diagram is also provided.</p></div><div class="sect2" title="Internal transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1423"></a><span class="command"><strong><a name="internal-transitions"></a></strong></span>Internal transitions</h3></div></div></div><p>Internal transitions are transitions executing in the scope of the active
+ state, a simple state or a submachine. One can see them as a self-transition
+ of this state, without an entry or exit action called. This is useful when
+ all you want is to execute some code for a given event in a given
+ state.</p><p>Internal transitions are specified as having a higher priority than normal
+ transitions. While it makes sense for a submachine with exit points, it is
+ surprising for a simple state. MSM lets you define the transition priority
+ by setting the transition’s position inside the transition table (see
+ <span class="command"><strong><a class="command" href="ch06.html#run-to-completion">internals</a></strong></span> ). The
+ difference between "normal" and internal transitions is that internal
+ transitions have no target state, therefore we need new row types. We had
+ a_row, g_row, _row and row, we now add a_irow, g_irow, _irow and irow which
+ are like normal transitions but define no target state. For, example an
+ internal transition with a guard condition could be:</p><p>
+ </p><pre class="programlisting">g_irow < Empty /*state*/,cd_detected/*event*/,&p::internal_guard/* guard */></pre><p>
+ </p><p>These new row types can be placed anywhere in the transition table so that
+ you can still have your state machine structure grouped together. The only
+ difference of behavior with the UML standard is the missing notion of higher
+ priority for internal transitions. Please have a look at <a class="link" href="examples/SimpleTutorialInternal.cpp" target="_top">the
+ example</a>.</p><p>It is also possible to do it the UML-conform way by declaring a transition
+ table called <code class="code">internal transition_table</code> inside the state itself
+ and using internal row types. For example:</p><pre class="programlisting">struct Empty : public msm::front::state<>
+{
+ struct internal_transition_table : mpl::vector<
+ a_internal < cd_detected , Empty, &Empty::internal_action >
+ > {};
+};</pre><p>This declares an internal transition table called
+ internal_transition_table and reacting on the event cd_detected by calling
+ internal_action on Empty. Let us note a few points:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>internal tables are NOT called transition_table but
+ internal_transition_table</p></li><li class="listitem"><p>they use different but similar row types: a_internal,
+ g_internal, _internal and internal.</p></li><li class="listitem"><p>These types take as first template argument the triggering
+ event and then the action and guard method. Note that the only
+ real difference to classical rows is the extra argument before
+ the function pointer. This is the type on which the function
+ will be called.</p></li><li class="listitem"><p>This also allows you, if you wish, to use actions and guards
+ from another state of the state machine or in the state machine
+ itself.</p></li><li class="listitem"><p>submachines can have an internal transition table and a
+ classical transition table.</p></li></ul></div><p>The <a class="link" href="examples/TestInternal.cpp" target="_top">following example</a>
+ makes use of an a_internal. It also uses functor-based internal transitions
+ which will be explained in <span class="command"><strong><a class="command" href="ch03s03.html#functor-internal-transitions">the functor
+ front-end</a></strong></span>, please ignore them for the moment. Also note that
+ the state-defined internal transitions, having the highest priority (as
+ mandated by the UML standard), are tried before those defined inside the
+ state machine transition table.</p><p>Which method should you use? It depends on what you need:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>the first version (using irow) is simpler and likely to
+ compile faster. It also lets you choose the priority of your
+ internal transition.</p></li><li class="listitem"><p>the second version is more logical from a UML perspective and
+ lets you make states more useful and reusable. It also allows
+ you to call actions and guards on any state of the state
+ machine.</p></li></ul></div><p>
+ <span class="command"><strong><a name="internal-transitions-note"></a></strong></span><span class="underline"><span class="bold"><strong>Note</strong></span></span>: There is an added
+ possibility coming from this feature. The
+ <code class="code">internal_transition_table</code> transitions being added directly
+ inside the main state machine's transition table, it is possible, if it is
+ more to your state, to distribute your state machine definition a bit like
+ Boost.Statechart, leaving to the state machine itself the only task of
+ declaring the states it wants to use using the
+ <code class="code">explicit_creation</code> type definition. While this is not the
+ author's favorite way, it is still possible. A simplified example using only
+ two states will show this possibility:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><a class="link" href="examples/distributed_table/DistributedTable.cpp" target="_top">state machine definition</a></p></li><li class="listitem"><p>Empty <a class="link" href="examples/distributed_table/Empty.hpp" target="_top">header</a> and <a class="link" href="examples/distributed_table/Empty.cpp" target="_top">cpp</a></p></li><li class="listitem"><p>Open <a class="link" href="examples/distributed_table/Open.hpp" target="_top">header</a> and <a class="link" href="examples/distributed_table/Open.cpp" target="_top">cpp</a></p></li><li class="listitem"><p><a class="link" href="examples/distributed_table/Events.hpp" target="_top">events definition</a></p></li></ul></div><p>There is an added bonus offered for submachines, which can have both the
+ standard transition_table and an internal_transition_table (which has a
+ higher priority). This makes it easier if you decide to make a full
+ submachine from a state. It is also slightly faster than the standard
+ alternative, adding orthogonal regions, because event dispatching will, if
+ accepted by the internal table, not continue to the subregions. This gives
+ you a O(1) dispatch instead of O(number of regions). While the example is
+ with eUML, the same is also possible with any front-end.</p></div><div class="sect2" title="more row types"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1525"></a><span class="command"><strong><a name="basic-row2"></a></strong></span>more row types</h3></div></div></div><p>It is also possible to write transitions using actions and guards not just
+ from the state machine but also from its contained states. In this case, one
+ must specify not just a method pointer but also the object on which to call
+ it. This transition row is called, not very originally, <code class="code">row2</code>.
+ They come, like normal transitions in four flavors: <code class="code">a_row2, g_row2,
+ _row2 and row2</code>. For example, a transition calling an action from
+ the state Empty could be:</p><p>
+ </p><pre class="programlisting">a_row2<Stopped,open_close,Open,Empty
+ /*action source*/,&Empty::open_drawer/*action*/></pre><p>
+ </p><p>The same capabilities are also available for internal transitions so that
+ we have: <code class="code">a_irow2, g_irow2, _irow2 and row2</code>. For transitions
+ defined as part of the <code class="code">internal_transition_table</code>, you can use
+ the <span class="command"><strong><a class="command" href="ch03s02.html#internal-transitions">a_internal, g_internal,
+ _internal, internal</a></strong></span> row types from the previous
+ sections.</p><p>These row types allow us to distribute the state machine code among
+ states, making them reusable and more useful. Using transition tables inside
+ states also contributes to this possibility. An <a class="link" href="examples/SimpleTutorial2.cpp" target="_top">example</a> of these new
+ rows is also provided.</p></div><div class="sect2" title="Explicit entry / entry and exit pseudo-state / fork"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1558"></a>Explicit entry / entry and exit pseudo-state / fork</h3></div></div></div><p>MSM (almost) fully supports these features, described in the <span class="command"><strong><a class="command" href="ch02s02.html#uml-history">small UML tutorial</a></strong></span>. Almost because
+ there are currently two limitations: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>it is only possible to explicitly enter a sub- state of the
+ target but not a sub-sub state.</p></li><li class="listitem"><p>it is not possible to explicitly exit. Exit points must be
+ used.</p></li></ul></div><p>Let us see a concrete example:</p><p><span class="inlinemediaobject"><img src="../images/entry%20tutorial.jpg" width="60%"></span></p><p>We find in this diagram:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>A “normal” activation of SubFsm2, triggered by event1. In each
+ region, the initial state is activated, i.e. SubState1 and
+ SubState1b.</p></li><li class="listitem"><p>An explicit entry into SubFsm2::SubState2 for region “1” with
+ event2 as trigger, meaning that in region “2” the initial state,
+ SubState1b, activated.</p></li><li class="listitem"><p>A fork into regions “1” and “2” to the explicit entries
+ SubState2 and SubState2b, triggered by event3. Both states
+ become active so no region is default activated (if we had a
+ third one, it would be).</p></li><li class="listitem"><p>A connection of two transitions through an entry pseudo state,
+ SubFsm2::PseudoEntry1, triggered by event4 and triggering also
+ the second transition on the same event (both transitions must
+ be triggered by the same event). Region “2” is default-activated
+ and SubState1b becomes active.</p></li><li class="listitem"><p>An exit from SubFsm2 using an exit pseudo-state, PseudoExit1,
+ triggered by event5 and connecting two transitions using the
+ same event. Again, the event is forwarded to the second
+ transition and both regions are exited, as SubFsm2 becomes
+ inactive. Note that if no transition is defined from
+ PseudoExit1, an error (as defined in the UML standard) will be
+ detected and no_transition called.</p></li></ul></div><p>The example is also <a class="link" href="examples/DirectEntryTutorial.cpp" target="_top">fully implemented</a>.</p><p>This sounds complicated but the syntax is simple.</p><div class="sect3" title="Explicit entry"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1604"></a>Explicit entry</h4></div></div></div><p>First, to define that a state is an explicit entry, you have to make
+ it a state and mark it as explicit, giving as template parameters the
+ region id (the region id starts with 0 and corresponds to the first
+ initial state of the initial_state type sequence).</p><p>
+ </p><pre class="programlisting">struct SubState2 : public msm::front::state<> ,
+ public msm::front::explicit_entry<0></pre><p>
+ </p><p>And define the submachine as:</p><p>
+ </p><pre class="programlisting">typedef msm::back::state_machine<SubFsm2_> SubFsm2;</pre><p>
+ </p><p>You can then use it as target in a transition with State1 as
+ source:</p><p>
+ </p><pre class="programlisting">_row < State1, Event2, SubFsm2::direct< SubFsm2_::SubState2> ></pre><p>
+ </p><p>The syntax deserves some explanation. SubFsm2_ is a front end.
+ SubState2 is a nested state, therefore the SubFsm2_::SubState2 syntax.
+ The containing machine (containing State1 and SubFsm2) refers to the
+ backend instance (SubFsm2). SubFsm2::direct states that an explicit
+ entry is desired.</p><p><span class="underline">Note (also valid for forks)</span>: in
+ order to make compile time more bearable for the more standard cases,
+ and unlike initial states, explicit entry states which are also not
+ found in the transition table of the entered submachine (a rare case) do
+ NOT get automatically created. To explicitly create such states, you
+ need to add in the state machine containing the explicit states a simple
+ typedef giving a sequence of states to be explicitly created
+ like:</p><p>
+ </p><pre class="programlisting">typedef mpl::vector<SubState2,SubState2b> explicit_creation;</pre><p>
+ </p></div><div class="sect3" title="Fork"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1639"></a>Fork</h4></div></div></div><p>Need a fork instead of an explicit entry? As a fork is an explicit
+ entry into states of different regions, we do not change the state
+ definition compared to the explicit entry and specify as target a list
+ of explicit entry states:</p><p>
+ </p><pre class="programlisting">_row < State1, Event3,
+ mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
+ SubFsm2::direct <SubFsm2_::SubState2b>
+ ></pre><p>
+ </p><p>With SubState2 defined as before and SubState2b defined as being in
+ the second region (Caution: MSM does not check that the region is
+ correct):</p><p>
+ </p><pre class="programlisting">struct SubState2b : public msm::front::state<> ,
+ public msm::front::explicit_entry<1></pre><p>
+ </p></div><div class="sect3" title="Entry pseudo states"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1656"></a>Entry pseudo states</h4></div></div></div><p> To define an entry pseudo state, you need derive from the
+ corresponding class and give the region id:</p><p>
+ </p><pre class="programlisting">struct PseudoEntry1 : public msm::front::entry_pseudo_state<0></pre><p>
+ </p><p>And add the corresponding transition in the top-level state machine's
+ transition table:</p><p>
+ </p><pre class="programlisting">_row < State1, Event4, SubFsm2::entry_pt<SubFsm2_::PseudoEntry1> ></pre><p>
+ </p><p>And another in the SubFsm2_ submachine definition (remember that UML
+ defines an entry point as a connection between two transitions), for
+ example this time with an action method:</p><p>
+ </p><pre class="programlisting">_row < PseudoEntry1, Event4, SubState3,&SubFsm2_::entry_action ></pre><p>
+ </p></div><div class="sect3" title="Exit pseudo states"><div class="titlepage"><div><div><h4 class="title"><a name="d0e1680"></a> Exit pseudo states </h4></div></div></div><p>And finally, exit pseudo states are to be used almost the same way,
+ but defined differently: it takes as template argument the event to be
+ forwarded (no region id is necessary):</p><p>
+ </p><pre class="programlisting">struct PseudoExit1 : public exit_pseudo_state<event6></pre><p>
+ </p><p>And you need, like for entry pseudo states, two transitions, one in
+ the submachine:</p><p>
+ </p><pre class="programlisting">_row < SubState3, Event5, PseudoExit1 ></pre><p>
+ </p><p>And one in the containing state machine:</p><p>
+ </p><pre class="programlisting">_row < SubFsm2::exit_pt<SubFsm2_::PseudoExit1>, Event6,State2 ></pre><p>
+ </p><p><span class="underline">Important note 1:</span> UML defines
+ transiting to an entry pseudo state and having either no second
+ transition or one with a guard as an error but defines no error
+ handling. MSM will tolerate this behavior; the entry pseudo state will
+ simply be the newly active state.</p><p><span class="underline">Important note 2</span>: UML defines
+ transiting to an exit pseudo state and having no second transition as an
+ error, and also defines no error handling. Therefore, it was decided to
+ implement exit pseudo state as terminate states and the containing
+ composite not properly exited will stay terminated as it was technically
+ “exited”.</p><p><span class="underline">Important note 3:</span> UML states
+ that for the exit point, the same event must be used in both
+ transitions. MSM relaxes this rule and only wants the event on the
+ inside transition to be convertible to the one of the outside
+ transition. In our case, event6 is convertible from event5. Notice that
+ the forwarded event must be named in the exit point definition. For
+ example, we could define event6 as simply as:</p><p>
+ </p><pre class="programlisting">struct event6
+{
+ event6(){}
+ template <class Event>
+ event6(Event const&){}
+}; //convertible from any event</pre><p>
+ </p></div></div><div class="sect2" title="Flags"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1721"></a>Flags</h3></div></div></div><p>This <a class="link" href="examples/Flags.cpp" target="_top">tutorial</a> is devoted to a
+ concept not defined in UML: flags. It has been added into MSM after proving
+ itself useful on many occasions. Please, do not be frightened as we are not
+ talking about ugly shortcuts made of an improbable collusion of
+ Booleans.</p><p>If you look into the Boost.Statechart documentation you'll find this
+ code:</p><pre class="programlisting">if ( ( state_downcast< const NumLockOff * >() != 0 ) &&
+ ( state_downcast< const CapsLockOff * >() != 0 ) &&
+ ( state_downcast< const ScrollLockOff * >() != 0 ) )
+ </pre><p>While correct and found in many UML books, this can be error-prone and a
+ potential time-bomb when your state machine grows and you add new states or
+ orthogonal regions.</p><p>And most of all, it hides the real question, which would be “does my state
+ machine's current state define a special property”? In this special case
+ “are my keys in a lock state”? So let's apply the Fundamental Theorem of
+ Software Engineering and move one level of abstraction higher.</p><p>In our player example, let's say we need to know if the player has a
+ loaded CD. We could do the same:</p><pre class="programlisting">if ( ( state_downcast< const Stopped * >() != 0 ) &&
+ ( state_downcast< const Open * >() != 0 ) &&
+ ( state_downcast< const Paused * >() != 0 ) &&
+ ( state_downcast< const Playing * >() != 0 )) </pre><p>Or flag these 4 states as CDLoaded-able. You add a flag_list type into
+ each flagged state:</p><p>
+ </p><pre class="programlisting">typedef mpl::vector1<CDLoaded> flag_list;</pre><p>
+ </p><p>You can even define a list of flags, for example in Playing:</p><p>
+ </p><pre class="programlisting">typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;</pre><p>
+ </p><p>This means that Playing supports both properties. To check if your player
+ has a loaded CD, check if your flag is active in the current state:</p><p>
+ </p><pre class="programlisting">player p; if (p.is_flag_active<CDLoaded>()) ... </pre><p>
+ </p><p>And what if you have orthogonal regions? How to decide if a state machine
+ is in a flagged state? By default, you keep the same code and the current
+ states will be OR'ed, meaning if one of the active states has the flag, then
+ is_flag_active returns true. Of course, in some cases, you might want that
+ all of the active states are flagged for the state to be active. You can
+ also AND the active states:</p><p>
+ </p><pre class="programlisting">if (p.is_flag_active<CDLoaded,player::Flag_AND>()) ...</pre><p>
+ </p><p>The following diagram displays the flag situation in the tutorial.</p><p><span class="inlinemediaobject"><img src="../images/FlagsTutorial.jpg" width="60%"></span></p></div><div class="sect2" title="Event Hierarchy"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1775"></a><span class="command"><strong><a name="event-hierarchy"></a></strong></span>Event Hierarchy</h3></div></div></div><p>There are cases where one needs transitions based on categories of events.
+ An example is text parsing. Let's say you want to parse a string and use a
+ state machine to manage your parsing state. You want to parse 4 digits and
+ decide to use a state for every matched digit. Your state machine could look
+ like:</p><p><span class="inlinemediaobject"><img src="../images/ParsingDigits.jpg" width="30%"></span></p><p>But how to detect the digit event? We would like to avoid defining 10
+ transitions on char_0, char_1... between two states as it would force us to
+ write 4 x 10 transitions and the compile-time would suffer. To solve this
+ problem, MSM supports the triggering of a transition on a subclass event.
+ For example, if we define digits as: </p><pre class="programlisting">struct digit {};
+struct char_0 : public digit {}; </pre><p>And to the same for other digits, we can now fire char_0, char_1 events
+ and this will cause a transition with "digit" as trigger to be taken.</p><p>An <a class="link" href="examples/ParsingDigits.cpp" target="_top">example</a> with
+ performance measurement, taken from the documentation of Boost.Xpressive
+ illustrates this example. You might notice that the performance is actually
+ very good (in this case even better).</p></div><div class="sect2" title="Customizing a state machine / Getting more speed"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1796"></a>Customizing a state machine / Getting more speed</h3></div></div></div><p>MSM is offering many UML features at a high-speed, but sometimes, you just
+ need more speed and are ready to give up some features in exchange. A
+ process_event is handling several tasks: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>checking for terminate/interrupt states</p></li><li class="listitem"><p>handling the message queue (for entry/exit/transition actions
+ generating themselves events)</p></li><li class="listitem"><p>handling deferred events</p></li><li class="listitem"><p>catching exceptions (or not)</p></li><li class="listitem"><p>handling the state switching and action calls</p></li></ul></div><p>Of these tasks, only the last one is absolutely necessary to
+ a state machine (its core job), the other ones are nice-to-haves which cost
+ CPU time. In many cases, it is not so important, but in embedded systems,
+ this can lead to ad-hoc state machine implementations. MSM detects by itself
+ if a concrete state machine makes use of terminate/interrupt states and
+ deferred events and deactivates them if not used. For the other two, if you
+ do not need them, you need to help by indicating it in your implementation.
+ This is done with two simple typedefs:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">no_exception_thrown</code> indicates that behaviors will
+ never throw and MSM does not need to catch anything</p></li><li class="listitem"><p><code class="code">no_message_queue</code> indicates that no action will
+ itself generate a new event and MSM can save us the message
+ queue.</p></li></ul></div><p>The third configuration possibility, explained <a class="link" href="ch03s02.html#basic-defer">here</a>, is to manually activate deferred
+ events, using <code class="code">activate_deferred_events</code>. For example, the
+ following state machine sets all three configuration types:</p><pre class="programlisting">struct player_ : public msm::front::state_machine_def<player_>
+{
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+ // also manually enable deferred events
+ typedef int activate_deferred_events
+ ...// rest of implementation
+};</pre></div><div class="sect2" title="Choosing the initial event"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1838"></a>Choosing the initial event</h3></div></div></div><p>A state machine is started using the <code class="code">start</code> method. This
+ causes the initial state's entry behavior to be executed. Like every entry
+ behavior, it becomes as parameter the event causing the state to be entered.
+ But when the machine starts, there was no event triggered. In this case, MSM
+ sends <code class="code">msm::back::state_machine<...>::InitEvent</code>, which might
+ not be the default you'd want. For this special case, MSM provides a
+ configuration mechanism in the form of a typedef. If the state machine's
+ front-end definition provides an initial_event typedef set to another event,
+ this event will be used. For example:</p><pre class="programlisting">struct my_initial_event{};
+struct player_ : public msm::front::state_machine_def<player_>{
+...
+typedef my_initial_event initial_event;
+};</pre></div><div class="sect2" title="Containing state machine (deprecated)"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1851"></a> Containing state machine (deprecated)</h3></div></div></div><p>This feature is still supported in MSM for backward compatibility but made
+ obsolete by the fact that every guard/action/entry action/exit action get
+ the state machine passed as argument and might be removed at a later
+ time.</p><p>All of the states defined in the state machine are created upon state
+ machine construction. This has the huge advantage of a reduced syntactic
+ noise. The cost is a small loss of control for the user on the state
+ creation and access. But sometimes you needed a way for a state to get
+ access to its containing state machine. Basically, a state needs to change
+ its declaration to:</p><pre class="programlisting">struct Stopped : public msm::front::state<sm_ptr></pre><p>And to provide a set_sm_ptr function: <code class="code">void set_sm_ptr(player*
+ pl)</code></p><p>to get a pointer to the containing state machine. The same applies to
+ terminate_state / interrupt_state and entry_pseudo_state /
+ exit_pseudo_state. </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 3. Tutorial </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Functor front-end</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch03s03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch03s03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,269 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Functor front-end</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch03.html" title="Chapter 3. Tutorial"><link rel="prev" href="ch03s02.html" title="Basic front-end"><link rel="next" href="ch03s04.html" title="eUML (experimental)"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Functor front-end</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s02.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Tutorial</th><td width="20%" align="right"> <a accesskey="n" href="ch03s04.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Functor front-end"><div class="titlepage"><div><div><h2 class="title" style="c
lear: both"><a name="d0e1866"></a><span class="command"><strong><a name="functor-front-end"></a></strong></span>Functor front-end</h2></div></div></div><p>The functor front-end is the preferred front-end at the moment. It is more
+ powerful than the standard front-end and has a more readable transition table.
+ It also makes it easier to reuse parts of state machines. Like <span class="command"><strong><a class="command" href="ch03s04.html#eUML-front-end">eUML</a></strong></span>, it also comes with a good deal
+ of predefined actions. Actually, eUML generates a functor front-end through
+ Boost.Typeof and Boost.Proto so both offer the same functionality.</p><p>The rows which MSM offered in the previous front-end come in different
+ flavors. We saw the a_row, g_row, _row, row, not counting internal rows. This is
+ already much to know, so why define new rows? These types have some
+ disadvantages: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>They are more typing and information than we would wish. This
+ means syntactic noise and more to learn.</p></li><li class="listitem"><p>Function pointers are weird in C++.</p></li><li class="listitem"><p>The action/guard signature is limited and does not allow for more
+ variations of parameters (source state, target state, current state
+ machine, etc.)</p></li><li class="listitem"><p>It is not easy to reuse action code from a state machine to
+ another.</p></li></ul></div><div class="sect2" title="Transition table"><div class="titlepage"><div><div><h3 class="title"><a name="d0e1890"></a> Transition table </h3></div></div></div><p>We can change the definition of the simple tutorial's transition table
+ to:</p><p>
+ </p><table id="d0e1897"><tbody><tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>play,</td>
+ <td>Playing,</td>
+ <td>start_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>open_close,</td>
+ <td>Open,</td>
+ <td>open_drawer,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>stop,</td>
+ <td>Stopped,</td>
+ <td> </td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Open ,</td>
+ <td>open_close ,</td>
+ <td>Empty ,</td>
+ <td>close_drawer,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Empty ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Stopped ,</td>
+ <td>store_cd_info ,</td>
+ <td>good_disk_format</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>g_row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Playing ,</td>
+ <td>store_cd_info ,</td>
+ <td>&player_::auto_start</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>stop_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>pause ,</td>
+ <td>Paused ,</td>
+ <td>pause_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>stop_and_open,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>end_pause ,</td>
+ <td>Playing ,</td>
+ <td>resume_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>stop_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr><tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>stop_and_open,</td>
+ <td> none</td>
+ <td>></td>
+ </tr><tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr><tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>Transitions are now of type "Row" with exactly 5 template arguments:
+ source state, event, target state, action and guard. Wherever there is
+ nothing (for example actions and guards), write "none". Actions and guards
+ are no more methods but functors getting as arguments the detected event,
+ the state machine, source and target state:</p><pre class="programlisting">struct store_cd_info
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ void operator()(Evt const&, Fsm& fsm, SourceState&,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+}; </pre><p>The advantage of functors compared to functions are that functors are
+ generic and reusable. They also allow passing more parameters than just
+ events. The guard functors are the same but have an operator() returning a
+ bool.</p><p>It is also possible to mix rows from different front-ends. To show this, a
+ g_row has been left in the transition table. <span class="underline">Note:</span> in case the action functor is used in the transition
+ table of a state machine contained inside a top-level state machine, the
+ “fsm” parameter refers to the lowest-level state machine (referencing this
+ action), not the top-level one.</p><p>To illustrate the reusable point, MSM comes with a whole set of predefined
+ functors. Please refer to eUML for the <a class="link" href="pt02.html#Reference-begin">full list</a>. For example, we are now going to replace the first
+ action by an action sequence and the guard by a more complex functor.</p><p>We decide we now want to execute two actions in the first transition
+ (Stopped -> Playing). We only need to change the action start_playback to
+ </p><pre class="programlisting">ActionSequence_< mpl::vector<some_action, start_playback> ></pre><p>and
+ now will execute some_action and start_playback every time the transition is
+ taken. ActionSequence_ is a functor calling each action of the mpl::vector
+ in sequence.</p><p>We also want to replace good_disk_format by a condition of the type:
+ “good_disk_format && (some_condition || some_other_condition)”. We
+ can achieve this using And_ and Or_ functors:
+ </p><pre class="programlisting">And_<good_disk_format,Or_< some_condition , some_other_condition> ></pre><p>It
+ even starts looking like functional programming. MSM ships with functors for
+ operators, state machine usage, STL algorithms or container methods.</p></div><div class="sect2" title="Defining states with entry/exit actions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2409"></a>Defining states with entry/exit actions</h3></div></div></div><p>You probably noticed that we just showed a different transition table and
+ that we even mixed rows from different front-ends. This means that you can
+ do this and leave the definitions for states unchanged. Most examples are
+ doing this as it is the simplest solution. You still enjoy the simplicity of
+ the first front-end with the extended power of the new transition types.
+ This <a class="link" href="examples/SimpleWithFunctors.cpp" target="_top">tutorial</a>,
+ adapted from the earlier example does just this.</p><p>Of course, it is also possible to define states where entry and exit
+ actions are also provided as functors as these are generated by eUML and
+ both front-ends are equivalent. For example, we can define a state
+ as:</p><pre class="programlisting">struct Empty_Entry
+{
+ template <class Event,class Fsm,class State>
+ void operator()(Event const&,Fsm&,State&)
+ {
+ ...
+ }
+}; // same for Empty_Exit
+struct Empty : public msm::front::euml::func_state<Empty_Entry,Empty_Exit>{};</pre><p>This also means that you can, like in the transition table, write entry /
+ exit actions made of more complicated action combinations. The previous
+ example can therefore <a class="link" href="examples/SimpleWithFunctors2.cpp" target="_top">be
+ rewritten</a>.</p><p>Usually, however, one will probably use the standard state definition as
+ it provides the same capabilities as this front-end state definition, unless
+ one needs some of the shipped predefined functors or is a fan of functional
+ programming.</p></div><div class="sect2" title="Defining a simple state machine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2428"></a>Defining a simple state machine</h3></div></div></div><p>Like states, state machines can be defined using the previous front-end,
+ as the previous example showed, or with the functor front-end, which allows
+ you to define a state machine entry and exit functions as functors, as in
+ <a class="link" href="examples/SimpleWithFunctors2.cpp" target="_top">this
+ example</a>.</p></div><div class="sect2" title="Anonymous transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2436"></a>Anonymous transitions</h3></div></div></div><p>Anonymous (completion) transitions are transitions without a named event.
+ We saw how this front-end uses <code class="code">none</code> when no action or guard is
+ required. We can also use <code class="code">none</code> instead of an event to mark an
+ anonymous transition. For example, the following transition makes an
+ immediate transition from State1 to State2:</p><pre class="programlisting">Row < State1 , none , State2 ></pre><p>The following transition does the same but calling an action in the
+ process:</p><pre class="programlisting">Row < State1 , none , State2 , State1ToState2, none ></pre><p>The following diagram shows an example and its <a class="link" href="examples/AnonymousTutorialWithFunctors.cpp" target="_top">implementation</a>:</p><p><span class="inlinemediaobject"><img src="../images/Anonymous.jpg" width="70%"></span></p></div><div class="sect2" title="Internal transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2462"></a><span class="command"><strong><a name="functor-internal-transitions"></a></strong></span>Internal
+ transitions</h3></div></div></div><p>The <a class="link" href="examples/SimpleTutorialInternalFunctors.cpp" target="_top">following example</a> uses internal transitions with the functor
+ front-end. As for the simple standard front-end, both methods of defining
+ internal transitions are supported:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>providing a <code class="code">Row</code> in the state machine's transition
+ table with <code class="code">none</code> as target state defines an internal
+ transition.</p></li><li class="listitem"><p>providing an <code class="code">internal_transition_table</code> made of
+ <code class="code">Internal</code> rows inside a state or submachine
+ defines UML-conform internal transitions with higher
+ priority.</p></li><li class="listitem"><p>transitions defined inside
+ <code class="code">internal_transition_table</code> require no source or
+ target state as the source state is known (<code class="code">Internal</code>
+ really are <code class="code">Row</code> without a source or target state)
+ .</p></li></ul></div><p>Like for the <span class="command"><strong><a class="command" href="ch03s02.html#internal-transitions-note">standard front-end internal transitions</a></strong></span>, internal transition
+ tables are added into the main state machine's table, thus allowing you to
+ distribute the transition table definition and reuse states.</p><p>There is an added bonus offered for submachines, which can have both the
+ standard transition_table and an internal_transition_table (which has higher
+ priority). This makes it easier if you decide to make a full submachine from
+ a state later. It is also slightly faster than the standard alternative,
+ adding orthogonal regions, because event dispatching will, if accepted by
+ the internal table, not continue to the subregions. This gives you a O(1)
+ dispatch instead of O(number of regions). While the example is with eUML,
+ the same is also possible with this front-end.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Basic front-end </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> eUML (experimental)</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch03s04.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch03s04.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,488 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>eUML (experimental)</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch03.html" title="Chapter 3. Tutorial"><link rel="prev" href="ch03s03.html" title="Functor front-end"><link rel="next" href="ch03s05.html" title="Back-end"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">eUML (experimental)</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s03.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Tutorial</th><td width="20%" align="right"> <a accesskey="n" href="ch03s05.html">Next</a></td></tr></table><hr></div><div class="sect1" title="eUML (experimental)"><div class="titlepage"><div><div><h2 class="title" style="clea
r: both"><a name="d0e2508"></a><span class="command"><strong><a name="eUML-front-end"></a></strong></span>eUML (experimental)</h2></div></div></div><p><span class="underline">Important note</span>: eUML requires a compiler
+ supporting the C++0x decltype/typeof feature (for example VC >= 9, g++ >= 4.3.
+ VC8 supports eUML but will crash with middle-size state machines). More
+ generally, eUML has experimental status because most compilers will start
+ crashing when a state machine becomes too big. Only g++ 4.3 (unfortunately not
+ 4.4 which shows a serious regression) seems perfectly resilient.</p><p>The previous front-ends are simple to write but still force an amount of
+ noise, mostly MPL types, so it would be nice to write code looking like C++
+ (with a C++ action language) directly inside the transition table, like UML
+ designers like to do on their state machine diagrams. If it were functional
+ programming, it would be even better. This is what eUML is for.</p><p>eUML is a Boost.Proto and Boost.Typeof-based compile-time domain specific
+ embedded language. It provides grammars which allow the definition of
+ actions/guards directly inside the transition table or entry/exit in the state
+ definition. There are grammars for actions, guards, flags, attributes, deferred
+ events, initial states.</p><p>It also relies on Boost.Typeof as a wrapper around the new decltype C++0x
+ feature to provide a compile-time evaluation of all the grammars. Unfortunately,
+ all the underlying Boost libraries are not Typeof-enabled, so for the moment,
+ you will need a compiler where Typeof is natively implemented (like VC8-9-10,
+ g++ >= 4.3).</p><p>Examples will be provided in the next paragraphs. You need to include eUML
+ basic features: </p><p>
+ </p><pre class="programlisting">#include <msm/front/euml/euml.hpp></pre><p>
+ </p><p>To add STL support (at possible cost of longer compilation times), include: </p><p>
+ </p><pre class="programlisting">#include <msm/front/euml/stl.hpp></pre><p>
+ </p><p>eUML is defined in the namespace <code class="code">msm::front::euml</code>.</p><div class="sect2" title="Transition table"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2541"></a>Transition table</h3></div></div></div><p>A transition can be defined using eUML as: </p><p>
+ </p><pre class="programlisting">source + event [guard] / action == target</pre><p>
+ </p><p>or as</p><p>
+ </p><pre class="programlisting">target == source + event [guard] / action</pre><p>
+ </p><p>The first version looks like a drawn transition in a diagram, the second
+ one seems natural to a C++ developer.</p><p>The simple transition table written with the <span class="command"><strong><a class="command" href="ch03s03.html#functor-front-end">previous front-end</a></strong></span> can now be
+ written as:</p><p>
+ </p><table frame="void" id="d0e2567"><tbody><tr>
+ <td>BOOST_MSM_EUML_TRANSITION_TABLE(( </td>
+ <td> </td>
+ </tr><tr>
+ <td>Stopped +</td>
+ <td>play [DummyGuard] / (TestFct,start_playback)</td>
+ <td>== Playing</td>
+ </tr><tr>
+ <td>Stopped +</td>
+ <td>open_close/ open_drawer</td>
+ <td>== Open</td>
+ </tr><tr>
+ <td>Stopped +</td>
+ <td>stop</td>
+ <td>== Stopped</td>
+ </tr><tr>
+ <td>Open +</td>
+ <td>open_close / close_drawer</td>
+ <td>== Empty</td>
+ </tr><tr>
+ <td>Empty +</td>
+ <td>open_close / open_drawer </td>
+ <td>== Open</td>
+ </tr><tr>
+ <td>Empty +</td>
+ <td>cd_detected [good_disk_format] / store_cd_info </td>
+ <td>== Stopped</td>
+ </tr><tr>
+ <td>),transition_table)</td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>Or, using the alternative notation, it can be:</p><p>
+ </p><table id="d0e2659"><tbody><tr>
+ <td>BOOST_MSM_EUML_TRANSITION_TABLE((</td>
+ <td> </td>
+ <td> </td>
+ </tr><tr>
+ <td>Playing == </td>
+ <td>Stopped +</td>
+ <td>play [DummyGuard] / (TestFct,start_playback)</td>
+ </tr><tr>
+ <td>Open ==</td>
+ <td>Stopped +</td>
+ <td>open_close/ open_drawer</td>
+ </tr><tr>
+ <td>Stopped ==</td>
+ <td>Stopped +</td>
+ <td>stop</td>
+ </tr><tr>
+ <td>Empty ==</td>
+ <td>Open +</td>
+ <td>open_close / close_drawer</td>
+ </tr><tr>
+ <td>Open ==</td>
+ <td>Empty +</td>
+ <td>open_close / open_drawer</td>
+ </tr><tr>
+ <td>Stopped ==</td>
+ <td>Empty +</td>
+ <td>cd_detected [good_disk_format] / store_cd_info </td>
+ </tr><tr>
+ <td>),transition_table)</td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><p>The transition table now looks like a list of (readable) rules with little
+ noise.</p><p>UML defines guards between “[ ]” and actions after a “/”, so the chosen
+ syntax is already more readable for UML designers. UML also allows designers
+ to define several actions sequentially (our previous ActionSequence_)
+ separated by a comma. The first transition does just this: two actions
+ separated by a comma and enclosed inside parenthesis to respect C++ operator
+ precedence.</p><p>If this seems to you like it will cost you run-time performance, don't
+ worry, eUML is based on typeof (decltype) which only evaluates the
+ parameters to BOOST_MSM_EUML_TRANSITION_TABLE and no run-time cost occurs.
+ Actually, eUML is only a metaprogramming layer on top of "standard" MSM
+ metaprogramming and this first layer generates the previously-introduced
+ <span class="command"><strong><a class="command" href="ch03s03.html#functor-front-end">functor
+ front-end</a></strong></span>.</p><p>UML also allows designers to define more complicated guards, like
+ [good_disk_format && (some_condition || some_other_condition)]. This
+ was possible with our previously defined functors, but using a complicated
+ template syntax. This syntax is now possible exactly as written, which means
+ without any syntactic noise at all.</p></div><div class="sect2" title="Defining events, actions and states with entry/exit actions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2761"></a>Defining events, actions and states with entry/exit actions</h3></div></div></div><div class="sect3" title="Events"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2764"></a>Events</h4></div></div></div><p>Events must be proto-enabled. To achieve this, they must inherit from
+ a proto terminal (euml_event<event-name>). eUML also provides a macro
+ to make this easier:</p><p>
+ </p><pre class="programlisting">BOOST_MSM_EUML_EVENT(play)</pre><p>
+ </p><p>This declares an event type and an instance of this type called
+ <code class="code">play</code>, which is now ready to use in state or transition
+ behaviors.</p><p>There is a second macro, BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES, which
+ takes as second parameter the attributes an event will contain, using
+ the <span class="command"><strong><a class="command" href="ch03s04.html#eUML-attributes">attribute
+ syntax</a></strong></span>.</p><p><span class="underline">Note</span>: as we now have events
+ defined as instances instead of just types, can we still process an
+ event by creating one on the fly, like:
+ <code class="code">fsm.process_event(play());</code> or do we have to write:
+ <code class="code">fsm.process_event(play);</code></p><p>The answer is you can do both. The second one is easier but unlike
+ other front-ends, the second uses a defined operator(), which creates an
+ event on the fly.</p></div><div class="sect3" title="Actions"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2795"></a>Actions</h4></div></div></div><p>Actions (returning void) and guards (returning a bool) are defined
+ like previous functors, with the difference that they also must be
+ proto-enabled. This can be done by inheriting from euml_action<
+ functor-name >. eUML also provides a macro:</p><pre class="programlisting">BOOST_MSM_EUML_ACTION(some_condition)
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ bool operator()(Evt const& ,Fsm& ,SourceState&,TargetState& )
+ { return true; }
+}; </pre><p>Like for events, this macro declares a functor type and an instance
+ for use in transition or state behaviors.</p><p>It is possible to use the same action grammar from the transition
+ table to define state entry and exit behaviors. So
+ <code class="code">(action1,action2)</code> is a valid entry or exit behavior
+ executing both actions in turn.</p><p>The state functors have a slightly different signature as there is no
+ source and target state but only a current state (entry/exit actions are
+ transition-independent), for example:</p><pre class="programlisting">BOOST_MSM_EUML_ACTION(Empty_Entry)
+{
+ template <class Evt,class Fsm,class State>
+ void operator()(Evt const& ,Fsm& ,State& ) { ... }
+}; </pre></div><div class="sect3" title="States"><div class="titlepage"><div><div><h4 class="title"><a name="d0e2813"></a>States</h4></div></div></div><p>There is also a macro for states. This macro has 2 arguments, first
+ the expression defining the state, then the state (instance)
+ name:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((),Paused)</pre><p>This defines a simple state without entry or exit action. You can
+ provide in the expression parameter the state behaviors (entry and exit)
+ using the action grammar, like in the transition table:</p><pre class="programlisting">BOOST_MSM_EUML_STATE(((Empty_Entry,Dummy_Entry)/*2 entryactions*/,
+ Empty_Exit/*1 exit action*/ ),
+ Empty)</pre><p>This means that Empty is defined as a state with an entry action made
+ of two sub-actions, Empty_Entry and Dummy_Entry (enclosed inside
+ parenthesis), and an exit action, Empty_Exit.</p><p>There are several possibilitites for the <span class="command"><strong><a name="eUML-build-state"></a></strong></span> expression syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(): state without entry or exit action.</p></li><li class="listitem"><p>(Expr1): state with entry but no exit action.</p></li><li class="listitem"><p>(Expr1,Expr2): state with entry and exit action.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes): state with entry and exit
+ action, defining some attributes (read further on).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure): state with entry and
+ exit action, defining some attributes (read further on) and
+ flags (standard MSM flags) or deferred events (standard MSM
+ deferred events).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure,Base): state with entry
+ and exit action, defining some attributes (read further on),
+ flags and deferred events (plain msm deferred events) and a
+ non-default base state (as defined in standard MSM).</p></li></ul></div><p>no_action is also defined, which does, well, nothing except being a
+ placeholder (needed for example as entry action if we have no entry but
+ an exit). Expr1 and Expr2 are a sequence of actions, obeying the same
+ action grammar as in the transition table (following the “/”
+ symbol).</p><p>The BOOST_MSM_EUML_STATE macro will allow you to define most common
+ states, but sometimes you will need more, for example provide in your
+ states some special behavior. In this case, you will have to do the
+ macro's job by hand, which is not very complicated. The state will need
+ to inherit from <code class="code">msm::front::state<></code>, like any state, and
+ from <code class="code">euml_state<state-name></code> to be proto-enabled. You
+ will then need to declare an instance for use in the transition table.
+ For example:</p><pre class="programlisting">struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
+{
+ void activate_empty() {std::cout << "switching to Empty " << std::endl;}
+ template <class Event,class Fsm>
+ void on_entry(Event const& evt,Fsm&fsm){...}
+ template <class Event,class Fsm>
+ void on_exit(Event const& evt,Fsm&fsm){...}
+};
+//instance for use in the transition table
+Empty_impl const Empty;</pre><p>Notice also that we defined a method named activate_empty. We would
+ like to call it inside a behavior. This can be done using the
+ BOOST_MSM_EUML_METHOD macro. </p><pre class="programlisting">BOOST_MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</pre><p>The first parameter is the name of the underlying functor, which you
+ could use with the functor front-end, the second is the state method
+ name, the third is the eUML-generated function, the fourth and fifth the
+ return value when used inside a transition or a state behavior. You can
+ now use this inside a transition:</p><pre class="programlisting">Empty == Open + open_close / (close_drawer,activate_empty_(target_))</pre></div></div><div class="sect2" title="Defining a simple state machine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2869"></a>Defining a simple state machine</h3></div></div></div><p>You can reuse the state machine definition method from the standard
+ front-end and simply replace the transition table by this new one. You can
+ also use eUML to define a state machine "on the fly" (if, for example, you
+ need to provide an on_entry/on_exit for this state machine as a functor).
+ For this, there is also a macro, <span class="command"><strong><a name="eUML-build-sm"></a></strong></span>BOOST_MSM_EUML_DECLARE_STATE_MACHINE, which has 2 arguments, an expression
+ describing the state machine and the state machine name. The expression has
+ up to 8 arguments:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(Stt, Init): simplest state machine where only the transition
+ table and initial state(s) are defined.</p></li><li class="listitem"><p>(Stt, Init, Expr1): state machine where the transition table,
+ initial state and entry action are defined.</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2): state machine where the transition
+ table, initial state, entry and exit actions are defined.</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2, Attributes): state machine where the
+ transition table, initial state, entry and exit actions are
+ defined. Furthermore, some attributes are added (read further
+ on).</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2, Attributes, Configure): state
+ machine where the transition table, initial state, entry and
+ exit actions are defined. Furthermore, some attributes (read
+ further on), flags, deferred events and <a class="link" href="ch03s04.html#eUML-Configuration">configuration
+ capabilities</a> (no message queue / no exception
+ catching) are added.</p></li><li class="listitem"><p>(Stt, Init, Expr1, Expr2, Attributes, Flags, Deferred , Base):
+ state machine where the transition table, initial state, entry
+ and exit actions are defined. Furthermore, attributes (read
+ further on), flags , deferred events and configuration
+ capabilities (no message queue / no exception catching) are
+ added and a non-default base state (see the <a class="link" href="ch03s05.html#backend-base-state">back-end
+ description</a>) is defined.</p></li></ul></div><p>For example, a minimum state machine could be defined
+ as:</p><p>
+ </p><table id="d0e2904"><tbody><tr>
+ <td>BOOST_MSM_EUML_TRANSITION_TABLE((</td>
+ <td> </td>
+ <td> </td>
+ </tr><tr>
+ <td>),transition_table)</td>
+ <td> </td>
+ <td> </td>
+ </tr></tbody></table><p>
+ </p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,init_ << Empty ),
+ player_)</pre><p>Please have a look at the player tutorial written using eUML's <a class="link" href="examples/SimpleTutorialEuml2.cpp" target="_top">first</a> and <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">second</a> syntax. The
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE macro, to which we will get back shortly,
+ declares attributes given to an eUML type (state or event) using the
+ <span class="command"><strong><a class="command" href="ch03s04.html#eUML-attributes">attribute
+ syntax</a></strong></span>.</p></div><div class="sect2" title="Defining a submachine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2942"></a>Defining a submachine</h3></div></div></div><p>Defining a submachine (see <a class="link" href="examples/CompositeTutorialEuml.cpp" target="_top">tutorial</a>) with
+ other front-ends simply means using a state which is a state machine in the
+ transition table of another state machine. This is the same with eUML. One
+ only needs define a second state machine and reference it in the transition
+ table of the containing state machine.</p><p>Unlike the state or event definition macros,
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE defines a type, not an instance because
+ a type is what the back-end requires. This means that you will need to
+ declare yourself an instance to reference your submachine into another state
+ machine, for example:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE(...,Playing_)
+typedef msm::back::state_machine<Playing_> Playing_type;
+Playing_type const Playing;</pre><p>We can now use this instance inside the transition table of the containing
+ state machine:</p><pre class="programlisting">Paused == Playing + pause / pause_playback</pre></div><div class="sect2" title="Attributes / Function call"><div class="titlepage"><div><div><h3 class="title"><a name="d0e2958"></a>
+ <span class="command"><strong><a name="eUML-attributes"></a></strong></span>Attributes / Function call</h3></div></div></div><p>We now want to make our grammar more useful. Very often, one needs only
+ very simple action methods, for example ++Counter or Counter > 5 where
+ Counter is usually defined as some attribute of the class containing the
+ state machine. It seems like a waste to write a functor for such a simple
+ action. Furthermore, states within MSM are also classes so they can have
+ attributes, and we would also like to provide them with attributes. </p><p>If you look back at our examples using the <a class="link" href="examples/SimpleTutorialEuml2.cpp" target="_top">first</a> and <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">second</a> syntaxes, you
+ will find a BOOST_MSM_EUML_DECLARE_ATTRIBUTE and a BOOST_MSM_EUML_ATTRIBUTES
+ macro. The first one declares possible attributes:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)</pre><p>This declares two attributes: cd_name of type std::string and cd_type of
+ type DiskTypeEnum. These attributes are not part of any event or state in
+ particular, we just declared a name and a type. Now, we can add attributes
+ to our cd_detected event using the second one:</p><pre class="programlisting">BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ),
+ cd_detected_attributes)</pre><p>This declares an attribute list which is not linked to anything in
+ particular yet. It can be attached to a state or an event. For example, if
+ we want the event cd_detected to have these defined attributes we
+ write:</p><pre class="programlisting">BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)</pre><p>For states, we use the BOOST_MSM_EUML_STATE macro, which has an expression
+ form where one can provide attributes. For example:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((no_action /*entry*/,no_action/*exit*/,
+ attributes_ << cd_detected_attributes),
+ some_state)</pre><p>OK, great, we now have a way to add attributes to a class, which we could
+ have done more easily, so what is the point? The point is that we can now
+ reference these attributes directly, at compile-time, in the transition
+ table. For example, in the example, you will find this transition:</p><pre class="programlisting">Stopped==Empty+cd_detected[good_disk_format&&(event_(cd_type)==Int_<DISK_CD>())] </pre><p>Read event_(cd_type) as event_->cd_type with event_ a type generic for
+ events, whatever the concrete event is (in this particular case, it happens
+ to be a cd_detected as the transition shows).</p><p>The main advantage of this feature is that you do not need to define a new
+ functor and you do not need to look inside the functor to know what it does,
+ you have all at hand.</p><p>MSM provides more generic objects for state machine types:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>event_ : used inside any action, the event triggering the
+ transition</p></li><li class="listitem"><p>state_: used inside entry and exit actions, the entered /
+ exited state</p></li><li class="listitem"><p>source_: used inside a transition action, the source
+ state</p></li><li class="listitem"><p>target_: used inside a transition action, the target
+ state</p></li><li class="listitem"><p>fsm_: used inside any action, the (lowest-level) state machine
+ processing the transition</p></li><li class="listitem"><p>Int_<int value>: a functor representing an int</p></li><li class="listitem"><p>Char_<value>: a functor representing a char</p></li><li class="listitem"><p>Size_t_<value>: a functor representing a size_t</p></li><li class="listitem"><p>String_<mpl::string> (boost >= 1.40): a functor
+ representing a string.</p></li></ul></div><p>These helpers can be used in two different ways:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>helper(attribute_name) returns the attribute with name
+ attribute_name</p></li><li class="listitem"><p>helper returns the state / event type itself.</p></li></ul></div><p>The second form is helpful if you want to provide your states with their
+ own methods, which you also want to use inside the transition table. In the
+ <a class="link" href="examples/SimpleTutorialEuml.cpp" target="_top">above
+ tutorial</a>, we provide Empty with an activate_empty method. We would
+ like to create a eUML functor and call it from inside the transition table.
+ This is done using the MSM_EUML_METHOD / MSM_EUML_FUNCTION macros. The first
+ creates a functor to a method, the second to a free function. In the
+ tutorial, we write:</p><pre class="programlisting">MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</pre><p>The first parameter is the functor name, for use with the functor
+ front-end. The second is the name of the method to call. The third is the
+ function name for use with eUML, the fourth is the return type of the
+ function if used in the context of a transition action, the fifth is the
+ result type if used in the context of a state entry / exit action (usually
+ fourth and fifth are the same). We now have a new eUML function calling a
+ method of "something", and this "something" is one of the five previously
+ shown generic helpers. We can now use this in a transition, for
+ example:</p><pre class="programlisting">Empty == Open + open_close / (close_drawer,activate_empty_(target_))</pre><p>The action is now defined as a sequence of two actions: close_drawer and
+ activate_empty, which is called on the target itself. The target being Empty
+ (the state defined left), this really will call Empty::activate_empty().
+ This method could also have an (or several) argument(s), for example the
+ event, we could then call activate_empty_(target_ , event_).</p><p>More examples can be found in the <a class="link" href="examples/CompilerStressTestEuml.cpp" target="_top">terrible compiler
+ stress test</a>, the <a class="link" href="examples/SimpleTimer.cpp" target="_top">timer example</a> or in the <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">iPodSearch with eUML</a>
+ (for String_ and more).</p></div><div class="sect2" title="Orthogonal regions, flags, event deferring"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3058"></a>Orthogonal regions, flags, event deferring</h3></div></div></div><p>Defining orthogonal regions really means providing more initial states. To
+ add more initial states, “shift left” some, for example, if we had another
+ initial state named AllOk :</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
+ init_ << Empty << AllOk ),
+ player_)</pre><p>You remember from the <span class="command"><strong><a class="command" href="ch03s04.html#eUML-build-state">BOOST_MSM_EUML_STATE </a></strong></span> and <span class="command"><strong><a class="command" href="ch03s04.html#eUML-build-sm">BOOST_MSM_EUML_DECLARE_STATE_MACHINE</a></strong></span> signatures that just
+ after attributes, we can define flags, like in the basic MSM front-end. To
+ do this, we have another "shift-left" grammar, for example:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((no_action,no_action, attributes_ <<no_attributes_,
+ /* flags */ configure_<< PlayingPaused << CDLoaded),
+ Paused)</pre><p>We now defined that Paused will get two flags, PlayingPaused and CDLoaded,
+ defined, with another macro:</p><pre class="programlisting">BOOST_MSM_EUML_FLAG(CDLoaded)</pre><p>This corresponds to the following basic front-end definition of
+ Paused:</p><pre class="programlisting">struct Paused : public msm::front::state<>
+{
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+};</pre><p>Under the hood, what you get really is a mpl::vector2.</p><p><span class="underline">Note</span>: As we use the version of
+ BOOST_MSM_EUML_STATE's expression with 4 arguments, we need to tell eUML
+ that we need no attributes. Similarly to a <code class="code">cout << endl</code>,
+ we need a <code class="code">attributes_ << no_attributes_</code> syntax.</p><p>You can use the flag with the is_flag_active method of a state machine.
+ You can also use the provided helper function is_flag_ (returning a bool)
+ for state and transition behaviors. For example, in the <a class="link" href="examples/iPodEuml.cpp" target="_top">iPod implementation with eUML</a>,
+ you find the following transition:</p><pre class="programlisting">ForwardPressed == NoForward + EastPressed[!is_flag_(NoFastFwd)]</pre><p>The function also has an optional second parameter which is the state
+ machine on which the function is called. By default, fsm_ is used (the
+ current state machine) but you could provide a functor returning a reference
+ to another state machine.</p><p>eUML also supports defining deferred events in the state (state machine)
+ definition. To this aim, we can reuse the flag grammar. For example:</p><pre class="programlisting">BOOST_MSM_EUML_STATE((Empty_Entry,Empty_Exit, attributes_ << no_attributes_,
+ /* deferred */ configure_<< play ),Empty) </pre><p>The configure_ left shift is also responsible for deferring events. Shift
+ inside configure_ a flag and the state will get a flag, shift an event and
+ it will get a deferred event. This replaces the basic front-end
+ definition:</p><pre class="programlisting">typedef mpl::vector<play> deferred_events;</pre><p>In <a class="link" href="examples/OrthogonalDeferredEuml.cpp" target="_top">this
+ tutorial</a>, player is defining a second orthogonal region with
+ AllOk as initial state. The <code class="code">Empty</code> and <code class="code">Open</code> states
+ also defer the event <code class="code">play</code>. <code class="code">Open</code>,
+ <code class="code">Stopped</code> and <code class="code">Pause</code> also support the flag
+ <code class="code">CDLoaded</code> using the same left shift into
+ <code class="code">configure_</code>.</p><p>In the functor front-end, we also had the possibility to defer an event
+ inside a transition, which makes possible conditional deferring. This is
+ also possible with eUML through the use of the defer_ order, as shown in
+ <a class="link" href="examples/OrthogonalDeferredEuml.cpp" target="_top">this
+ tutorial</a>. You will find the following transition:</p><pre class="programlisting">Open + play / defer_</pre><p>This is an <span class="command"><strong><a class="command" href="ch03s04.html#eUML-internal">internal
+ transition</a></strong></span>. Ignore it for the moment. Interesting is, that
+ when the event <code class="code">play</code> is fired and <code class="code">Open</code> is active,
+ the event will be deferred. Now add a guard and you can conditionally defer
+ the event, for example:</p><pre class="programlisting">Open + play [ some_condition ] / defer_</pre><p>This is similar to what we did with the functor front-end. This means that
+ we have the same constraints. Using defer_ instead of a state declaration,
+ we need to tell MSM that we have deferred events in this state machine. We
+ do this (again) using a configure_ declaration in the state machine
+ definition in which we shift the deferred_events configuration flag:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
+ init_ << Empty << AllOk,
+ Entry_Action,
+ Exit_Action,
+ attributes_ << no_attributes_,
+ configure_<< deferred_events ),
+ player_)</pre><p>A <a class="link" href="examples/OrthogonalDeferredEuml2.cpp" target="_top">tutorial</a>
+ illustrates this possibility.</p></div><div class="sect2" title="Customizing a state machine / Getting more speed"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3170"></a>
+ <span class="command"><strong><a name="eUML-Configuration"></a></strong></span>Customizing a state machine / Getting
+ more speed</h3></div></div></div><p>We just saw how to use configure_ to define deferred events or flags. We
+ can also use it to configure our state machine like we did with the other front-ends:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">configure_ << no_exception</code>: disables
+ exception handling</p></li><li class="listitem"><p><code class="code">configure_ << no_msg_queue</code> deactivates the
+ message queue</p></li><li class="listitem"><p><code class="code">configure_ << deferred_events</code> manually
+ enables event deferring</p></li></ul></div><p>Deactivating the first two features and not activating the third if not
+ needed greatly improves the event dispatching speed of your state machine.
+ Our <a class="link" href="examples/EumlSimple.cpp" target="_top">speed testing</a> example
+ with eUML does this for the best performance.</p></div><div class="sect2" title="Completion / Anonymous transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3198"></a>Completion / Anonymous transitions</h3></div></div></div><p>Anonymous transitions (See <span class="command"><strong><a class="command" href="ch02s02.html#uml-anonymous">UML
+ tutorial</a></strong></span>) are transitions without a named event, which are
+ therefore triggered immediately when the source state becomes active,
+ provided a guard allows it. As there is no event, to define such a
+ transition, simply omit the “+” part of the transition (the event), for
+ example: </p><pre class="programlisting">State3 == State4 [always_true] / State3ToState4
+State4 [always_true] / State3ToState4 == State3</pre><p>Please have a look at <a class="link" href="examples/AnonymousTutorialEuml.cpp" target="_top">this example</a>,
+ which implements the <span class="command"><strong><a class="command" href="ch03s02.html#anonymous-transitions">previously
+ defined</a></strong></span> state machine with eUML.</p></div><div class="sect2" title="Internal transitions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3216"></a><span class="command"><strong><a name="eUML-internal"></a></strong></span>Internal transitions</h3></div></div></div><p>Like both other front-ends, eUML supports two ways of defining internal transitions:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>in the state machine's transition table. In this case, you
+ need to specify a source state, event, actions and guards but no
+ target state, which eUML will interpret as an internal
+ transition, for example this defines a transition internal to
+ Open, on the event open_close:</p><pre class="programlisting">Open + open_close [internal_guard1] / internal_action1</pre><p><a class="link" href="examples/EumlInternal.cpp" target="_top">A full
+ example</a> is also provided.</p></li><li class="listitem"><p>in a state's <code class="code">internal_transition_table</code>. For
+ example:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
+struct Open_impl : public Open_def
+{
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ open_close [internal_guard1] / internal_action1
+ ))
+};</pre><p>Notice how we do not need to repeat that the transition
+ originates from Open as we already are in Open's context. </p><p>The <a class="link" href="examples/EumlInternalDistributed.cpp" target="_top">implementation</a> also shows the added bonus offered
+ for submachines, which can have both the standard
+ transition_table and an internal_transition_table (which has
+ higher priority). This makes it easier if you decide to make a
+ full submachine from a state. It is also slightly faster than
+ the standard alternative, adding orthogonal regions, because
+ event dispatching will, if accepted by the internal table, not
+ continue to the subregions. This gives you a O(1) dispatch
+ instead of O(number of regions).</p></li></ul></div></div><div class="sect2" title="Other state types"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3247"></a>Other state types</h3></div></div></div><p>We saw the <span class="command"><strong><a class="command" href="ch03s04.html#eUML-build-state">build_state</a></strong></span>
+ function, which creates a simple state. Likewise, eUML provides other
+ state-building macros for other types of states:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>BOOST_MSM_EUML_TERMINATE_STATE takes the same arguments as
+ BOOST_MSM_EUML_STATE and defines, well, a terminate
+ state.</p></li><li class="listitem"><p>BOOST_MSM_EUML_INTERRUPT_STATE takes the same arguments as
+ BOOST_MSM_EUML_STATE and defines an interrupt state. However,
+ the expression argument must contain as first element the event
+ ending the interruption, for example:
+ <code class="code">BOOST_MSM_EUML_INTERRUPT_STATE(( end_error /*end
+ interrupt event*/,ErrorMode_Entry,ErrorMode_Exit
+ ),ErrorMode)</code></p></li><li class="listitem"><p>BOOST_MSM_EUML_EXIT_STATE takes the same arguments as
+ BOOST_MSM_EUML_STATE and defines an exit pseudo state. However,
+ the expression argument must contain as first element the event
+ propagated from the exit point:
+ <code class="code">BOOST_MSM_EUML_EXIT_STATE(( event6 /*propagated
+ event*/,PseudoExit1_Entry,PseudoExit1_Exit
+ ),PseudoExit1)</code></p></li><li class="listitem"><p>BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE defines an entry pseudo
+ state. It takes 3 parameters: the region index to be entered is
+ defined as an int argument, followed by the configuration
+ expression like BOOST_MSM_EUML_STATE and the state name, so that
+ <code class="code">BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0 /*region
+ index*/,( SubState2_Entry,SubState2_Exit ),SubState2)</code>
+ defines an entry state into the first region of a
+ submachine.</p></li><li class="listitem"><p>BOOST_MSM_EUML_ENTRY_STATE defines an entry pseudo state. It
+ takes 3 parameters: the region index to be entered is defined as
+ an int argument, followed by the configuration expression like
+ BOOST_MSM_EUML_STATE and the state name, so that
+ <code class="code">BOOST_MSM_EUML_ENTRY_STATE(0,(
+ PseudoEntry1_Entry,PseudoEntry1_Exit ),PseudoEntry1)</code>
+ defines a pseudo entry state into the first region of a
+ submachine.</p></li></ul></div><p>To use these states in the transition table, eUML offers the functions
+ <code class="code">explicit_</code>, <code class="code">exit_pt_</code> and
+ <code class="code">entry_pt_</code>. For example, a direct entry into the substate
+ SubState2 from SubFsm2 could be:</p><pre class="programlisting">explicit_(SubFsm2,SubState2) == State1 + event2</pre><p>Forks being a list on direct entries, eUML supports a logical syntax
+ (state1, state2, ...), for example:</p><pre class="programlisting">(explicit_(SubFsm2,SubState2),
+ explicit_(SubFsm2,SubState2b),
+ explicit_(SubFsm2,SubState2c)) == State1 + event3 </pre><p>An entry point is entered using the same syntax as explicit entries:
+ </p><pre class="programlisting">entry_pt_(SubFsm2,PseudoEntry1) == State1 + event4</pre><p>For exit points, it is again the same syntax except that exit points are
+ used as source of the transition:
+ </p><pre class="programlisting">State2 == exit_pt_(SubFsm2,PseudoExit1) + event6 </pre><p>The <a class="link" href="examples/DirectEntryEuml.cpp" target="_top">entry tutorial</a>
+ is also available with eUML.</p></div><div class="sect2" title="Helper functions"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3311"></a>Helper functions</h3></div></div></div><p>We saw a few helpers but there are more, so let us have a more complete description:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>event_ : used inside any action, the event triggering the
+ transition</p></li><li class="listitem"><p>state_: used inside entry and exit actions, the entered /
+ exited state</p></li><li class="listitem"><p>source_: used inside a transition action, the source
+ state</p></li><li class="listitem"><p>target_: used inside a transition action, the target
+ state</p></li><li class="listitem"><p>fsm_: used inside any action, the (deepest-level) state
+ machine processing the transition</p></li><li class="listitem"><p>These objects can also be used as a function and return an
+ attribute, for example event_(cd_name)</p></li><li class="listitem"><p>Int_<int value>: a functor representing an int</p></li><li class="listitem"><p>Char_<value>: a functor representing a char</p></li><li class="listitem"><p>Size_t_<value>: a functor representing a size_t</p></li><li class="listitem"><p>True_ and False_ functors returning true and false
+ respectively</p></li><li class="listitem"><p>String_<mpl::string> (boost >= 1.40): a functor
+ representing a string.</p></li><li class="listitem"><p>if_then_else_(guard, action, action) where action can be an
+ action sequence</p></li><li class="listitem"><p>if_then_(guard, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>while_(guard, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>do_while_(guard, action) where action can be an action
+ sequence</p></li><li class="listitem"><p>for_(action, guard, action, action) where action can be an
+ action sequence</p></li><li class="listitem"><p>process_(some_event [, some state machine] [, some state
+ machine] [, some state machine] [, some state machine]) will
+ call process_event (some_event) on the current state machine or
+ on the one(s) passed as 2nd , 3rd, 4th, 5th argument. This allow
+ sending events to several external machines</p></li><li class="listitem"><p>process2_(some_event,Value [, some state machine] [, some
+ state machine] [, some state machine]) will call process_event
+ (some_event(Value)) on the current state machine or on the
+ one(s) passed as 3rd, 4th, 5th argument</p></li><li class="listitem"><p>is_ flag_(some_flag[, some state machine]) will call
+ is_flag_active on the current state machine or on the one passed
+ as 2nd argument</p></li><li class="listitem"><p>Predicate_<some predicate>: Used in STL algorithms. Wraps
+ unary/binary functions to make them eUML-compatible so that they
+ can be used in STL algorithms</p></li></ul></div><p>This can be quite fun. For example, </p><pre class="programlisting">/( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(),/*if clause*/
+ show_playing_song, /*then clause*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else clause*/
+ )
+ )</pre><p>means: if (fsm.SongIndex > 0, call show_playing_song else
+ {fsm.SongIndex=1; process EndPlay on fsm;}</p><p>A few examples are using these features:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>the iPod example introduced at the BoostCon09 <a class="link" href="examples/iPodEuml.cpp" target="_top">has been rewritten</a>
+ with eUML (weak compilers please move on...)</p></li><li class="listitem"><p>the iPodSearch example also introduced at the BoostCon09 <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">has been
+ rewritten</a> with eUML. In this example, you will also
+ find some examples of STL functor usage.</p></li><li class="listitem"><p><a class="link" href="examples/SimpleTimer.cpp" target="_top">A simpler
+ timer</a> example is a good starting point. </p></li></ul></div><p>There is unfortunately a small catch. Defining a functor using
+ MSM_EUML_METHOD or MSM_EUML_FUNCTION will create a correct functor. Your own
+ eUML functors written as described at the beginning of this section will
+ also work well, <span class="underline">except</span>, for the
+ moment, with the while_, if_then_, if_then_else_ functions.</p></div><div class="sect2" title="Phoenix-like STL support"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3408"></a>Phoenix-like STL support</h3></div></div></div><p>eUML supports most C++ operators (except address-of). For example it is
+ possible to write event_(some_attribute)++ or [source_(some_bool) &&
+ fsm_(some_other_bool)]. But a programmer needs more than operators in his
+ daily programming. The STL is clearly a must have. Therefore, eUML comes in
+ with a lot of functors to further reduce the need for your own functors for
+ the transition table. For almost every algorithm or container method of the
+ STL, a corresponding eUML function is defined. Like Boost.Phoenix, “.” And
+ “->” of call on objects are replaced by a functional programming paradigm,
+ for example:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>begin_(container), end_(container): return iterators of a
+ container.</p></li><li class="listitem"><p>empty_(container): returns container.empty()</p></li><li class="listitem"><p>clear_(container): container.clear()</p></li><li class="listitem"><p>transform_ : std::transform</p></li></ul></div><p>In a nutshell, almost every STL method or algorithm is matched by a
+ corresponding functor, which can then be used in the transition table or
+ state actions. The <a class="link" href="pt02.html#Reference-begin">reference</a>
+ lists all eUML functions and the underlying functor (so that this
+ possibility is not reserved to eUML but also to the functor-based
+ front-end). The file structure of this Phoenix-like library matches the one
+ of Boost.Phoenix. All functors for STL algorithms are to be found in:</p><pre class="programlisting">#include <msm/front/euml/algorithm.hpp></pre><p>The algorithms are also divided into sub-headers, matching the phoenix
+ structure for simplicity:</p><pre class="programlisting">#include < msm/front/euml/iteration.hpp>
+#include < msm/front/euml/transformation.hpp>
+#include < msm/front/euml/querying.hpp> </pre><p>Container methods can be found in:</p><pre class="programlisting">#include < msm/front/euml/container.hpp></pre><p>Or one can simply include the whole STL support (you will also need to
+ include euml.hpp):</p><pre class="programlisting">#include < msm/front/euml/stl.hpp></pre><p>A few examples (to be found in <a class="link" href="examples/iPodSearchEuml.cpp" target="_top">this tutorial</a>):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">push_back_(fsm_(m_tgt_container),event_(m_song))</code>:
+ the state machine has an attribute m_tgt_container of type
+ std::vector<OneSong> and the event has an attribute m_song of
+ type OneSong. The line therefore pushes m_song at the end of
+ m_tgt_container</p></li><li class="listitem"><p><code class="code">if_then_( state_(m_src_it) !=
+ end_(fsm_(m_src_container)),
+ process2_(OneSong(),*(state_(m_src_it)++)) )</code>: the
+ current state has an attribute m_src_it (an iterator). If this
+ iterator != fsm.m_src_container.end(), process OneSong on fsm,
+ copy-constructed from state.m_src_it which we
+ post-increment</p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch03s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Functor front-end </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Back-end</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch03s05.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch03s05.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,152 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Back-end</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch03.html" title="Chapter 3. Tutorial"><link rel="prev" href="ch03s04.html" title="eUML (experimental)"><link rel="next" href="ch04.html" title="Chapter 4. Performance / Compilers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Back-end</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s04.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Tutorial</th><td width="20%" align="right"> <a accesskey="n" href="ch04.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Back-end"><div class="titlepage"><div><div><h2 class="title" style="clea
r: both"><a name="d0e3461"></a>Back-end</h2></div></div></div><p>There is, at the moment, one back-end. This back-end contains the library
+ engine and defines the performance and functionality trade-offs. The currently
+ available back-end implements most of the functionality defined by the UML 2.0
+ standard at very high runtime speed, in exchange for longer compile-time. The
+ runtime speed is due to a constant-time double-dispatch and self-adapting
+ capabilities allowing the framework to adapt itself to the features used by a
+ given concrete state machine. All unneeded features either disable themselves or
+ can be manually disabled. See section 5.1 for a complete description of the
+ run-to-completion algorithm.</p><div class="sect2" title="Creation"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3466"></a>Creation </h3></div></div></div><p>MSM being divided between front and back-end, one needs to first define a
+ front-end. Then, to create a real state machine, the back-end must be
+ declared:
+ </p><pre class="programlisting">typedef msm::back::state_machine<my_front_end> my_fsm;</pre><p>We now have a fully functional state machine type. The next sections will
+ describe what can be done with it.</p></div><div class="sect2" title="Starting a state machine"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3475"></a><span class="command"><strong><a name="backend-start"></a></strong></span>Starting a state machine</h3></div></div></div><p>The <code class="code">start</code> method starts the state machine, meaning it will
+ activate the initial state, which means in turn that the initial state's
+ entry behavior will be called. We need the start method because you do not
+ always want the entry behavior of the initial state to be called immediately
+ but only when your state machine is ready to process events. A good example
+ of this is when you use a state machine to write an algorithm and each loop
+ back to the initial state is an algorithm call. Each call to start will make
+ the algorithm run once. The <a class="link" href="examples/iPodSearch.cpp" target="_top">iPodSearch</a> example uses this possibility.</p></div><div class="sect2" title="Event dispatching"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3487"></a>Event dispatching</h3></div></div></div><p>The main reason to exist for a state machine is to dispatch events. For
+ MSM, events are objects of a given event type. The object itself can contain
+ data, but the event type is what decides of the transition to be taken. For
+ MSM, if some_event is a given type (a simple struct for example) and e1 and
+ e2 concrete instances of some_event, e1 and e2 are equivalent, from a
+ transition perspective. Of course, e1 and e2 can have different values and
+ you can use them inside actions. Events are dispatched as const reference,
+ so actions cannot modify events for obvious side-effect reasons. To dispatch
+ an event of type some_event, you can simply create one on the fly or
+ instantiate if before processing: </p><pre class="programlisting">my_fsm fsm; fsm.process_event(some_event());
+some_event e1; fsm.process_event(e1)</pre><p>Creating an event on the fly will be optimized by the compiler so the
+ performance will not degrade.</p></div><div class="sect2" title="Active state(s)"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3496"></a>Active state(s)</h3></div></div></div><p>The backend also offers a way to know which state is active, though you
+ will normally only need this for debugging purposes. If what you need simply
+ is doing something with the active state, <span class="command"><strong><a class="command" href="ch02s02.html#UML-internal-transition">internal transitions</a></strong></span> or
+ <span class="command"><strong><a class="command" href="ch03s05.html#backend-visitor">visitors</a></strong></span> are a better
+ alternative. If you need to know what state is active, const int*
+ current_state() will return an array of state ids. Please refer to the
+ <span class="command"><strong><a class="command" href="ch06s03.html#internals-state-id">internals section</a></strong></span> to
+ know how state ids are generated.</p></div><div class="sect2" title="Base state type"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3510"></a><span class="command"><strong><a name="backend-base-state"></a></strong></span>Base state type </h3></div></div></div><p>Sometimes, one needs to customize states to avoid repetition and provide a
+ common functionality, for example in the form of a virtual method. You might
+ also want to make your states polymorphic so that you can call typeid on
+ them for logging or debugging. It is also useful if you need a visitor, like
+ the next section will show. You will notice that all front-ends offer the
+ possibility of adding a base type. Note that all states and state machines
+ must have the same base state, so this could reduce reuse. For example,
+ using the basic front end, you need to:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Add the non-default base state in your msm::front::state<>
+ definition, as first template argument (except for
+ interrupt_states for which it is the second argument, the first
+ one being the event ending the interrupt), for example,
+ my_base_state being your new base state for all states in a
+ given state machine:
+ </p><pre class="programlisting">struct Empty : public msm::front::state<my_base_state></pre><p>
+ Now, my_base_state is your new base state. If it has a virtual
+ function, your states become polymorphic. MSM also provides a
+ default polymorphic base type,
+ <code class="code">msm::front::polymorphic_state</code>
+ </p></li><li class="listitem"><p>Add the user-defined base state in the state machine frontend
+ definition, as a second template argument, for example:
+ </p><pre class="programlisting">struct player_ : public msm::front::state_machine<player_,my_base_state> </pre></li></ul></div><p>You can also ask for a state with a given id (which you might have gotten
+ from current_state()) using <code class="code">const base_state* get_state_by_id(int id)
+ const</code> where base_state is the one you just defined. You can now
+ do something polymorphically.</p></div><div class="sect2" title="Visitor"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3536"></a><span class="command"><strong><a name="backend-visitor"></a></strong></span>Visitor</h3></div></div></div><p>In some cases, having a pointer-to-base of the currently active states is
+ not enough. You might want to call non-virtually a method of the currently
+ active states. It will not be said that MSM forces the virtual keyword down
+ your throat!</p><p>To achieve this goal, MSM provides its own variation of a visitor pattern
+ using the previously described user-defined state technique. If you add to
+ your user-defined base state an <code class="code">accept_sig</code> typedef giving the
+ return value (unused for the moment) and parameters and provide an accept
+ method with this signature, calling visit_current_states will cause accept
+ to be called on the currently active states. Typically, you will also want
+ to provide an empty default accept in your base state in order in order not
+ to force all your states to implement accept. For example your base state
+ could be:</p><pre class="programlisting">struct my_visitable_state
+{
+ // signature of the accept function
+ typedef args<void> accept_sig;
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept() const {}
+};</pre><p>This makes your states polymorphic and visitable. In this case, accept is
+ made const and takes no argument. It could also be:</p><pre class="programlisting">struct SomeVisitor {…};
+struct my_visitable_state
+{
+ // signature of the accept function
+ typedef args<void,SomeVisitor&> accept_sig;
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept(SomeVisitor&) const {}
+};</pre><p>And now, <code class="code">accept</code> will take one argument (it could also be
+ non-const). By default, <code class="code">accept</code> takes up to 2 arguments. To get
+ more, set #define BOOST_MSM_VISITOR_ARG_SIZE to another value before
+ including state_machine.hpp. For example:</p><pre class="programlisting">#define BOOST_MSM_VISITOR_ARG_SIZE 3
+#include <boost/msm/back/state_machine.hpp></pre><p>Note that accept will be called on ALL active states <span class="underline">and also automatically on sub-states of a
+ submachine</span>.</p><p><span class="underline">Important warning</span>: The method
+ visit_current_states takes its parameter by value, so if the signature of
+ the accept function is to contain a parameter passed by reference, pass this
+ parameter with a boost:ref/cref to avoid undesired copies or slicing. So,
+ for example, in the above case, call:</p><pre class="programlisting">SomeVisitor vis; sm.visit_current_states(boost::ref(vis));</pre><p>This <a class="link" href="examples/SM-2Arg.cpp" target="_top">example</a> uses a
+ visiting function with 2 arguments.</p></div><div class="sect2" title="Flags"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3579"></a>Flags</h3></div></div></div><p>Flags is a MSM-only concept, supported by all front-ends, which base
+ themselves on the functions: </p><pre class="programlisting">template <class Flag> bool is_flag_active()
+template <class Flag,class BinaryOp> bool is_flag_active()</pre><p>These functions return true if the currently active state(s) support the
+ Flag property. The first variant ORs the result if there are several
+ orthogonal regions, the second one expects OR or AND, for example:</p><pre class="programlisting">my_fsm.is_flag_active<MyFlag>()
+my_fsm.is_flag_active<MyFlag,my_fsm_type::Flag_OR>()</pre><p>Please refer to the front-ends sections for usage examples.</p></div><div class="sect2" title="Getting a state"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3592"></a>Getting a state</h3></div></div></div><p>It is sometimes necessary to have the client code get access to the
+ states' data. After all, the states are created once for good and hang
+ around as long as the state machine does so why not use it? You simply just
+ need sometimes to get information about any state, even inactive ones. An
+ example is if you want to write a coverage tool and know how many times a
+ state was visited. To get a state, use the get_state method giving the state
+ name, for example: </p><pre class="programlisting">player::Stopped* tempstate = p.get_state<player::Stopped*>();</pre><p> or </p><pre class="programlisting">player::Stopped& tempstate2 = p.get_state<player::Stopped&>();</pre><p>depending on your personal taste. </p></div><div class="sect2" title="State machine constructor with arguments"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3605"></a> State machine constructor with arguments </h3></div></div></div><p>You might want to define a state machine with a non-default constructor.
+ For example, you might want to write: </p><pre class="programlisting">struct player_ : public msm::front::state_machine_def<player_>
+{
+ player_(int some_value){…}
+}; </pre><p>This is possible, using the back-end as forwarding object: </p><pre class="programlisting">typedef msm::back::state_machine<player_ > player; player p(3);</pre><p>The back-end will call the corresponding front-end constructor upon
+ creation.</p><p>You can pass arguments up to the value of the
+ BOOST_MSM_CONSTRUCTOR_ARG_SIZE macro (currently 5) arguments. Change this
+ value before including any header if you need to overwrite the default.
+ </p></div><div class="sect2" title="Trading run-time speed for better compile-time / multi-TU compilation"><div class="titlepage"><div><div><h3 class="title"><a name="d0e3620"></a><span class="command"><strong><a name="backend-tradeof-rt-ct"></a></strong></span>Trading run-time speed for
+ better compile-time / multi-TU compilation</h3></div></div></div><p>MSM is optimized for run-time speed at the cost of longer compile-time.
+ This can become a problem with older compilers and big state machines,
+ especially if you don't really care about run-time speed that much and would
+ be satisfied by a performance roughly the same as most state machine
+ libraries. MSM offers a back-end policy to help there. But before you try
+ it, if you are using a VC compiler, deactivate the /Gm compiler option
+ (default for debug builds). This option can cause builds to be 3 times
+ longer... If the compile-time still is a problem, read further. MSM offers a
+ policy which will speed up compiling in two main cases:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>many transition conflicts</p></li><li class="listitem"><p>submachines</p></li></ul></div><p>The back-end <code class="code">msm::back::state_machine</code> has a third template
+ argument (first is the front-end, second is the history policy) defaulting
+ to <code class="code">favor_runtime_speed</code>. To switch to
+ <code class="code">favor_compile_time</code>, which is declared in
+ <code class="code"><msm/back/favor_compile_time.hpp></code>, you need to:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>switch the policy to <code class="code">favor_compile_time</code> for the
+ main state machine (and possibly submachines)</p></li><li class="listitem"><p>move the submachine declarations into their own header which
+ includes
+ <code class="code"><msm/back/favor_compile_time.hpp></code></p></li><li class="listitem"><p>add for each submachine a cpp file including your header and
+ calling a macro, which generates helper code, for
+ example:</p><pre class="programlisting">#include "mysubmachine.hpp"
+BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(mysubmachine)</pre></li><li class="listitem"><p>configure your compiler for multi-core compilation</p></li></ul></div><p>You will now compile your state machine on as many cores as you have
+ submachines, which will greatly speed up the compilation if you factor your
+ state machine into smaller submachines.</p><p>Independently, transition conflicts resolution will also be much
+ faster.</p><p>This policy uses boost.any behind the hood, which means that we will lose
+ one feature which MSM offers with the default policy, <a class="link" href="ch03s02.html#event-hierarchy">event hierarchy</a>. The following
+ example takes our iPod example and speeds up compile-time by using this
+ technique. We have:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><a class="link" href="examples/iPod_distributed/iPod.cpp" target="_top">our main
+ state machine and main function</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/PlayingMode.hpp" target="_top">PlayingMode moved to a separate header</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/PlayingMode.cpp" target="_top">a
+ cpp for PlayingMode</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/MenuMode.hpp" target="_top">MenuMode moved to a separate header</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/MenuMode.cpp" target="_top">a
+ cpp for MenuMode</a></p></li><li class="listitem"><p><a class="link" href="examples/iPod_distributed/Events.hpp" target="_top">events
+ move to a separate header as all machines use
+ it</a></p></li></ul></div><p>
+ </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch03.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">eUML (experimental) </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 4. Performance / Compilers</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch04.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch04.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,13 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 4. Performance / Compilers</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="ch03s05.html" title="Back-end"><link rel="next" href="ch04s02.html" title="Executable size"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 4. Performance / Compilers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch03s05.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="ch04s02.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 4. Performan
ce / Compilers"><div class="titlepage"><div><div><h2 class="title"><a name="d0e3702"></a>Chapter 4. Performance / Compilers</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1">Speed</span></dt><dt><span class="sect1">Executable size</span></dt><dt><span class="sect1">Supported compilers</span></dt><dt><span class="sect1"> Limitations </span></dt><dt><span class="sect1"> Compilers corner </span></dt></dl></div><p>Tests were made on different PCs running Windows XP and Vista and compiled with
+ VC9 SP1 or Ubuntu and compiled with g++ 4.2 and 4.3. For these tests, the same
+ player state machine was written using Boost.Statechart, as a <a class="link" href="examples/SC Simple.cpp" target="_top">state machine with only simple states</a>
+ and as a <a class="link" href="examples/SC Composite.cpp" target="_top">state machine with a composite
+ state</a>. The same simple and composite state machines are implemented with
+ MSM with a standard frontend <a class="link" href="examples/MsmSimple.cpp" target="_top">(simple)</a><a class="link" href="examples/MsmComposite.cpp" target="_top">(composite)</a>,
+ the simple one also with <a class="link" href="examples/MsmSimpleFunctors.cpp" target="_top">functors</a> and with <a class="link" href="examples/EumlSimple.cpp" target="_top">eUML</a>. As these simple machines need no terminate/interrupt states, no
+ message queue and have no-throw guarantee on their actions, the MSM state machines
+ are defined with minimum functionality. Test machine is a Q6600 2.4GHz, Vista
+ 64.</p><div class="sect1" title="Speed"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3724"></a>Speed</h2></div></div></div><p>VC9:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>The simple test completes 90 times faster with MSM than with
+ Boost.Statechart</p></li><li class="listitem"><p>The composite test completes 25 times faster with MSM</p></li></ul></div><p>gcc 4.2.3 (Ubuntu 8.04 in VMWare, same PC):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>The simple test completes 46 times faster with MSM</p></li><li class="listitem"><p>The composite test completes 19 times faster with Msm</p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch03s05.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch04s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Back-end </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Executable size</td></tr></table></div>
</body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch04s02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch04s02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,14 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Executable size</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch04.html" title="Chapter 4. Performance / Compilers"><link rel="prev" href="ch04.html" title="Chapter 4. Performance / Compilers"><link rel="next" href="ch04s03.html" title="Supported compilers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Executable size</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Performance / Compilers</th><td width="20%" align="right"> <a accesskey="n" href="ch04s03.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Executable size"><div clas
s="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3745"></a>Executable size</h2></div></div></div><p>There are some worries that MSM generates huge code. Is it true? The 2
+ compilers I tested disagree with this claim. On VC9, the test state machines
+ used in the performance section produce executables of 14kB (for simple and
+ eUML) and 21kB (for the composite). This includes the test code and iostreams.
+ By comparison, an empty executable with iostreams generated by VC9 has a size of
+ 7kB. Boost.Statechart generates executables of 43kB and 54kB. As a bonus, eUML
+ comes for “free” in terms of executable size. You even get a speed gain. With
+ g++ 4.3, it strongly depends on the compiler options (much more than VC). A good
+ size state machine with –O3 can generate an executable of 600kB, and with eUML
+ you can get to 1.5MB. Trying with –Os –s I come down to 18kB and 30kB for the
+ test state machines, while eUML will go down to 1MB (which is still big), so in
+ this case eUML does not come for free.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch04.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch04s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 4. Performance / Compilers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Supported compilers</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch04s03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch04s03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,9 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Supported compilers</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch04.html" title="Chapter 4. Performance / Compilers"><link rel="prev" href="ch04s02.html" title="Executable size"><link rel="next" href="ch04s04.html" title="Limitations"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Supported compilers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s02.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Performance / Compilers</th><td width="20%" align="right"> <a accesskey="n" href="ch04s04.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Supported compilers"><div class="titlepage"><div><
div><h2 class="title" style="clear: both"><a name="d0e3750"></a>Supported compilers</h2></div></div></div><p> MSM was successfully tested with: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>VC8 (please read further), VC9SP1, VC10 Beta 1 and 2</p></li><li class="listitem"><p>g++ 4.1 and higher</p></li><li class="listitem"><p>Green Hills Software MULTI for ARM v5.0.5 patch 4416 (Simple and
+ Composite tutorials)</p></li></ul></div><p> eUML will only work with: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>VC8 (partly). You cannot, however use any overloaded function
+ (like splice) and compile times and RAM consumption explode</p></li><li class="listitem"><p>VC9SP1, VC10 Beta1-2</p></li><li class="listitem"><p>g++ 4.3 and higher (previous versions lack native typeof
+ support)</p></li></ul></div><p>VC8 and to some lesser extent VC9 suffer from a bug. Enabling the option
+ "Enable Minimal Rebuild" (/Gm) will cause much higher compile-time (up to three
+ times with VC8!). This option being activated per default in Debug mode, this
+ can be a big problem.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch04s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch04.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch04s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Executable size </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Limitations </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch04s04.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch04s04.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,15 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Limitations</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch04.html" title="Chapter 4. Performance / Compilers"><link rel="prev" href="ch04s03.html" title="Supported compilers"><link rel="next" href="ch04s05.html" title="Compilers corner"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center"> Limitations </th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s03.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Performance / Compilers</th><td width="20%" align="right"> <a accesskey="n" href="ch04s05.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Limitations"><div class="titlepage"><div><div><h2 class
="title" style="clear: both"><a name="d0e3779"></a> Limitations </h2></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Compilation times of state machines with > 80 transitions that are
+ going to make you storm the CFO's office and make sure you get a
+ shiny octocore with 12GB RAM by next week, unless he's interested in
+ paying you watch the compiler agonize for hours... (Make sure you
+ ask for dual 24" as well, it doesn't hurt).</p></li><li class="listitem"><p>eUML allows very long constructs but will also quickly increase
+ your compile time on some compilers (VC9, VC10 Beta1) with buggy
+ decltype support (I suspect some at least quadratic algorithms
+ there). Even g++ 4.4 shows some regression compared to 4.3 and will
+ crash if the constructs become too big.</p></li><li class="listitem"><p>Need to overwrite the mpl::vector/list default-size-limit of 20
+ and fusion default vector size of 10 if more than 10 states found in
+ a state machine</p></li></ul></div><p>
+ </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch04s03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch04.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch04s05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Supported compilers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Compilers corner </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch04s05.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch04s05.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,35 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Compilers corner</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch04.html" title="Chapter 4. Performance / Compilers"><link rel="prev" href="ch04s04.html" title="Limitations"><link rel="next" href="ch05.html" title="Chapter 5. Questions & Answers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center"> Compilers corner </th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s04.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Performance / Compilers</th><td width="20%" align="right"> <a accesskey="n" href="ch05.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Compilers corner"><div class="t
itlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3795"></a> Compilers corner </h2></div></div></div><p>Compilers are sometimes full of surprises and such strange errors happened in
+ the course of the development that I wanted to list the most fun for readers’
+ entertainment.</p><p><span class="underline">VC8</span>: </p><pre class="programlisting">template <class StateType>
+typename ::boost::enable_if<
+ typename ::boost::mpl::and_<
+ typename ::boost::mpl::not_<
+ typename has_exit_pseudo_states<StateType>::type
+ >::type,
+ typename ::boost::mpl::not_<
+ typename is_pseudo_exit<StateType>::type
+ >::type
+ >::type,
+ BaseState*>::type </pre><p>I get the following error:</p><p>error C2770: invalid explicit template argument(s) for '`global
+ namespace'::boost::enable_if<...>::...' </p><p>If I now remove the first “::” in ::boost::mpl , the compiler shuts up. So in
+ this case, it is not possible to follow Boost’s guidelines.</p><p><span class="underline">VC9</span>:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>This one is my all times’ favorite. Do you know why the exit
+ pseudo states are referenced in the transition table with a
+ “submachine::exit_pt” ? Because “exit” will crash the compiler.
+ “Exit” is not possible either because it will crash the compiler on
+ one machine, but not on another (the compiler was installed from the
+ same disk).</p></li><li class="listitem"><p>Sometimes, removing a policy crashes the compiler, so some
+ versions are defining a dummy policy called WorkaroundVC9.</p></li><li class="listitem"><p>Typeof: While g++ and VC9 compile “standard” state machines in
+ comparable times, Typeof (while in both ways natively supported)
+ seems to behave in a quadratic complexity with VC9 and VC10.</p></li><li class="listitem"><p>eUML: in case of a compiler crash, changing the order of state
+ definitions (first states without entry or exit) sometimes solves
+ the problem.</p></li></ul></div><p><span class="underline">g++ 4.x</span>: Boring compiler, almost all is
+ working almost as expected. Being not a language lawyer I am unsure about the
+ following “Typeof problem”. VC9 and g++ disagree on the question if you can
+ derive from the BOOST_TYPEOF generated type without first defining a typedef. I
+ will be thankful for an answer on this. I only found two ways to break the compiler:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Add more eUML constructs until something explodes (especially with
+ g++-4.4) </p></li><li class="listitem"><p>The build_terminate function uses 2 mpl::push_back instead of
+ mpl::insert_range because g++ would not accept insert_range.</p></li></ul></div><p>You can test your compiler’s decltype implementation with the <a class="link" href="examples/CompilerStressTestEuml.cpp" target="_top">following stress
+ test</a> and reactivate the commented-out code until the compiler
+ crashes.</p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch04s04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch04.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch05.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> Limitations </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 5. Questions & Answers</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch05.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch05.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,32 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 5. Questions & Answers</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="ch04s05.html" title="Compilers corner"><link rel="next" href="ch06.html" title="Chapter 6. Internals"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 5. Questions & Answers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch04s05.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="ch06.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 5.&
nbsp;Questions & Answers"><div class="titlepage"><div><div><h2 class="title"><a name="d0e3845"></a>Chapter 5. Questions & Answers</h2></div></div></div><p><span class="underline">Question</span>: on_entry gets as argument, the
+ sent event. What event do I get when the state becomes default-activated (because it
+ is an initial state)?</p><p>
+ <span class="underline">Answer</span>: To allow you to know that the state
+ was default-activated, MSM generates a boost::msm::InitEvent default event. </p><p><span class="underline">Question</span>: Why do I see no call to
+ no_transition in my submachine? </p><p><span class="underline">Answer</span>: Because of the priority rule defined
+ by UML. It says that in case of transition conflict, the most inner state has a
+ higher priority. So after asking the inner state, the containing composite has to be
+ also asked to handle the transition and could find a possible transition.</p><p><span class="underline">Question</span>: Why do I get a compile error
+ saying the compiler cannot convert to a function ...Fsm::*(some_event)? </p><p><span class="underline">Answer</span>: You probably defined a transition
+ triggered by the event some_event, but used a guard/action method taking another
+ event. </p><p><span class="underline">Question</span>: Why do I get a compile error
+ saying something like “too few” or “too many” template arguments? </p><p><span class="underline">Answer</span>: You probably defined a transition in
+ form of a a_row or g_row where you wanted just a _row or the other way around. With
+ Row, it could mean that you forgot a "none". </p><p><span class="underline">Question</span>: Why do I get a very long compile
+ error when I define more than 20 rows in the transition table? </p><p><span class="underline">Answer</span>: MSM uses Boost.MPL under the hood
+ and this is the default maximum size. Please define the following 3 macros before
+ including any MSM headers: </p><pre class="programlisting">#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 // or whatever you need
+#define BOOST_MPL_LIMIT_MAP_SIZE 30 // or whatever you need </pre><p><span class="underline">Question</span>: Why do I get this error: ”error
+ C2977: 'boost::mpl::vector' : too many template arguments”? </p><p><span class="underline">Answer</span>: The first possibility is that you
+ defined a transition table as, say, vector17 and have 18 entries. The second is that
+ you have 17 entries and have a composite state. Under the hood, MSM adds a row for
+ every event in the composite transition table. The third one is that you used a
+ mpl::vector without the number of entries but are close to the MPL default of 50 and
+ have a composite, thus pushing you above 50. Then you need mpl/vector60/70….hpp and
+ a mpl/map60/70….hpp </p><p><span class="underline">Question</span>: Why do I get a very long compile
+ error when I define more than 10 states in a state machine? </p><p><span class="underline">Answer</span>: MSM uses Boost.Fusion under the hood
+ and this is the default maximum size. Please define the following macro before
+ including any MSM headers: </p><pre class="programlisting">#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need </pre></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch04s05.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch06.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> Compilers corner </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 6. Internals</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch06.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch06.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,61 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 6. Internals</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="ch05.html" title="Chapter 5. Questions & Answers"><link rel="next" href="ch06s02.html" title="Frontend / Backend interface"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 6. Internals</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch05.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="ch06s02.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 6.&nb
sp;Internals"><div class="titlepage"><div><div><h2 class="title"><a name="d0e3909"></a>Chapter 6. Internals</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1">Backend: Run To Completion</span></dt><dt><span class="sect1"><a href="ch06s02.html">Frontend / Backend
+ interface</a></span></dt><dt><span class="sect1"> Generated state ids </span></dt><dt><span class="sect1">Metaprogramming tools</span></dt></dl></div><p>This chapter describes the internal machinery of the back-end, which can be useful
+ for UML experts but can be safely ignored for most users. For implementers, the
+ interface between front- and back- end is also described in detail.</p><div class="sect1" title="Backend: Run To Completion"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3914"></a><span class="command"><strong><a name="run-to-completion"></a></strong></span>Backend: Run To Completion</h2></div></div></div><p>The back-end implements the following run-to completion algorithm:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Check if one region of the concrete state machine is in a
+ terminate or interrupt state. If yes, event processing is disabled
+ while the condition lasts (forever for a terminate pseudo-state,
+ while active for an interrupt pseudo-state).</p></li><li class="listitem"><p>If the message queue feature is enabled and if the state machine
+ is already processing an event, push the currently processed event
+ into the queue and end processing. Otherwise, remember that the
+ state machine is now processing an event and continue.</p></li><li class="listitem"><p>If the state machine detected that no deferred event is used, skip
+ this step. Otherwise, mark the first deferred event from the
+ deferred queue as active.</p></li><li class="listitem"><p>Now start the core of event dispatching. If exception handling is
+ activated, this will happen inside a try/catch block and the
+ front-end <code class="code">exception_caught</code> is called if an exception
+ occurs. </p></li><li class="listitem"><p>The event is now dispatched in turn to every region, in the order
+ defined by the initial state front-end definition. This will, for
+ every region, call the corresponding front-end transition definition
+ (the "row" or "Row" of the transition table).</p></li><li class="listitem"><p>Without transition conflict, if for a given region a transition is
+ possible, the guard condition is checked. If it returns
+ <code class="code">true</code>, the transition processing continues and the
+ current state's exit action is called, followed by the transition
+ action behavior and the new active state's entry behavior.</p></li><li class="listitem"><p>With transition conflicts (several possible transitions,
+ disambiguated by mutually exclusive guard conditions), the guard
+ conditions are tried in reverse order of their transition definition
+ in the transition table. The first one returning <code class="code">true</code>
+ selects its transition. Note that this is not defined by the UML
+ standard, which simply specifies that if the guard conditions are
+ not mutually exclusive, the state machine is ill-formed and the
+ behaviour undefined. Relying on this implementation-specific
+ behaviour will make it harder for the developer to support another
+ state machine framework.</p></li><li class="listitem"><p>If at least one region processes the event, this event is seen as
+ having been accepted. If not, the library calls
+ <code class="code">no_transition</code> on the state machine for every
+ contained region.</p></li><li class="listitem"><p>If the currently active state is a submachine, the behaviour is
+ slightly different. The UML standard specifies that internal
+ transitions have to be tried first, so the event is first dispatched
+ to the submachine. Only if the submachine does not accept the event
+ are other (non internal) transitions tried.</p></li><li class="listitem"><p>This back-end supports simple states' and submachines' internal
+ transitions. These are provided in the state's
+ <code class="code">internal_transition_table</code> type. Transitions defined
+ in this table are added at the end of the main state machine's
+ transition table, but with a lesser priority than the submachine's
+ transitions (defined in <code class="code">transition_table</code>). This means,
+ for simple states, that these transitions have higher priority than
+ non-internal transitions, conform to the UML standard which gives
+ higher priority to deeper-level transitions. For submachines, this
+ is a non-standard addition which can help make event processing
+ faster by giving a chance to bypass subregion processing. With
+ standard UML, one would need to add a subregion only to process
+ these internal transitions, which would be slower.</p></li><li class="listitem"><p>After the dispatching itself, the deferred event marked in step 3
+ (if any) now gets a chance of processing.</p></li><li class="listitem"><p>Then, events queued in the message queue also get a dispatching
+ chance</p></li><li class="listitem"><p>Finally, completion / anonymous transitions, if to be found in the
+ transition table, also get their dispatching chance.</p></li></ul></div><p>This algorithm illustrates how the back-end configures itself at compile-time
+ as much as possible. Every feature not found in a given state machine definition
+ is deactivated and has therefore no runtime cost. Completion events, deferred
+ events, terminate states, dispatching to several regions, internal transitions
+ are all deactivated if not used. User configuration is only for exception
+ handling and message queue necessary.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch05.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch06s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 5. Questions & Answers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Frontend / Backend
+ interface</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch06s02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch06s02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,60 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Frontend / Backend interface</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch06.html" title="Chapter 6. Internals"><link rel="prev" href="ch06.html" title="Chapter 6. Internals"><link rel="next" href="ch06s03.html" title="Generated state ids"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Frontend / Backend
+ interface</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch06.html">Prev</a> </td><th width="60%" align="center">Chapter 6. Internals</th><td width="20%" align="right"> <a accesskey="n" href="ch06s03.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Frontend / Backend interface"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e3980"></a><span class="command"><strong><a name="internals-front-back-interface"></a></strong></span>Frontend / Backend
+ interface</h2></div></div></div><p>The design of MSM tries to make front-ends and back-ends (later) to be as
+ interchangeable as possible. Of course, no back-end will ever implement every
+ feature defined by any possible front-end and inversely, but the goal is to make
+ it as easy as possible to extend the current state of the library.</p><p>To achieve this, MSM divides the functionality between both sides: the
+ front-end is a sort of user interface and is descriptive, the back-end
+ implements the state machine engine.</p><p>MSM being based on a transition table, a concrete state machine (or a given
+ front-end) must provide a transition_table. This transition table must be made
+ of rows. And each row must tell what kind of transition it is and implement the
+ calls to the actions and guards. A state machine must also define its regions
+ (marked by initial states) And that is about the only constraints for
+ front-ends. How the rows are described is implementer's choice. </p><p>Every row must provide:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>A <code class="code">Source</code> typedef indicating, well, the type of the source
+ state.</p></li><li class="listitem"><p>A <code class="code">Target</code> typedef indicating, well, the type of the target
+ state.</p></li><li class="listitem"><p>A <code class="code">Evt</code> typedef indicating the type of the event triggering
+ the transition.</p></li><li class="listitem"><p>A <code class="code">row_type_tag</code> typedef indicating the type of the
+ transition.</p></li><li class="listitem"><p>Rows having a type requiring transition actions must provide a static
+ function <code class="code">action_call</code> with the following signature: <code class="code">
+ template <class Fsm,class SourceState,class TargetState,class
+ AllStates> </code></p><p><code class="code">static void action_call (Fsm& fsm, Event const& evt,
+ SourceState&, TargetState&, AllStates&) </code></p><p>The function gets as parameters the (back-end) state machine, the
+ event, source and target states and a container (in the current
+ back-end, a fusion::set) of all the states defined in the state machine.
+ For example, as the back-end has the front-end as basic class,
+ <code class="code">action_call</code> is simply defined as
+ <code class="code">(fsm.*action)(evt)</code>.</p></li><li class="listitem"><p>Rows having a type requiring a guard must provide a static function
+ <code class="code">guard_call</code> with the following signature:<code class="code"> </code></p><p><code class="code">template <class Fsm,class SourceState,class TargetState,class
+ AllStates></code></p><p><code class="code">static bool guard_call (Fsm&, Event const&,
+ SourceState&, TargetState&, AllStates&)</code></p></li><li class="listitem"><p>The possible transition (row) types are:</p><div class="itemizedlist"><ul class="itemizedlist" type="circle"><li class="listitem"><p>a_row_tag: a transition with actions and no guard</p></li><li class="listitem"><p>g_row_type: a transition with a guard and no
+ actions</p></li><li class="listitem"><p>_row_tag: a transition without actions or guard</p></li><li class="listitem"><p>row_tag: a transition with guard and actions</p></li><li class="listitem"><p>a_irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) with actions</p></li><li class="listitem"><p>g_irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) with guard</p></li><li class="listitem"><p>irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) with actions and
+ guards</p></li><li class="listitem"><p>_irow_tag: an internal transition (defined inside the
+ <code class="code">transition_table</code>) without action or guard.
+ Due to higher priority for internal transitions, this is
+ equivalent to a "ignore event"</p></li><li class="listitem"><p>sm_a_i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) with
+ actions</p></li><li class="listitem"><p>sm_g_i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) with
+ guard</p></li><li class="listitem"><p>sm_i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) with actions and
+ guards</p></li><li class="listitem"><p>sm__i_row_tag: an internal transition (defined inside the
+ <code class="code">internal_transition_table</code>) without action
+ or guard. Due to higher priority for internal transitions,
+ this is quivalent to a "ignore event"</p></li></ul></div></li></ul></div><p>Furthermore, a front-end must provide the definition of states and state
+ machines. State machine definitions must provide (the implementer is free to
+ provide it or let it be done by every concrete state machine. Different MSM
+ front-ends took one or the other approach):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">initial_state</code>: This typedef can be a single state or
+ a mpl container and provides the initial states defining one or
+ several orthogonal regions.</p></li><li class="listitem"><p><code class="code">transition_table</code>: This typedef is a MPL sequence of
+ transition rows.</p></li><li class="listitem"><p><code class="code">configuration</code>: this typedef is a MPL sequence of
+ known types triggering special behavior in the back-end, for example
+ if a concrete fsm requires a message queue or exception
+ catching.</p></li></ul></div><p>States and state machines must both provide a (possibly empty) definition of:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">flag_list</code>: the flags being active when this state or
+ state machine become the current state of the fsm.</p></li><li class="listitem"><p><code class="code">deferred_events</code>: events being automatically deferred
+ when the state is the current state of the fsm.</p></li><li class="listitem"><p><code class="code">internal_transition_table</code>: the internal transitions
+ of this state.</p></li><li class="listitem"><p><code class="code">on_entry</code> and <code class="code">on_exit</code> methods.</p></li></ul></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch06.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch06.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch06s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 6. Internals </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Generated state ids </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch06s03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch06s03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,23 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Generated state ids</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch06.html" title="Chapter 6. Internals"><link rel="prev" href="ch06s02.html" title="Frontend / Backend interface"><link rel="next" href="ch06s04.html" title="Metaprogramming tools"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center"> Generated state ids </th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch06s02.html">Prev</a> </td><th width="60%" align="center">Chapter 6. Internals</th><td width="20%" align="right"> <a accesskey="n" href="ch06s04.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Generated state ids"><div class="titlepage"><div><div><
h2 class="title" style="clear: both"><a name="d0e4158"></a><span class="command"><strong><a name="internals-state-id"></a></strong></span> Generated state ids </h2></div></div></div><p>Normally, one does not need to know the ids are generated for all the states
+ of a state machine, unless for debugging purposes, like the pstate function does
+ in the tutorials in order to display the name of the current state. This section
+ will show how to automatically display typeid-generated names, but these are not
+ very readable on all platforms, so it can help to know how the ids are
+ generated. The ids are generated using the transition table, from the “Start”
+ column up to down, then from the “Next” column, up to down, as shown in the next
+ image: </p><p><span class="inlinemediaobject"><img src="../images/AnnexA.jpg" width="90%"></span></p><p>Stopped will get id 0, Open id 1, ErrorMode id 6 and SleepMode (seen only in
+ the “Next” column) id 7. If you have some implicitly created states, like
+ transition-less initial states or states created using the explicit_creation
+ typedef, these will be added as a source at the end of the transition table. If
+ you have submachine states, a row will be added for them at the end of the
+ table, after the automatically or explicitly created states, which can change
+ their id. The next help you will need for debugging would be to call the
+ current_state method of the state_machine class, then the display_type helper to
+ generate a readable name from the id. If you do not want to go through the
+ transition table to fill an array of names, the library provides another helper,
+ fill_state_names, which, given an array of sufficient size (please see next
+ section to know how many states are defined in the state machine), will fill it
+ with typeid-generated names. </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch06s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch06.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch06s04.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Frontend / Backend
+ interface </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Metaprogramming tools</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch06s04.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch06s04.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,26 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Metaprogramming tools</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch06.html" title="Chapter 6. Internals"><link rel="prev" href="ch06s03.html" title="Generated state ids"><link rel="next" href="ch07.html" title="Chapter 7. Acknowledgements"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Metaprogramming tools</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch06s03.html">Prev</a> </td><th width="60%" align="center">Chapter 6. Internals</th><td width="20%" align="right"> <a accesskey="n" href="ch07.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Metaprogramming tools"><div class="titlepage"><div><
div><h2 class="title" style="clear: both"><a name="d0e4170"></a>Metaprogramming tools</h2></div></div></div><p>We can find for the transition table more uses than what we have seen so far.
+ Let's suppose you need to write a coverage tool. A state machine would be
+ perfect for such a job, if only it could provide some information about its
+ structure. Thanks to the transition table and Boost.MPL, it does.</p><p>What is needed for a coverage tool? You need to know how many states are
+ defined in the state machine, and how many events can be fired. This way you can
+ log the fired events and the states visited in the life of a concrete machine
+ and be able to perform some coverage analysis, like “fired 65% of all possible
+ events and visited 80% of the states defined in the state machine”. To achieve
+ this, MSM provides a few useful tools:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>generate_state_set<transition table>: returns a mpl::set of all
+ the states defined in the table.</p></li><li class="listitem"><p>generate_event_set<transition table>: returns a mpl::set of all
+ the events defined in the table.</p></li><li class="listitem"><p>using mpl::size<>::value you can get the number of elements in
+ the set.</p></li><li class="listitem"><p>display_type defines an operator() sending typeid(Type).name() to
+ cout.</p></li><li class="listitem"><p>fill_state_names fills an array of char const* with names of all
+ states (found by typeid)</p></li><li class="listitem"><p>using mpl::for_each on the result of generate_state_set and
+ generate_event_set passing display_type as argument will display all
+ the states of the state machine.</p></li><li class="listitem"><p>let's suppose you need to recursively find the states and events
+ defined in the composite states and thus also having a transition
+ table. Calling recursive_get_transition_table<Composite> will
+ return you the transition table of the composite state, recursively
+ adding the transition tables of all sub-state machines and
+ sub-sub...-sub-state machines. Then call generate_state_set or
+ generate_event_set on the result to get the full list of states and
+ events. </p></li></ul></div><p> An <a class="link" href="examples/BoostCon09Full.cpp" target="_top">example</a> shows the
+ tools in action. </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch06s03.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch06.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch07.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> Generated state ids </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 7. Acknowledgements</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch07.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch07.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,13 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 7. Acknowledgements</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="ch06s04.html" title="Metaprogramming tools"><link rel="next" href="ch07s02.html" title="MSM v1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 7. Acknowledgements</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch06s04.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="ch07s02.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 7. Acknowledgements"><div
class="titlepage"><div><div><h2 class="title"><a name="d0e4204"></a>Chapter 7. Acknowledgements</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1">MSM v2</span></dt><dt><span class="sect1"> MSM v1</span></dt></dl></div><p>I am in debt to the following people who helped MSM along the way.</p><div class="sect1" title="MSM v2"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e4209"></a>MSM v2</h2></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Thanks to Dave Abrahams for managing the review</p></li><li class="listitem"><p>Thanks to Eric Niebler for his patience correcting my grammar
+ errors</p></li><li class="listitem"><p>Special thanks to Joel de Guzman who gave me very good ideas at
+ the BoostCon09. These ideas were the starting point of the redesign.
+ Any time again, Joel ☺</p></li><li class="listitem"><p>Thanks to Richard O’Hara for making Green Hills bring a patch in
+ less than 1 week, thus adding one more compiler to the supported
+ list.</p></li><li class="listitem"><p>Big thanks to those who took the time to write a review: Franz
+ Alt, David Bergman, Michael Caisse, Barend Gehrels, Darryl Greene,
+ Juraj Ivancic, Erik Nelson, Kenny Riddile.</p></li><li class="listitem"><p>Thanks to Matt Calabrese, Juraj Ivancic, Adam Merz and Joseph Wu
+ for reporting bugs.</p></li></ul></div><p>
+ </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch06s04.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch07s02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Metaprogramming tools </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> MSM v1</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch07s02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch07s02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,13 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>MSM v1</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="ch07.html" title="Chapter 7. Acknowledgements"><link rel="prev" href="ch07.html" title="Chapter 7. Acknowledgements"><link rel="next" href="ch08.html" title="Chapter 8. Version history"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center"> MSM v1</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch07.html">Prev</a> </td><th width="60%" align="center">Chapter 7. Acknowledgements</th><td width="20%" align="right"> <a accesskey="n" href="ch08.html">Next</a></td></tr></table><hr></div><div class="sect1" title="MSM v1"><div class="titlepage"><div><div><h2 class="titl
e" style="clear: both"><a name="d0e4234"></a> MSM v1</h2></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>The original version of this framework is based on the brilliant
+ work of David Abrahams and Aleksey Gurtovoy who laid down the base
+ and the principles of the framework in their excellent book, “C++
+ template Metaprogramming”. The implementation also makes heavy use
+ of the boost::mpl.</p></li><li class="listitem"><p>Thanks to Jeff Flinn for his idea of the user-defined base state
+ and his review which allowed MSM to be presented at the
+ BoostCon09.</p></li><li class="listitem"><p>Thanks to my MSM v1 beta testers, Christoph Woskowski and Franz
+ Alt for using the framework with little documentation and to my
+ private reviewer, Edouard Alligand</p></li></ul></div><p>
+ </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch07.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch07.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch08.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 7. Acknowledgements </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 8. Version history</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch08.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch08.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,9 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 8. Version history</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt01.html" title="Part I. User' guide"><link rel="prev" href="ch07s02.html" title="MSM v1"><link rel="next" href="pt02.html" title="Part II. Reference"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 8. Version history</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch07s02.html">Prev</a> </td><th width="60%" align="center">Part I. User' guide</th><td width="20%" align="right"> <a accesskey="n" href="pt02.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 8. Version history"><div c
lass="titlepage"><div><div><h2 class="title"><a name="d0e4250"></a>Chapter 8. Version history</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1">From V2.0 to V2.10</span></dt></dl></div><div class="sect1" title="From V2.0 to V2.10"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e4253"></a>From V2.0 to V2.10</h2></div></div></div><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>New documentation</p></li><li class="listitem"><p>Internal transitions. Either as part of the transition table or
+ using a state's internal transition table</p></li><li class="listitem"><p>increased dispatch and copy speed</p></li><li class="listitem"><p><span class="command"><strong><a class="command" href="ch03s02.html#basic-row2">new row types</a></strong></span> for the
+ basic front-end</p></li><li class="listitem"><p>new eUML syntax, better attribute support, macros to ease
+ developer's life. Even VC8 seems to like it better.</p></li><li class="listitem"><p>New policy for reduced compile-time at the cost of dispatch
+ speed</p></li><li class="listitem"><p>Support for base events</p></li><li class="listitem"><p>possibility to choose the initial event</p></li></ul></div><p>
+ </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch07s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt01.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="pt02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> MSM v1 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Part II. Reference</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch08s02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch08s02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,23 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>eUML functions</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="ch08.html" title="Chapter 8. Reference"><link rel="prev" href="ch08.html" title="Chapter 8. Reference"><link rel="next" href="ch08s03.html" title="Functional programming"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">eUML functions</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch08.html">Prev</a> </td><th width="60%" align="center">Chapter 8. Reference</th><td width="20%" align="right"> <a accesskey="n" href="ch08s03.html">Next</a></td></tr></table><hr></div><div class="sect1" title="eUML functions"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e4306"></a>eUML functions</h2></div></
div></div><p>The following table lists the supported operators: </p><p>
+ </p><div class="table"><a name="d0e4313"></a><p class="title"><b>Table 8.1. Operators and state machine helpers</b></p><div class="table-contents"><table summary="Operators and state machine helpers" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>eUML function / operator</th><th>Description</th><th>Functor</th></tr></thead><tbody><tr><td>&&</td><td>Calls lazily Action1&& Action2</td><td>And_</td></tr><tr><td>||</td><td>Calls lazily Action1|| Action2</td><td>Or_</td></tr><tr><td>!</td><td>Calls lazily !Action1</td><td>Not_</td></tr><tr><td>!=</td><td>Calls lazily Action1 != Action2</td><td>NotEqualTo_</td></tr><tr><td>==</td><td>Calls lazily Action1 == Action2</td><td>EqualTo_</td></tr><tr><td>></td><td>Calls lazily Action1 > Action2</td><td>Greater_</td></tr><tr><td>>=</td><td>Calls lazily Action1 >= Action2</td><td>Greater_Equal_</td></tr><tr><td><</td><td>Calls lazily Action1 < Action2</td><td>Less_</td></tr><tr><td><=</td><td>C
alls lazily Action1 <= Action2</td><td>Less_Equal_</td></tr><tr><td>&</td><td>Calls lazily Action1 & Action2</td><td>Bitwise_And_</td></tr><tr><td>|</td><td>Calls lazily Action1 | Action2</td><td>Bitwise_Or_</td></tr><tr><td>^</td><td>Calls lazily Action1 ^ Action2</td><td>Bitwise_Xor_</td></tr><tr><td>--</td><td>Calls lazily --Action1 / Action1--</td><td>Pre_Dec_ / Post_Dec_</td></tr><tr><td>++</td><td>Calls lazily ++Action1 / Action1++</td><td>Pre_Inc_ / Post_Inc_</td></tr><tr><td>/</td><td>Calls lazily Action1 / Action2</td><td>Divides_</td></tr><tr><td>/=</td><td>Calls lazily Action1 /= Action2</td><td>Divides_Assign_</td></tr><tr><td>*</td><td>Calls lazily Action1 * Action2</td><td>Multiplies_</td></tr><tr><td>*=</td><td>Calls lazily Action1 *= Action2</td><td>Multiplies_Assign_</td></tr><tr><td>+ (binary)</td><td>Calls lazily Action1 + Action2</td><td>Plus_</td></tr><tr><td>+ (unary)</td><td>Calls lazily +Action1</td><td>Unary_Plus_</td></tr><tr><td>+=</td><td>Calls lazily Action1 += Action2
</td><td>Plus_Assign_</td></tr><tr><td>- (binary)</td><td>Calls lazily Action1 - Action2</td><td>Minus_</td></tr><tr><td>- (unary)</td><td>Calls lazily -Action1</td><td>Unary_Minus_</td></tr><tr><td>-=</td><td>Calls lazily Action1 -= Action2</td><td>Minus_Assign_</td></tr><tr><td>%</td><td>Calls lazily Action1 % Action2</td><td>Modulus_</td></tr><tr><td>%=</td><td>Calls lazily Action1 %= Action2</td><td>Modulus_Assign_</td></tr><tr><td>>></td><td>Calls lazily Action1 >> Action2</td><td>ShiftRight_</td></tr><tr><td>>>=</td><td>Calls lazily Action1 >>= Action2</td><td>ShiftRight_Assign_</td></tr><tr><td><<</td><td>Calls lazily Action1 << Action2</td><td>ShiftLeft_</td></tr><tr><td><<=</td><td>Calls lazily Action1 <<= Action2</td><td>ShiftLeft_Assign_</td></tr><tr><td>[] (works on vector, map, arrays)</td><td>Calls lazily Action1 [Action2]</td><td>Subscript_</td></tr><tr><td>if_then_else_(Condition,Action1,Action2)</td><td>Returns either the result of calling Acti
on1 or the result of
+ calling Action2</td><td>If_Else_</td></tr><tr><td>if_then_(Condition,Action)</td><td>Returns the result of calling Action if Condition</td><td>If_Then_</td></tr><tr><td>while_(Condition, Body)</td><td>While Condition(), calls Body(). Returns nothing</td><td>While_Do_</td></tr><tr><td>do_while_(Condition, Body)</td><td>Calls Body() while Condition(). Returns nothing</td><td>Do_While_</td></tr><tr><td>for_(Begin,Stop,EndLoop,Body)</td><td>Calls for(Begin;Stop;EndLoop){Body;}</td><td>For_Loop_</td></tr><tr><td>process_(Event [,fsm1] [,fsm2] [,fsm3] [,fsm4])</td><td>Processes Event on the current state machine (if no fsm
+ specified) or on up to 4 state machines returned by an
+ appropriate functor.</td><td>Process_</td></tr><tr><td>process2_(Event, Data [,fsm1] [,fsm2] [,fsm3])</td><td>Processes Event on the current state machine (if no fsm
+ specified) or on up to 2 state machines returned by an
+ appropriate functor. The event is copy-constructed from what
+ Data() returns.</td><td>Process2_</td></tr><tr><td>is_flag_(Flag [,fsm])</td><td>Calls is_flag_active() on the current state machine or the
+ one returned by calling fsm.</td><td>Get_Flag_</td></tr><tr><td>event_ [(attribute name)]</td><td>Returns the current event (as const reference)</td><td>GetEvent_</td></tr><tr><td>source_ [(attribute name)]</td><td>Returns the source state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</td><td>GetSource_</td></tr><tr><td>target_ [(attribute name)]</td><td>Returns the target state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</td><td>GetTarget_</td></tr><tr><td>state_ [(attribute name)]</td><td>Returns the source state of the currently active state (as
+ reference). Valid inside a state entry/exit action. If an
+ attribute name is provided, returns the attribute by
+ reference.</td><td>GetState_</td></tr><tr><td>fsm_ [(attribute name)]</td><td>Returns the current state machine (as reference). Valid
+ inside a state entry/exit action or a transition. If an
+ attribute name is provided, returns the attribute by
+ reference.</td><td>GetFsm_</td></tr><tr><td>substate_(state_name [,fsm])</td><td>Returns (as reference) the state state_name referenced in the
+ current state machine or the one given as argument.</td><td>SubState_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>TODO macro for functor def</p><p>To use these functions, you need to include: </p><p><code class="code">#include <msm/front/euml/euml.hpp></code></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch08.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch08.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch08s03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 8. Reference </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Functional programming </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch08s03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch08s03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,92 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Functional programming</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="ch08.html" title="Chapter 8. Reference"><link rel="prev" href="ch08s02.html" title="eUML functions"><link rel="next" href="rn01.html" title="Reference"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center"> Functional programming </th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch08s02.html">Prev</a> </td><th width="60%" align="center">Chapter 8. Reference</th><td width="20%" align="right"> <a accesskey="n" href="rn01.html">Next</a></td></tr></table><hr></div><div class="sect1" title="Functional programming"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="d0e4652"></a> Functional programming </h2><
/div></div></div><p>To use these functions, you need to include: </p><p><code class="code">#include <msm/front/euml/stl.hpp></code></p><p>or the specified header in the following tables.</p><p>The following table lists the supported STL algorithms: </p><p>
+ </p><div class="table"><a name="d0e4666"></a><p class="title"><b>Table 8.2. STL algorithms</b></p><div class="table-contents"><table summary="STL algorithms" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL algorithms in querying.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>find_(first, last, value)</td><td>Find_</td></tr><tr><td>find_if_(first, last, value)</td><td>FindIf_</td></tr><tr><td>lower_bound_(first, last, value [,opᵃ])</td><td>LowerBound_</td></tr><tr><td>upper_bound_(first, last, value [,opᵃ])</td><td>UpperBound_</td></tr><tr><td>equal_range_(first, last, value [,opᵃ])</td><td>EqualRange_</td></tr><tr><td>binary_search_(first, last, value [,opᵃ])</td><td>BinarySearch_</td></tr><tr><td>min_element_(first, last[,opᵃ])</td><td>MinElement_</td></tr><tr><td>max_element_(first, last[,opᵃ])</td><td>MaxElement_</td></tr><tr><td>adjacent_find_(first, last[,opᵃ])</td><td>AdjacentFind_</td></tr><tr><td>find_end_( first1,
last1, first2, last2 [,op ᵃ])</td><td>FindEnd_</td></tr><tr><td>find_first_of_( first1, last1, first2, last2 [,op ᵃ])</td><td>FindFirstOf_</td></tr><tr><td>equal_( first1, last1, first2 [,op ᵃ])</td><td>Equal_</td></tr><tr><td>search_( first1, last1, first2, last2 [,op ᵃ])</td><td>Search_</td></tr><tr><td>includes_( first1, last1, first2, last2 [,op ᵃ])</td><td>Includes_</td></tr><tr><td>lexicographical_compare_ ( first1, last1, first2, last2 [,op
+ ᵃ]) </td><td>LexicographicalCompare_</td></tr><tr><td>count_(first, last, value [,size])</td><td>Count_</td></tr><tr><td>count_if_(first, last, op ᵃ [,size])</td><td>CountIf_</td></tr><tr><td>distance_(first, last)</td><td>Distance_</td></tr><tr><td>mismatch _( first1, last1, first2 [,op ᵃ])</td><td>Mismatch_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e4777"></a><p class="title"><b>Table 8.3. STL algorithms</b></p><div class="table-contents"><table summary="STL algorithms" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL algorithms in transformation.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>copy_(first, last, result)</td><td>Copy_</td></tr><tr><td>copy_backward_(first, last, result)</td><td>CopyBackward_</td></tr><tr><td>reverse_(first, last)</td><td>Reverse_</td></tr><tr><td>reverse_copy_(first, last , result)</td><td>ReverseCopy_</td></tr><tr><td>remove_(first, last, value)</td><td>Remove_</td></tr><tr><td>remove_if_(first, last , opᵃ)</td><td>RemoveIf_</td></tr><tr><td>remove_copy_(first, last , output, value)</td><td>RemoveCopy_</td></tr><tr><td>remove_copy_if_(first, last, output, opᵃ)</td><td>RemoveCopyIf_</td></tr><tr><td>fill_(first, last, value)</td><td>Fill_</td></tr><tr><td>fill_n_(first, size, value)ᵇ</td><td>FillN_</td></tr><tr><td>generate_(f
irst, last, generatorᵃ)</td><td>Generate_</td></tr><tr><td>generate_(first, size, generatorᵃ)ᵇ</td><td>GenerateN_</td></tr><tr><td>unique_(first, last [,opᵃ])</td><td>Unique_</td></tr><tr><td>unique_copy_(first, last, output [,opᵃ])</td><td>UniqueCopy_</td></tr><tr><td>random_shuffle_(first, last [,opᵃ])</td><td>RandomShuffle_</td></tr><tr><td>rotate_copy_(first, middle, last, output)</td><td>RotateCopy_</td></tr><tr><td>partition_ (first, last [,opᵃ])</td><td>Partition_</td></tr><tr><td>stable_partition_ (first, last [,opᵃ])</td><td>StablePartition_</td></tr><tr><td>stable_sort_(first, last [,opᵃ])</td><td>StableSort_</td></tr><tr><td>sort_(first, last [,opᵃ])</td><td>Sort_</td></tr><tr><td>partial_sort_(first, middle, last [,opᵃ])</td><td>PartialSort_</td></tr><tr><td>partial_sort_copy_ (first, last, res_first, res_last [,opᵃ]) </td><td>PartialSortCopy_</td></tr><tr><td>nth_element_(first, nth, last [,opᵃ])</td><td>NthElement_</t
d></tr><tr><td>merge_( first1, last1, first2, last2, output [,op ᵃ])</td><td>Merge_</td></tr><tr><td>inplace_merge_(first, middle, last [,opᵃ])</td><td>InplaceMerge_</td></tr><tr><td>set_union_(first1, last1, first2, last2, output [,op
+ ᵃ])</td><td>SetUnion_</td></tr><tr><td>push_heap_(first, last [,op ᵃ])</td><td>PushHeap_</td></tr><tr><td>pop_heap_(first, last [,op ᵃ])</td><td>PopHeap_</td></tr><tr><td>make_heap_(first, last [,op ᵃ])</td><td>MakeHeap_</td></tr><tr><td>sort_heap_(first, last [,op ᵃ])</td><td>SortHeap_</td></tr><tr><td>next_permutation_(first, last [,op ᵃ])</td><td>NextPermutation_</td></tr><tr><td>prev_permutation_(first, last [,op ᵃ])</td><td>PrevPermutation_</td></tr><tr><td>inner_product_(first1, last1, first2, init [,op1ᵃ] [,op2ᵃ]) </td><td>InnerProduct_</td></tr><tr><td>partial_sum_(first, last, output [,opᵃ])</td><td>PartialSum_</td></tr><tr><td>adjacent_difference_(first, last, output [,opᵃ])</td><td>AdjacentDifference_</td></tr><tr><td>replace_(first, last, old_value, new_value)</td><td>Replace_</td></tr><tr><td>replace_if_(first, last, opᵃ, new_value)</td><td>ReplaceIf_</td></tr><tr><td>replace_copy_(first,
last, result, old_value,
+ new_value)</td><td>ReplaceCopy_</td></tr><tr><td>replace_copy_if_(first, last, result, opᵃ, new_value)</td><td>ReplaceCopyIf_</td></tr><tr><td>rotate_(first, middle, last)ᵇ</td><td>Rotate_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e4993"></a><p class="title"><b>Table 8.4. STL container methods</b></p><div class="table-contents"><table summary="STL container methods" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL container methods(common) in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>container::reference front_(container)</td><td>Front_</td></tr><tr><td>container::reference back_(container)</td><td>Back_</td></tr><tr><td>container::iterator begin_(container)</td><td>Begin_</td></tr><tr><td>container::iterator end_(container)</td><td>End_</td></tr><tr><td>container::reverse_iterator rbegin_(container)</td><td>RBegin_</td></tr><tr><td>container::reverse_iterator rend_(container)</td><td>REnd_</td></tr><tr><td>void push_back_(container, value)</td><td>Push_Back_</td></tr><tr><td>void pop_back_(container, value)</td><td>Pop_Back_</td></tr><tr><td>void push_front_(container, value)</td><td>Push_Front_</td></tr><tr><td>void pop_front_(container, val
ue)</td><td>Pop_Front_</td></tr><tr><td>void clear_(container)</td><td>Clear_</td></tr><tr><td>size_type capacity_(container)</td><td>Capacity_</td></tr><tr><td>size_type size_(container)</td><td>Size_</td></tr><tr><td>size_type max_size_(container)</td><td>Max_Size_</td></tr><tr><td>void reserve_(container, value)</td><td>Reserve _</td></tr><tr><td>void resize_(container, value)</td><td>Resize _</td></tr><tr><td>iterator insert_(container, pos, value)</td><td>Insert_</td></tr><tr><td>void insert_( container , pos, first, last)</td><td>Insert_</td></tr><tr><td>void insert_( container , pos, number, value)</td><td>Insert_</td></tr><tr><td>void swap_( container , other_container)</td><td>Swap_</td></tr><tr><td>void erase_( container , pos)</td><td>Erase_</td></tr><tr><td>void erase_( container , first, last) </td><td>Erase_</td></tr><tr><td>bool empty_( container)</td><td>Empty_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5124"></a><p class="title"><b>Table 8.5. STL list methods</b></p><div class="table-contents"><table summary="STL list methods" border="1"><colgroup><col><col></colgroup><thead><tr><th>std::list methods in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>void list_remove_(container, value)</td><td>ListRemove_</td></tr><tr><td>void list_remove_if_(container, opᵃ)</td><td>ListRemove_If_</td></tr><tr><td>void list_merge_(container, other_list)</td><td>ListMerge_</td></tr><tr><td>void list_merge_(container, other_list, opᵃ)</td><td>ListMerge_</td></tr><tr><td>void splice_(container, iterator, other_list)</td><td>Splice_</td></tr><tr><td>void splice_(container, iterator, other_list,
+ iterator)</td><td>Splice_</td></tr><tr><td>void splice_(container, iterator, other_list, first,
+ last)</td><td>Splice_</td></tr><tr><td>void list_reverse_(container)</td><td>ListReverse_</td></tr><tr><td>void list_unique_(container)</td><td>ListUnique_</td></tr><tr><td>void list_unique_(container, opᵃ)</td><td>ListUnique_</td></tr><tr><td>void list_sort_(container)</td><td>ListSort_</td></tr><tr><td>void list_sort_(container, opᵃ)</td><td>ListSort_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5200"></a><p class="title"><b>Table 8.6. STL associative container methods </b></p><div class="table-contents"><table summary="STL associative container methods " border="1"><colgroup><col><col></colgroup><thead><tr><th>Associative container methods in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>iterator insert_(container, pos, value)</td><td>Insert_</td></tr><tr><td>void insert_( container , first, last)</td><td>Insert_</td></tr><tr><td>pair<iterator, bool> insert_( container , value)</td><td>Insert_</td></tr><tr><td>void associative_erase_( container , pos)</td><td>Associative_Erase_</td></tr><tr><td>void associative_erase_( container , first, last)</td><td>Associative_Erase_</td></tr><tr><td>size_type associative_erase_( container , key)</td><td>Associative_Erase_</td></tr><tr><td>iterator associative_find_( container , key)</td><td>Associative_Find_</td></tr><tr><td>size_type associative_count_( container , key)</td><td
>AssociativeCount_</td></tr><tr><td>iterator associative_lower_bound_( container , key)</td><td>Associative_Lower_Bound_</td></tr><tr><td>iterator associative_upper_bound_( container , key)</td><td>Associative_Upper_Bound_</td></tr><tr><td>pair<iterator, iterator> associative_equal_range_(
+ container , key)</td><td>Associative_Equal_Range_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5271"></a><p class="title"><b>Table 8.7. STL pair</b></p><div class="table-contents"><table summary="STL pair" border="1"><colgroup><col><col></colgroup><thead><tr><th>std::pair in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>first_type first_(pair<T1, T2>)</td><td>First_</td></tr><tr><td>second_type second_(pair<T1, T2>)</td><td>Second_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5297"></a><p class="title"><b>Table 8.8. STL string</b></p><div class="table-contents"><table summary="STL string" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>STL string method</th><th>std::string method in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>substr (size_type pos, size_type size)</td><td>string substr_(container, pos, length)</td><td>Substr_</td></tr><tr><td>int compare(string)</td><td>int string_compare_(container, another_string)</td><td>StringCompare_</td></tr><tr><td>int compare(char*)</td><td>int string_compare_(container, another_string)</td><td>StringCompare_</td></tr><tr><td>int compare(size_type pos, size_type size, string)</td><td>int string_compare_(container, pos, size,
+ another_string)</td><td>StringCompare_</td></tr><tr><td>int compare (size_type pos, size_type size, string, size_type
+ length)</td><td>int string_compare_(container, pos, size, another_string,
+ length)</td><td>StringCompare_</td></tr><tr><td>string& append(const string&)</td><td>string& append_(container, another_string)</td><td>Append_</td></tr><tr><td>string& append (charT*)</td><td>string& append_(container, another_string)</td><td>Append_</td></tr><tr><td>string& append (string , size_type pos, size_type
+ size)</td><td>string& append_(container, other_string, pos,
+ size)</td><td>Append_</td></tr><tr><td>string& append (charT*, size_type size)</td><td>string& append_(container, another_string,
+ length)</td><td>Append_</td></tr><tr><td>string& append (size_type size, charT)</td><td>string& append_(container, size, char)</td><td>Append_</td></tr><tr><td>string& append (iterator begin, iterator end)</td><td>string& append_(container, begin, end)</td><td>Append_</td></tr><tr><td>string& insert (size_type pos, charT*)</td><td>string& string_insert_(container, pos,
+ other_string)</td><td>StringInsert_</td></tr><tr><td>string& insert(size_type pos, charT*,size_type n)</td><td>string& string_insert_(container, pos, other_string,
+ n)</td><td>StringInsert_</td></tr><tr><td>string& insert(size_type pos,size_type n, charT
+ c)</td><td>string& string_insert_(container, pos, n, c)</td><td>StringInsert_</td></tr><tr><td>string& insert (size_type pos, const string&)</td><td>string& string_insert_(container, pos,
+ other_string)</td><td>StringInsert_</td></tr><tr><td>string& insert (size_type pos, const string&,
+ size_type pos1, size_type n)</td><td>string& string_insert_(container, pos, other_string,
+ pos1, n)</td><td>StringInsert_</td></tr><tr><td>string& erase(size_type pos=0, size_type n=npos)</td><td>string& string_erase_(container, pos, n)</td><td>StringErase_</td></tr><tr><td>string& assign(const string&)</td><td>string& string_assign_(container, another_string)</td><td>StringAssign_</td></tr><tr><td>string& assign(const charT*)</td><td>string& string_assign_(container, another_string)</td><td>StringAssign_</td></tr><tr><td>string& assign(const string&, size_type pos,
+ size_type n)</td><td>string& string_assign_(container, another_string, pos,
+ n)</td><td>StringAssign_</td></tr><tr><td>string& assign(const charT*, size_type n)</td><td>string& string_assign_(container, another_string,
+ n)</td><td>StringAssign_</td></tr><tr><td>string& assign(size_type n, charT c)</td><td>string& string_assign_(container, n, c)</td><td>StringAssign_</td></tr><tr><td>string& assign(iterator first, iterator last)</td><td>string& string_assign_(container, first, last)</td><td>StringAssign_</td></tr><tr><td>string& replace(size_type pos, size_type n, const
+ string&)</td><td>string& string_replace_(container, pos, n,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, const charT*,
+ size_type n1)</td><td>string& string_replace_(container, pos, n,
+ another_string, n1)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, const
+ charT*)</td><td>string& string_replace_(container, pos, n,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, size_type n1,
+ charT c)</td><td>string& string_replace_(container, pos, n, n1, c)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ string&)</td><td>string& string_replace_(container, first, last,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ charT*, size_type n)</td><td>string& string_replace_(container, first, last,
+ another_string, n)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ charT*)</td><td>string& string_replace_(container, first, last,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, size_type
+ n, charT c)</td><td>string& string_replace_(container, first, last, n,
+ c)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, iterator
+ f, iterator l)</td><td>string& string_replace_(container, first, last, f,
+ l)</td><td>StringReplace_</td></tr><tr><td>const charT* c_str()</td><td>const charT* c_str_(container)</td><td>CStr_</td></tr><tr><td>const charT* data()</td><td>const charT* string_data_(container)</td><td>StringData_</td></tr><tr><td>size_type copy(charT* buf, size_type n, size_type pos =
+ 0)</td><td>size_type string_copy_(container, buf, n, pos); size_type
+ string_copy_(container, buf, n) </td><td>StringCopy_</td></tr><tr><td>size_type find(charT* s, size_type pos, size_type n)</td><td>size_type string_find_(container, s, pos, n)</td><td>StringFind_</td></tr><tr><td>size_type find(charT* s, size_type pos=0)</td><td>size_type string_find_(container, s, pos); size_type
+ string_find_(container, s) </td><td>StringFind_</td></tr><tr><td>size_type find(const string& s, size_type pos=0)</td><td>size_type string_find_(container, s, pos) size_type
+ string_find_(container, s) </td><td>StringFind_</td></tr><tr><td>size_type find(charT c, size_type pos=0)</td><td>size_type string_find_(container, c, pos) size_type
+ string_find_(container, c) </td><td>StringFind_</td></tr><tr><td>size_type rfind(charT* s, size_type pos, size_type n)</td><td>size_type string_rfind_(container, s, pos, n)</td><td>StringRFind_</td></tr><tr><td>size_type rfind(charT* s, size_type pos=npos)</td><td>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </td><td>StringRFind_</td></tr><tr><td>size_type rfind(const string& s, size_type
+ pos=npos)</td><td>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </td><td>StringRFind_</td></tr><tr><td>size_type rfind(charT c, size_type pos=npos)</td><td>size_type string_rfind_(container, c, pos) size_type
+ string_rfind_(container, c) </td><td>StringRFind_</td></tr><tr><td>size_type find_first_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_first_of_(container, s, pos, n)</td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (charT* s, size_type pos=0)</td><td>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (const string& s, size_type
+ pos=0)</td><td>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (charT c, size_type pos=0)</td><td>size_type find_first_of_(container, c, pos) size_type
+ find_first_of_(container, c) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_not_of(charT* s, size_type pos,
+ size_type n)</td><td>size_type find_first_not_of_(container, s, pos, n)</td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (charT* s, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (const string& s, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (charT c, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, c, pos); size_type
+ find_first_not_of_(container, c) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_last_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_last_of_(container, s, pos, n)</td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (charT* s, size_type pos=npos)</td><td>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (const string& s, size_type
+ pos=npos)</td><td>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (charT c, size_type pos=npos)</td><td>size_type find_last_of_(container, c, pos); size_type
+ find_last_of_(container, c) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_not_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_last_not_of_(container, s, pos, n)</td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (charT* s, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (const string& s, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_not_of_(container, s) </td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (charT c, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, c, pos); size_type
+ find_last_not_of_(container, c) </td><td>StringFindLastNotOf_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p><span class="underline">Notes</span>: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>ᵃ: algorithms requiring a predicate need to make them eUML compatible
+ by wrapping them inside a Predicate_ functor. For example,
+ std::less<int> => Predicate_<std::less<int> >()</p></li><li class="listitem"><p>ᵇ: If using the SGI STL implementation, these functors use the SGI
+ return value</p></li></ul></div><p>
+ </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch08s02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="ch08.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="rn01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">eUML functions </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Reference</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch09.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch09.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,24 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 9. eUML operators and basic helpers</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt02.html" title="Part II. Reference"><link rel="prev" href="pt02.html" title="Part II. Reference"><link rel="next" href="ch10.html" title="Chapter 10. Functional programming"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 9. eUML operators and basic helpers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="pt02.html">Prev</a> </td><th width="60%" align="center">Part II. Reference</th><td width="20%" align="right"> <a accesskey="n" href="ch10.html">Next</a></td></tr></table><hr></div><div cl
ass="chapter" title="Chapter 9. eUML operators and basic helpers"><div class="titlepage"><div><div><h2 class="title"><a name="d0e4290"></a>Chapter 9. eUML operators and basic helpers</h2></div></div></div><p>The following table lists the supported operators: </p><p>
+ </p><div class="table"><a name="d0e4297"></a><p class="title"><b>Table 9.1. Operators and state machine helpers</b></p><div class="table-contents"><table summary="Operators and state machine helpers" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>eUML function / operator</th><th>Description</th><th>Functor</th></tr></thead><tbody><tr><td>&&</td><td>Calls lazily Action1&& Action2</td><td>And_</td></tr><tr><td>||</td><td>Calls lazily Action1|| Action2</td><td>Or_</td></tr><tr><td>!</td><td>Calls lazily !Action1</td><td>Not_</td></tr><tr><td>!=</td><td>Calls lazily Action1 != Action2</td><td>NotEqualTo_</td></tr><tr><td>==</td><td>Calls lazily Action1 == Action2</td><td>EqualTo_</td></tr><tr><td>></td><td>Calls lazily Action1 > Action2</td><td>Greater_</td></tr><tr><td>>=</td><td>Calls lazily Action1 >= Action2</td><td>Greater_Equal_</td></tr><tr><td><</td><td>Calls lazily Action1 < Action2</td><td>Less_</td></tr><tr><td><=</td><td>C
alls lazily Action1 <= Action2</td><td>Less_Equal_</td></tr><tr><td>&</td><td>Calls lazily Action1 & Action2</td><td>Bitwise_And_</td></tr><tr><td>|</td><td>Calls lazily Action1 | Action2</td><td>Bitwise_Or_</td></tr><tr><td>^</td><td>Calls lazily Action1 ^ Action2</td><td>Bitwise_Xor_</td></tr><tr><td>--</td><td>Calls lazily --Action1 / Action1--</td><td>Pre_Dec_ / Post_Dec_</td></tr><tr><td>++</td><td>Calls lazily ++Action1 / Action1++</td><td>Pre_Inc_ / Post_Inc_</td></tr><tr><td>/</td><td>Calls lazily Action1 / Action2</td><td>Divides_</td></tr><tr><td>/=</td><td>Calls lazily Action1 /= Action2</td><td>Divides_Assign_</td></tr><tr><td>*</td><td>Calls lazily Action1 * Action2</td><td>Multiplies_</td></tr><tr><td>*=</td><td>Calls lazily Action1 *= Action2</td><td>Multiplies_Assign_</td></tr><tr><td>+ (binary)</td><td>Calls lazily Action1 + Action2</td><td>Plus_</td></tr><tr><td>+ (unary)</td><td>Calls lazily +Action1</td><td>Unary_Plus_</td></tr><tr><td>+=</td><td>Calls lazily Action1 += Action2
</td><td>Plus_Assign_</td></tr><tr><td>- (binary)</td><td>Calls lazily Action1 - Action2</td><td>Minus_</td></tr><tr><td>- (unary)</td><td>Calls lazily -Action1</td><td>Unary_Minus_</td></tr><tr><td>-=</td><td>Calls lazily Action1 -= Action2</td><td>Minus_Assign_</td></tr><tr><td>%</td><td>Calls lazily Action1 % Action2</td><td>Modulus_</td></tr><tr><td>%=</td><td>Calls lazily Action1 %= Action2</td><td>Modulus_Assign_</td></tr><tr><td>>></td><td>Calls lazily Action1 >> Action2</td><td>ShiftRight_</td></tr><tr><td>>>=</td><td>Calls lazily Action1 >>= Action2</td><td>ShiftRight_Assign_</td></tr><tr><td><<</td><td>Calls lazily Action1 << Action2</td><td>ShiftLeft_</td></tr><tr><td><<=</td><td>Calls lazily Action1 <<= Action2</td><td>ShiftLeft_Assign_</td></tr><tr><td>[] (works on vector, map, arrays)</td><td>Calls lazily Action1 [Action2]</td><td>Subscript_</td></tr><tr><td>if_then_else_(Condition,Action1,Action2)</td><td>Returns either the result of calling Acti
on1 or the result of
+ calling Action2</td><td>If_Else_</td></tr><tr><td>if_then_(Condition,Action)</td><td>Returns the result of calling Action if Condition</td><td>If_Then_</td></tr><tr><td>while_(Condition, Body)</td><td>While Condition(), calls Body(). Returns nothing</td><td>While_Do_</td></tr><tr><td>do_while_(Condition, Body)</td><td>Calls Body() while Condition(). Returns nothing</td><td>Do_While_</td></tr><tr><td>for_(Begin,Stop,EndLoop,Body)</td><td>Calls for(Begin;Stop;EndLoop){Body;}</td><td>For_Loop_</td></tr><tr><td>process_(Event [,fsm1] [,fsm2] [,fsm3] [,fsm4])</td><td>Processes Event on the current state machine (if no fsm
+ specified) or on up to 4 state machines returned by an
+ appropriate functor.</td><td>Process_</td></tr><tr><td>process2_(Event, Data [,fsm1] [,fsm2] [,fsm3])</td><td>Processes Event on the current state machine (if no fsm
+ specified) or on up to 2 state machines returned by an
+ appropriate functor. The event is copy-constructed from what
+ Data() returns.</td><td>Process2_</td></tr><tr><td>is_flag_(Flag [,fsm])</td><td>Calls is_flag_active() on the current state machine or the
+ one returned by calling fsm.</td><td>Get_Flag_</td></tr><tr><td>event_ [(attribute name)]</td><td>Returns the current event (as const reference)</td><td>GetEvent_</td></tr><tr><td>source_ [(attribute name)]</td><td>Returns the source state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</td><td>GetSource_</td></tr><tr><td>target_ [(attribute name)]</td><td>Returns the target state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</td><td>GetTarget_</td></tr><tr><td>state_ [(attribute name)]</td><td>Returns the source state of the currently active state (as
+ reference). Valid inside a state entry/exit action. If an
+ attribute name is provided, returns the attribute by
+ reference.</td><td>GetState_</td></tr><tr><td>fsm_ [(attribute name)]</td><td>Returns the current state machine (as reference). Valid
+ inside a state entry/exit action or a transition. If an
+ attribute name is provided, returns the attribute by
+ reference.</td><td>GetFsm_</td></tr><tr><td>substate_(state_name [,fsm])</td><td>Returns (as reference) the state state_name referenced in the
+ current state machine or the one given as argument.</td><td>SubState_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>To use these functions, you need to include: </p><p><code class="code">#include <msm/front/euml/euml.hpp></code></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="pt02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt02.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="ch10.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Part II. Reference </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 10.
+ Functional programming </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/ch10.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/ch10.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,100 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Chapter 10. Functional programming</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt02.html" title="Part II. Reference"><link rel="prev" href="ch09.html" title="Chapter 9. eUML operators and basic helpers"><link rel="next" href="re01.html" title="Common headers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Chapter 10.
+ Functional programming </th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch09.html">Prev</a> </td><th width="60%" align="center">Part II. Reference</th><td width="20%" align="right"> <a accesskey="n" href="re01.html">Next</a></td></tr></table><hr></div><div class="chapter" title="Chapter 10. Functional programming"><div class="titlepage"><div><div><h2 class="title"><a name="d0e4634"></a>Chapter 10.
+ <span class="command"><strong><a name="eUML-STL-all"></a></strong></span>Functional programming </h2></div></div></div><p>To use these functions, you need to include: </p><p><code class="code">#include <msm/front/euml/stl.hpp></code></p><p>or the specified header in the following tables.</p><p>The following tables list the supported STL algorithms: </p><p>
+ <span class="command"><strong><a name="eUML-STL-querying"></a></strong></span>
+ </p><div class="table"><a name="d0e4652"></a><p class="title"><b>Table 10.1. STL algorithms</b></p><div class="table-contents"><table summary="STL algorithms" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL algorithms in querying.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>find_(first, last, value)</td><td>Find_</td></tr><tr><td>find_if_(first, last, value)</td><td>FindIf_</td></tr><tr><td>lower_bound_(first, last, value [,opᵃ])</td><td>LowerBound_</td></tr><tr><td>upper_bound_(first, last, value [,opᵃ])</td><td>UpperBound_</td></tr><tr><td>equal_range_(first, last, value [,opᵃ])</td><td>EqualRange_</td></tr><tr><td>binary_search_(first, last, value [,opᵃ])</td><td>BinarySearch_</td></tr><tr><td>min_element_(first, last[,opᵃ])</td><td>MinElement_</td></tr><tr><td>max_element_(first, last[,opᵃ])</td><td>MaxElement_</td></tr><tr><td>adjacent_find_(first, last[,opᵃ])</td><td>AdjacentFind_</td></tr><tr><td>find_end_( first1
, last1, first2, last2 [,op ᵃ])</td><td>FindEnd_</td></tr><tr><td>find_first_of_( first1, last1, first2, last2 [,op ᵃ])</td><td>FindFirstOf_</td></tr><tr><td>equal_( first1, last1, first2 [,op ᵃ])</td><td>Equal_</td></tr><tr><td>search_( first1, last1, first2, last2 [,op ᵃ])</td><td>Search_</td></tr><tr><td>includes_( first1, last1, first2, last2 [,op ᵃ])</td><td>Includes_</td></tr><tr><td>lexicographical_compare_ ( first1, last1, first2, last2 [,op
+ ᵃ]) </td><td>LexicographicalCompare_</td></tr><tr><td>count_(first, last, value [,size])</td><td>Count_</td></tr><tr><td>count_if_(first, last, op ᵃ [,size])</td><td>CountIf_</td></tr><tr><td>distance_(first, last)</td><td>Distance_</td></tr><tr><td>mismatch _( first1, last1, first2 [,op ᵃ])</td><td>Mismatch_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ <span class="command"><strong><a name="eUML-STL-iteration"></a></strong></span>
+ </p><div class="table"><a name="d0e4765"></a><p class="title"><b>Table 10.2. STL algorithms</b></p><div class="table-contents"><table summary="STL algorithms" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL algorithms in iteration.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>for_each_(first,last, unary opᵃ)</td><td>ForEach_</td></tr><tr><td>accumulate_first, last, init [,opᵃ])</td><td>Accumulate_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ <span class="command"><strong><a name="eUML-STL-transformation"></a></strong></span>
+ </p><div class="table"><a name="d0e4793"></a><p class="title"><b>Table 10.3. STL algorithms</b></p><div class="table-contents"><table summary="STL algorithms" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL algorithms in transformation.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>copy_(first, last, result)</td><td>Copy_</td></tr><tr><td>copy_backward_(first, last, result)</td><td>CopyBackward_</td></tr><tr><td>reverse_(first, last)</td><td>Reverse_</td></tr><tr><td>reverse_copy_(first, last , result)</td><td>ReverseCopy_</td></tr><tr><td>remove_(first, last, value)</td><td>Remove_</td></tr><tr><td>remove_if_(first, last , opᵃ)</td><td>RemoveIf_</td></tr><tr><td>remove_copy_(first, last , output, value)</td><td>RemoveCopy_</td></tr><tr><td>remove_copy_if_(first, last, output, opᵃ)</td><td>RemoveCopyIf_</td></tr><tr><td>fill_(first, last, value)</td><td>Fill_</td></tr><tr><td>fill_n_(first, size, value)ᵇ</td><td>FillN_</td></tr><tr><td>generate_(
first, last, generatorᵃ)</td><td>Generate_</td></tr><tr><td>generate_(first, size, generatorᵃ)ᵇ</td><td>GenerateN_</td></tr><tr><td>unique_(first, last [,opᵃ])</td><td>Unique_</td></tr><tr><td>unique_copy_(first, last, output [,opᵃ])</td><td>UniqueCopy_</td></tr><tr><td>random_shuffle_(first, last [,opᵃ])</td><td>RandomShuffle_</td></tr><tr><td>rotate_copy_(first, middle, last, output)</td><td>RotateCopy_</td></tr><tr><td>partition_ (first, last [,opᵃ])</td><td>Partition_</td></tr><tr><td>stable_partition_ (first, last [,opᵃ])</td><td>StablePartition_</td></tr><tr><td>stable_sort_(first, last [,opᵃ])</td><td>StableSort_</td></tr><tr><td>sort_(first, last [,opᵃ])</td><td>Sort_</td></tr><tr><td>partial_sort_(first, middle, last [,opᵃ])</td><td>PartialSort_</td></tr><tr><td>partial_sort_copy_ (first, last, res_first, res_last [,opᵃ]) </td><td>PartialSortCopy_</td></tr><tr><td>nth_element_(first, nth, last [,opᵃ])</td><td>NthElement_</
td></tr><tr><td>merge_( first1, last1, first2, last2, output [,op ᵃ])</td><td>Merge_</td></tr><tr><td>inplace_merge_(first, middle, last [,opᵃ])</td><td>InplaceMerge_</td></tr><tr><td>set_union_(first1, last1, first2, last2, output [,op
+ ᵃ])</td><td>SetUnion_</td></tr><tr><td>push_heap_(first, last [,op ᵃ])</td><td>PushHeap_</td></tr><tr><td>pop_heap_(first, last [,op ᵃ])</td><td>PopHeap_</td></tr><tr><td>make_heap_(first, last [,op ᵃ])</td><td>MakeHeap_</td></tr><tr><td>sort_heap_(first, last [,op ᵃ])</td><td>SortHeap_</td></tr><tr><td>next_permutation_(first, last [,op ᵃ])</td><td>NextPermutation_</td></tr><tr><td>prev_permutation_(first, last [,op ᵃ])</td><td>PrevPermutation_</td></tr><tr><td>inner_product_(first1, last1, first2, init [,op1ᵃ] [,op2ᵃ]) </td><td>InnerProduct_</td></tr><tr><td>partial_sum_(first, last, output [,opᵃ])</td><td>PartialSum_</td></tr><tr><td>adjacent_difference_(first, last, output [,opᵃ])</td><td>AdjacentDifference_</td></tr><tr><td>replace_(first, last, old_value, new_value)</td><td>Replace_</td></tr><tr><td>replace_if_(first, last, opᵃ, new_value)</td><td>ReplaceIf_</td></tr><tr><td>replace_copy_(first,
last, result, old_value,
+ new_value)</td><td>ReplaceCopy_</td></tr><tr><td>replace_copy_if_(first, last, result, opᵃ, new_value)</td><td>ReplaceCopyIf_</td></tr><tr><td>rotate_(first, middle, last)ᵇ</td><td>Rotate_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ <span class="command"><strong><a name="eUML-STL-container"></a></strong></span>
+ </p><div class="table"><a name="d0e5011"></a><p class="title"><b>Table 10.4. STL container methods</b></p><div class="table-contents"><table summary="STL container methods" border="1"><colgroup><col><col></colgroup><thead><tr><th>STL container methods(common) in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>container::reference front_(container)</td><td>Front_</td></tr><tr><td>container::reference back_(container)</td><td>Back_</td></tr><tr><td>container::iterator begin_(container)</td><td>Begin_</td></tr><tr><td>container::iterator end_(container)</td><td>End_</td></tr><tr><td>container::reverse_iterator rbegin_(container)</td><td>RBegin_</td></tr><tr><td>container::reverse_iterator rend_(container)</td><td>REnd_</td></tr><tr><td>void push_back_(container, value)</td><td>Push_Back_</td></tr><tr><td>void pop_back_(container, value)</td><td>Pop_Back_</td></tr><tr><td>void push_front_(container, value)</td><td>Push_Front_</td></tr><tr><td>void pop_front_(container, va
lue)</td><td>Pop_Front_</td></tr><tr><td>void clear_(container)</td><td>Clear_</td></tr><tr><td>size_type capacity_(container)</td><td>Capacity_</td></tr><tr><td>size_type size_(container)</td><td>Size_</td></tr><tr><td>size_type max_size_(container)</td><td>Max_Size_</td></tr><tr><td>void reserve_(container, value)</td><td>Reserve _</td></tr><tr><td>void resize_(container, value)</td><td>Resize _</td></tr><tr><td>iterator insert_(container, pos, value)</td><td>Insert_</td></tr><tr><td>void insert_( container , pos, first, last)</td><td>Insert_</td></tr><tr><td>void insert_( container , pos, number, value)</td><td>Insert_</td></tr><tr><td>void swap_( container , other_container)</td><td>Swap_</td></tr><tr><td>void erase_( container , pos)</td><td>Erase_</td></tr><tr><td>void erase_( container , first, last) </td><td>Erase_</td></tr><tr><td>bool empty_( container)</td><td>Empty_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5142"></a><p class="title"><b>Table 10.5. STL list methods</b></p><div class="table-contents"><table summary="STL list methods" border="1"><colgroup><col><col></colgroup><thead><tr><th>std::list methods in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>void list_remove_(container, value)</td><td>ListRemove_</td></tr><tr><td>void list_remove_if_(container, opᵃ)</td><td>ListRemove_If_</td></tr><tr><td>void list_merge_(container, other_list)</td><td>ListMerge_</td></tr><tr><td>void list_merge_(container, other_list, opᵃ)</td><td>ListMerge_</td></tr><tr><td>void splice_(container, iterator, other_list)</td><td>Splice_</td></tr><tr><td>void splice_(container, iterator, other_list,
+ iterator)</td><td>Splice_</td></tr><tr><td>void splice_(container, iterator, other_list, first,
+ last)</td><td>Splice_</td></tr><tr><td>void list_reverse_(container)</td><td>ListReverse_</td></tr><tr><td>void list_unique_(container)</td><td>ListUnique_</td></tr><tr><td>void list_unique_(container, opᵃ)</td><td>ListUnique_</td></tr><tr><td>void list_sort_(container)</td><td>ListSort_</td></tr><tr><td>void list_sort_(container, opᵃ)</td><td>ListSort_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5218"></a><p class="title"><b>Table 10.6. STL associative container methods </b></p><div class="table-contents"><table summary="STL associative container methods " border="1"><colgroup><col><col></colgroup><thead><tr><th>Associative container methods in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>iterator insert_(container, pos, value)</td><td>Insert_</td></tr><tr><td>void insert_( container , first, last)</td><td>Insert_</td></tr><tr><td>pair<iterator, bool> insert_( container , value)</td><td>Insert_</td></tr><tr><td>void associative_erase_( container , pos)</td><td>Associative_Erase_</td></tr><tr><td>void associative_erase_( container , first, last)</td><td>Associative_Erase_</td></tr><tr><td>size_type associative_erase_( container , key)</td><td>Associative_Erase_</td></tr><tr><td>iterator associative_find_( container , key)</td><td>Associative_Find_</td></tr><tr><td>size_type associative_count_( container , key)</td><t
d>AssociativeCount_</td></tr><tr><td>iterator associative_lower_bound_( container , key)</td><td>Associative_Lower_Bound_</td></tr><tr><td>iterator associative_upper_bound_( container , key)</td><td>Associative_Upper_Bound_</td></tr><tr><td>pair<iterator, iterator> associative_equal_range_(
+ container , key)</td><td>Associative_Equal_Range_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5289"></a><p class="title"><b>Table 10.7. STL pair</b></p><div class="table-contents"><table summary="STL pair" border="1"><colgroup><col><col></colgroup><thead><tr><th>std::pair in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>first_type first_(pair<T1, T2>)</td><td>First_</td></tr><tr><td>second_type second_(pair<T1, T2>)</td><td>Second_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p>
+ </p><div class="table"><a name="d0e5315"></a><p class="title"><b>Table 10.8. STL string</b></p><div class="table-contents"><table summary="STL string" border="1"><colgroup><col><col><col></colgroup><thead><tr><th>STL string method</th><th>std::string method in container.hpp</th><th>Functor</th></tr></thead><tbody><tr><td>substr (size_type pos, size_type size)</td><td>string substr_(container, pos, length)</td><td>Substr_</td></tr><tr><td>int compare(string)</td><td>int string_compare_(container, another_string)</td><td>StringCompare_</td></tr><tr><td>int compare(char*)</td><td>int string_compare_(container, another_string)</td><td>StringCompare_</td></tr><tr><td>int compare(size_type pos, size_type size, string)</td><td>int string_compare_(container, pos, size,
+ another_string)</td><td>StringCompare_</td></tr><tr><td>int compare (size_type pos, size_type size, string, size_type
+ length)</td><td>int string_compare_(container, pos, size, another_string,
+ length)</td><td>StringCompare_</td></tr><tr><td>string& append(const string&)</td><td>string& append_(container, another_string)</td><td>Append_</td></tr><tr><td>string& append (charT*)</td><td>string& append_(container, another_string)</td><td>Append_</td></tr><tr><td>string& append (string , size_type pos, size_type
+ size)</td><td>string& append_(container, other_string, pos,
+ size)</td><td>Append_</td></tr><tr><td>string& append (charT*, size_type size)</td><td>string& append_(container, another_string,
+ length)</td><td>Append_</td></tr><tr><td>string& append (size_type size, charT)</td><td>string& append_(container, size, char)</td><td>Append_</td></tr><tr><td>string& append (iterator begin, iterator end)</td><td>string& append_(container, begin, end)</td><td>Append_</td></tr><tr><td>string& insert (size_type pos, charT*)</td><td>string& string_insert_(container, pos,
+ other_string)</td><td>StringInsert_</td></tr><tr><td>string& insert(size_type pos, charT*,size_type n)</td><td>string& string_insert_(container, pos, other_string,
+ n)</td><td>StringInsert_</td></tr><tr><td>string& insert(size_type pos,size_type n, charT
+ c)</td><td>string& string_insert_(container, pos, n, c)</td><td>StringInsert_</td></tr><tr><td>string& insert (size_type pos, const string&)</td><td>string& string_insert_(container, pos,
+ other_string)</td><td>StringInsert_</td></tr><tr><td>string& insert (size_type pos, const string&,
+ size_type pos1, size_type n)</td><td>string& string_insert_(container, pos, other_string,
+ pos1, n)</td><td>StringInsert_</td></tr><tr><td>string& erase(size_type pos=0, size_type n=npos)</td><td>string& string_erase_(container, pos, n)</td><td>StringErase_</td></tr><tr><td>string& assign(const string&)</td><td>string& string_assign_(container, another_string)</td><td>StringAssign_</td></tr><tr><td>string& assign(const charT*)</td><td>string& string_assign_(container, another_string)</td><td>StringAssign_</td></tr><tr><td>string& assign(const string&, size_type pos,
+ size_type n)</td><td>string& string_assign_(container, another_string, pos,
+ n)</td><td>StringAssign_</td></tr><tr><td>string& assign(const charT*, size_type n)</td><td>string& string_assign_(container, another_string,
+ n)</td><td>StringAssign_</td></tr><tr><td>string& assign(size_type n, charT c)</td><td>string& string_assign_(container, n, c)</td><td>StringAssign_</td></tr><tr><td>string& assign(iterator first, iterator last)</td><td>string& string_assign_(container, first, last)</td><td>StringAssign_</td></tr><tr><td>string& replace(size_type pos, size_type n, const
+ string&)</td><td>string& string_replace_(container, pos, n,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, const charT*,
+ size_type n1)</td><td>string& string_replace_(container, pos, n,
+ another_string, n1)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, const
+ charT*)</td><td>string& string_replace_(container, pos, n,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(size_type pos, size_type n, size_type n1,
+ charT c)</td><td>string& string_replace_(container, pos, n, n1, c)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ string&)</td><td>string& string_replace_(container, first, last,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ charT*, size_type n)</td><td>string& string_replace_(container, first, last,
+ another_string, n)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, const
+ charT*)</td><td>string& string_replace_(container, first, last,
+ another_string)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, size_type
+ n, charT c)</td><td>string& string_replace_(container, first, last, n,
+ c)</td><td>StringReplace_</td></tr><tr><td>string& replace(iterator first, iterator last, iterator
+ f, iterator l)</td><td>string& string_replace_(container, first, last, f,
+ l)</td><td>StringReplace_</td></tr><tr><td>const charT* c_str()</td><td>const charT* c_str_(container)</td><td>CStr_</td></tr><tr><td>const charT* data()</td><td>const charT* string_data_(container)</td><td>StringData_</td></tr><tr><td>size_type copy(charT* buf, size_type n, size_type pos =
+ 0)</td><td>size_type string_copy_(container, buf, n, pos); size_type
+ string_copy_(container, buf, n) </td><td>StringCopy_</td></tr><tr><td>size_type find(charT* s, size_type pos, size_type n)</td><td>size_type string_find_(container, s, pos, n)</td><td>StringFind_</td></tr><tr><td>size_type find(charT* s, size_type pos=0)</td><td>size_type string_find_(container, s, pos); size_type
+ string_find_(container, s) </td><td>StringFind_</td></tr><tr><td>size_type find(const string& s, size_type pos=0)</td><td>size_type string_find_(container, s, pos) size_type
+ string_find_(container, s) </td><td>StringFind_</td></tr><tr><td>size_type find(charT c, size_type pos=0)</td><td>size_type string_find_(container, c, pos) size_type
+ string_find_(container, c) </td><td>StringFind_</td></tr><tr><td>size_type rfind(charT* s, size_type pos, size_type n)</td><td>size_type string_rfind_(container, s, pos, n)</td><td>StringRFind_</td></tr><tr><td>size_type rfind(charT* s, size_type pos=npos)</td><td>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </td><td>StringRFind_</td></tr><tr><td>size_type rfind(const string& s, size_type
+ pos=npos)</td><td>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </td><td>StringRFind_</td></tr><tr><td>size_type rfind(charT c, size_type pos=npos)</td><td>size_type string_rfind_(container, c, pos) size_type
+ string_rfind_(container, c) </td><td>StringRFind_</td></tr><tr><td>size_type find_first_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_first_of_(container, s, pos, n)</td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (charT* s, size_type pos=0)</td><td>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (const string& s, size_type
+ pos=0)</td><td>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_of (charT c, size_type pos=0)</td><td>size_type find_first_of_(container, c, pos) size_type
+ find_first_of_(container, c) </td><td>StringFindFirstOf_</td></tr><tr><td>size_type find_first_not_of(charT* s, size_type pos,
+ size_type n)</td><td>size_type find_first_not_of_(container, s, pos, n)</td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (charT* s, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (const string& s, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_first_not_of (charT c, size_type
+ pos=0)</td><td>size_type find_first_not_of_(container, c, pos); size_type
+ find_first_not_of_(container, c) </td><td>StringFindFirstNotOf_</td></tr><tr><td>size_type find_last_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_last_of_(container, s, pos, n)</td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (charT* s, size_type pos=npos)</td><td>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (const string& s, size_type
+ pos=npos)</td><td>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_of (charT c, size_type pos=npos)</td><td>size_type find_last_of_(container, c, pos); size_type
+ find_last_of_(container, c) </td><td>StringFindLastOf_</td></tr><tr><td>size_type find_last_not_of(charT* s, size_type pos, size_type
+ n)</td><td>size_type find_last_not_of_(container, s, pos, n)</td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (charT* s, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_of_(container, s) </td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (const string& s, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_not_of_(container, s) </td><td>StringFindLastNotOf_</td></tr><tr><td>size_type find_last_not_of (charT c, size_type
+ pos=npos)</td><td>size_type find_last_not_of_(container, c, pos); size_type
+ find_last_not_of_(container, c) </td><td>StringFindLastNotOf_</td></tr></tbody></table></div></div><p><br class="table-break">
+ </p><p><span class="underline">Notes</span>: </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>ᵃ: algorithms requiring a predicate need to make them eUML compatible
+ by wrapping them inside a Predicate_ functor. For example,
+ std::less<int> => Predicate_<std::less<int> >()</p></li><li class="listitem"><p>ᵇ: If using the SGI STL implementation, these functors use the SGI
+ return value</p></li></ul></div><p>
+ </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch09.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt02.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="re01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 9. eUML operators and basic helpers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Common headers</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/docutils.css
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/docutils.css 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,275 @@
+/*
+:Author: David Goodger
+:Contact: goodger_at_[hidden]
+:Date: $Date: 2007-11-25 19:34:32 +0000 (Sun, 25 Nov 2007) $
+:Revision: $Revision: 41371 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+ border: 0 }
+
+table.borderless td, table.borderless th {
+ /* Override padding for "table.docutils td" with "! important".
+ The right padding separates the table cells. */
+ padding: 0 0.5em 0 0 ! important }
+
+.first {
+ /* Override more specific margin styles with "! important". */
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin-left: 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left {
+ clear: left }
+
+img.align-right {
+ clear: right }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid 1px black;
+ margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+ul.auto-toc {
+ list-style-type: none }
Added: trunk/libs/msm/doc/HTML/examples/AnonymousTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/AnonymousTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,123 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+
+
+ // front-end: define the FSM structure
+ struct my_machine_ : public msm::front::state_machine_def<my_machine_>
+ {
+ // The list of FSM states
+ struct State1 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
+ };
+ struct State2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
+ };
+
+ struct State3 : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State3" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State3" << std::endl;}
+ };
+
+ struct State4 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State4" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State4" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ void State2ToState3(none const&) { std::cout << "my_machine::State2ToState3\n"; }
+ void State3ToState4(none const&) { std::cout << "my_machine::State3ToState4\n"; }
+ // guard conditions
+ bool always_true(none const& evt)
+ {
+ std::cout << "always_true" << std::endl;
+ return true;
+ }
+ bool always_false(none const& evt)
+ {
+ std::cout << "always_false" << std::endl;
+ return false;
+ }
+
+ typedef my_machine_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < State1 , none , State2 >,
+ a_row < State2 , none , State3 , &p::State2ToState3 >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ row < State3 , none , State4 , &p::State3ToState4 , &p::always_true >,
+ g_row < State3 , none , State4 , &p::always_false >,
+ _row < State4 , event1 , State1 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+ void pstate(my_machine const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1());
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/AnonymousTutorialEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/AnonymousTutorialEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,165 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+namespace msm = boost::msm;
+using namespace boost::msm::front::euml;
+
+namespace
+{
+ // events
+ BOOST_MSM_EUML_EVENT(event1)
+
+ BOOST_MSM_EUML_ACTION(State1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State3_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State3_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State4_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State4" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State4_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State4" << std::endl;
+ }
+ };
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( State1_Entry,State1_Exit ),State1)
+ BOOST_MSM_EUML_STATE(( State2_Entry,State2_Exit ),State2)
+ BOOST_MSM_EUML_STATE(( State3_Entry,State3_Exit ),State3)
+ BOOST_MSM_EUML_STATE(( State4_Entry,State4_Exit ),State4)
+
+ // transition actions
+ BOOST_MSM_EUML_ACTION(State2ToState3)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State2ToState3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State3ToState4)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State3ToState4" << std::endl;
+ }
+ };
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(always_true)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "always_true" << std::endl;
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(always_false)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "always_false" << std::endl;
+ return false;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ State2 == State1 ,
+ State3 == State2 / State2ToState3,
+ State4 == State3 [always_true] / State3ToState4,
+ State4 == State3 [always_false],
+ State1 == State4 + event1
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << State1 // Init State
+ ),
+ my_machine_) //fsm name
+
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+ void pstate(my_machine const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/AnonymousTutorialWithFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/AnonymousTutorialWithFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,148 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+
+
+ // front-end: define the FSM structure
+ struct my_machine_ : public msm::front::state_machine_def<my_machine_>
+ {
+ // The list of FSM states
+ struct State1 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
+ };
+ struct State2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
+ };
+
+ struct State3 : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State3" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State3" << std::endl;}
+ };
+
+ struct State4 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State4" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State4" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ struct State2ToState3
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State2ToState3" << std::endl;
+ }
+ };
+ struct State3ToState4
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State3ToState4" << std::endl;
+ }
+ };
+ // guard conditions
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ std::cout << "always_true" << std::endl;
+ return true;
+ }
+ };
+ struct always_false
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ std::cout << "always_false" << std::endl;
+ return true;
+ }
+ };
+
+ typedef my_machine_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State1 , none , State2 >,
+ Row < State2 , none , State3 , State2ToState3 >,
+ Row < State3 , none , State4 , none , always_false >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State3 , none , State4 , State3ToState4 , always_true >,
+ Row < State4 , event1 , State1 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+ void pstate(my_machine const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1());
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/BoostCon09Full.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/BoostCon09Full.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,360 @@
+#include <vector>
+#include <iostream>
+#include <boost/mpl/vector/vector50.hpp>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/back/tools.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ // event which every other event can convert to
+ struct AllSongsPlayed
+ {
+ template <class Event>
+ AllSongsPlayed(Event const&){}
+ };
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(DiskTypeEnum diskType): disc_type(diskType) {}
+ DiskTypeEnum disc_type;
+ };
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ typedef mpl::vector<play> deferred_events;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+ // a state needing a pointer to the containing state machine
+ // and using for this the non-default policy
+ // if policy used, set_sm_ptr is needed
+ struct Stopped : public msm::front::state<default_base_state,msm::front::sm_ptr>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl){m_player=pl;}
+ player_* m_player;
+ };
+ // the player state machine contains a state which is himself a state machine
+ // it demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ struct CDFinished : public msm::front::exit_pseudo_state<AllSongsPlayed>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing::CDFinished" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing::CDFinished" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ void all_songs_played(NextSong const&) { std::cout << "Playing::all_songs_played\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+---------------+------------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >,
+ a_row < Song3 , NextSong , CDFinished , &pl::all_songs_played >
+ // +---------+---------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
+ };
+
+ struct AllOk : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ struct ErrorMode : //public msm::front::terminate_state<>
+ public msm::front::interrupt_state<end_error>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // 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";
+ // generate another event to test the queue
+ //cd.m_player.process_event(play());
+ }
+ void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
+ void end_playback (AllSongsPlayed const&) { std::cout << "player::end_playback\n"; }
+ void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ a_row < Playing::exit_pt<
+ Playing_::CDFinished> , AllSongsPlayed, Stopped , &p::end_playback >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row < ErrorMode ,end_error ,AllOk , &p::report_end_error >
+ // +-------------+---------------+---------+---------------------+----------------------+
+ > {};
+
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+
+ void pstate(player const& p)
+ {
+ typedef player::stt Stt;
+ typedef msm::back::generate_state_set<Stt>::type all_states;
+ static char const* state_names[mpl::size<all_states>::value];
+ // fill the names of the states defined in the state machine
+ mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
+ (msm::back::fill_state_names<Stt>(state_names));
+
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ std::cout << "play is not handled in the current state but is marked as delayed" << std::endl;
+ p.process_event(play()); pstate(p);
+ std::cout << "cd_detected will cause play to be handled also" << std::endl;
+ // will be rejected, wrong disk type
+ p.process_event(cd_detected(DISK_DVD)); pstate(p);
+ // will be accepted, wrong disk type
+ p.process_event(cd_detected(DISK_CD)); pstate(p);
+
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
+ p.process_event(NextSong());pstate(p);
+ // We are now in second song, Flag inactive
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ p.process_event(NextSong());pstate(p);
+ // 2nd song active
+ p.process_event(PreviousSong());pstate(p);
+ // Pause
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // but end_pause is an event activating the History
+ // => keep the last active State (SecondSong)
+ p.process_event(end_pause()); pstate(p);
+ // force an exit by listening all the songs
+ p.process_event(NextSong());
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ // go back to Playing
+ // but play is not leading to Shallow History => do not remember the last active State (SecondSong)
+ // and activate again FirstSong and LightOn
+ p.process_event(play()); pstate(p);
+ p.process_event(error_found()); pstate(p);
+
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(NextSong());pstate(p);
+
+ // the states and events of the higher level FSM (player)
+ typedef player::stt Stt;
+ typedef msm::back::generate_state_set<Stt>::type simple_states;
+
+ std::cout << "the state list:" << std::endl;
+ mpl::for_each<simple_states,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+
+ std::cout << "the event list:" << std::endl;
+ typedef msm::back::generate_event_set<Stt>::type event_list;
+ mpl::for_each<event_list,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+ std::cout << std::endl;
+
+ // the states and events recursively searched
+ typedef msm::back::recursive_get_transition_table<player>::type recursive_stt;
+
+ std::cout << "the state list (including sub-SMs):" << std::endl;
+
+ typedef msm::back::generate_state_set<recursive_stt>::type all_states;
+ mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+
+ std::cout << "the event list (including sub-SMs):" << std::endl;
+ typedef msm::back::generate_event_set<recursive_stt>::type all_events;
+ mpl::for_each<all_events,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
+
Added: trunk/libs/msm/doc/HTML/examples/CompilerStressTestEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/CompilerStressTestEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,436 @@
+#include <vector>
+#include <list>
+#include <set>
+#include <map>
+#include <iostream>
+
+// we need more than the default 10 states
+#define FUSION_MAX_VECTOR_SIZE 15
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+#include <boost/msm/front/euml/stl.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// how long the timer will ring when countdown elapsed.
+#define RINGING_TIME 5
+
+namespace // Concrete FSM implementation
+{
+ // flag
+ BOOST_MSM_EUML_FLAG(SomeFlag)
+
+ // declares attributes with type and name. Can be used anywhere after
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_song_id)
+
+ // declare that a type inheriting from OneSongDef will get these 2 attributes
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song << m_song_id ), OneSongDef)
+ // events
+ // this event is done "manually", not using any predefined macro
+ struct OneSong_impl : euml_event<OneSong_impl>,OneSongDef
+ {
+ OneSong_impl(){}
+ OneSong_impl(const string& asong)
+ {
+ get_attribute(m_song)=asong;
+ get_attribute(m_song_id)=1;
+ }
+ OneSong_impl(const OneSong_impl& asong)
+ {
+ get_attribute(m_song)=asong.get_attribute(m_song);
+ get_attribute(m_song_id)=1;
+ }
+ const string& get_data() const {return get_attribute(m_song);}
+ };
+ // declare an instance for use in the transition table
+ OneSong_impl const OneSong;
+
+ struct SongComparator : euml_action<SongComparator>
+ {
+ bool operator()(const OneSong_impl& lhs,const OneSong_impl& rhs)const
+ {
+ return lhs.get_data() == rhs.get_data();
+ }
+ };
+ struct SongLessComparator : euml_action<SongLessComparator>
+ {
+ bool operator()(const OneSong_impl& lhs,const OneSong_impl& rhs)const
+ {
+ return lhs.get_data() < rhs.get_data();
+ }
+ };
+ struct Comparator
+ {
+ template <class T>
+ bool operator()(const T& lhs,const T& rhs)const
+ {
+ return lhs < rhs;
+ }
+ };
+ struct RemoveDummy
+ {
+ bool operator()(const OneSong_impl& lhs)const
+ {
+ return (lhs.get_attribute(m_song).compare(std::string("She-Dummy. Remove this one"))==0 );
+ }
+ };
+ template <int val>
+ struct LookFor
+ {
+ template <class T>
+ bool operator()(const T& lhs)const
+ {
+ return lhs == val;
+ }
+ };
+ template <int val>
+ struct LessThan
+ {
+ template <class T>
+ bool operator()(const T& lhs)const
+ {
+ return lhs < val;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SongDeleter)
+ {
+ bool operator()(const OneSong_impl& lhs)const
+ {
+ return lhs.get_data() == "Twist and Shout";
+ }
+ };
+ struct Generator
+ {
+ int operator()()const
+ {
+ return 1;
+ }
+ };
+ struct Print
+ {
+ template <class T>
+ void operator()(const T& lhs)const
+ {
+ std::cout << "Song:" << lhs.get_data() << endl;
+ }
+ };
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), NotFoundDef)
+ // declare an event instance called NotFound with the defined attributes
+ // these attributes can then be referenced anywhere (stt, state behaviors)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(NotFound,NotFoundDef)
+
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)
+ struct Found_impl : euml_event<Found_impl>,FoundDef
+ {
+ Found_impl(){}
+ Found_impl (const string& data)
+ {
+ get_attribute(m_song)=data;
+ }
+ int foo()const {std::cout << "foo()" << std::endl; return 0;}
+ int foo(int i)const {std::cout << "foo(int):" << i << std::endl; return 1;}
+ int foo(int i,int j)const {std::cout << "foo(int,int):" << i <<"," << j << std::endl; return 2;}
+
+ };
+ Found_impl const Found;
+ // some functions to call
+ // this macro creates a functor and an eUML function wrapper. Now, foo_ can be used anywhere
+ BOOST_MSM_EUML_METHOD(FoundFoo_ , foo , foo_ , int , int )
+
+ template <class T>
+ int do_print(T& t ) {std::cout << "print(T):" << typeid(T).name() << std::endl;return 1;}
+ BOOST_MSM_EUML_FUNCTION(PrintState_ , do_print , print_ , int , int )
+
+ BOOST_MSM_EUML_EVENT(Done)
+
+ // Concrete FSM implementation
+ struct some_base
+ {
+ int foobar()const {std::cout << "foobar()" << std::endl; return 0;}
+ int foobar(int i)const {std::cout << "foobar(int):" << i << std::endl; return 1;}
+ int foobar(int i,int j)const {std::cout << "foobar(int,int):" << i <<"," << j << std::endl; return 2;}
+ };
+ // some functions to call
+ BOOST_MSM_EUML_METHOD(FooBar_ , foobar , foobar_ , int , int )
+
+ // fsm attributes
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_src_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<OneSong_impl>,m_tgt_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<int>,m_var2)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<int>,m_var3)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(set<int>,m_var4)
+ typedef std::map<int,int> int_int_map;
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int_int_map,m_var5)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_var6)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_var7)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<int>,m_var8)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<int>,m_var9)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_var10)
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( ( insert_(fsm_(m_tgt_container),end_(fsm_(m_tgt_container)),
+ append_(event_(m_song),fsm_(m_var7)) ),//foo_(event_,Int_<0>()) ,
+ //foo_(event_,Int_<0>(),Int_<1>()),print_(state_),
+ process_(Done/*,fsm_*/),if_then_(true_,true_) ),
+ no_action
+ ),Insert)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_letters)
+ BOOST_MSM_EUML_STATE(( if_then_else_( (string_find_(event_(m_song),state_(m_letters),Size_t_<0>()) != Npos_<string>()&&
+ string_find_(event_(m_song),Char_<'S'>(),Size_t_<0>()) != Npos_<string>()&&
+ string_find_first_of_(event_(m_song),Char_<'S'>()) == Size_t_<0>() &&
+ string_compare_(event_(m_song),Int_<0>(),size_(event_(m_song)),event_(m_song)) == Int_<0>()
+ //&& is_flag_(SomeFlag(),fsm_())
+ //&& ( event_(m_song_id) == Int_<1>())
+ //&& string_find_(event_(m_song),String_<mpl::string<'Sh','e'> >())
+ // != Npos_<string>()
+
+ ),
+ process2_(Found,
+ //string_insert_(event_(m_song),Size_t_<0>(),fsm_(m_var6)) ),
+ string_replace_(
+ string_assign_(
+ string_erase_(
+ string_insert_(
+ substr_(event_(m_song),Size_t_<1>()),
+ Size_t_<0>(),
+ Size_t_<1>(),
+ Char_<'S'>()),
+ Size_t_<0>(),
+ Size_t_<1>() ),
+ event_(m_song) ),
+ Size_t_<0>(),
+ Size_t_<1>(),
+ c_str_(fsm_(m_var6))
+ /*Size_t_<1>(),
+ Char_<'s'>()*/ ) ),
+ process2_(NotFound,event_(m_song),fsm_) ) ,
+ no_action,
+ attributes_ << m_letters,
+ configure_<< SomeFlag ),StringFind)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>::iterator,m_src_it)
+ BOOST_MSM_EUML_STATE(( if_then_( (state_(m_src_it) != end_(fsm_(m_src_container)) &&
+ //associative_find_(fsm_(m_var4),Int_<9>()) != end_(fsm_(m_var4))&&
+ //associative_count_(fsm_(m_var4),Int_<9>()) == Size_t_<1>() &&
+ //*associative_upper_bound_(fsm_(m_var4),Int_<8>()) == Int_<9>()&&
+ //*associative_lower_bound_(fsm_(m_var4),Int_<9>()) == Int_<9>() &&
+ //second_(associative_equal_range_(fsm_(m_var4),Int_<8>())) == associative_upper_bound_(fsm_(m_var4),Int_<8>()) &&
+ //first_(associative_equal_range_(fsm_(m_var4),Int_<8>())) == associative_lower_bound_(fsm_(m_var4),Int_<8>())&&
+ //second_(*associative_lower_bound_(fsm_(m_var5),Int_<0>())) == Int_<0>() && //map => pair as return
+ //find_if_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<LookFor<8> >()) != end_(fsm_(m_var4))&&
+ //*lower_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >()) == Int_<9>()&&
+ //*upper_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>(),Predicate_<std::less<int> >()) == Int_<9>() &&
+ //second_(equal_range_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>()))
+ // == upper_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>()) &&
+ //first_(equal_range_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >()))
+ // == lower_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >())&&
+ //binary_search_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >())&&
+ //binary_search_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>())&&
+ //count_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>()) == Int_<1>()&&
+ //count_if_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<LookFor<9> >()) == Int_<1>()&&
+ //distance_(begin_(fsm_(m_var4)),end_(fsm_(m_var4))) == Int_<2>()&&
+ //*min_element_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<std::less<int> >()) == Int_<8>()&&
+ //*max_element_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<std::less<int> >()) == Int_<9>()&&
+ //adjacent_find_(begin_(fsm_(m_var4)),end_(fsm_(m_var4))) == end_(fsm_(m_var4))&&
+ //*find_end_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
+ // == Int_<1>()&&
+ //*find_first_of_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
+ // == Int_<1>()&&
+ //equal_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),begin_(fsm_(m_var8)))&&
+ //*search_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
+ // == Int_<1>()&&
+ //includes_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))&&
+ //!lexicographical_compare_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),
+ // begin_(fsm_(m_var9)),end_(fsm_(m_var9)))&&
+ //first_(mismatch_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),begin_(fsm_(m_var8))))
+ // == end_(fsm_(m_var9)) &&
+ accumulate_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),Int_<1>(),
+ Predicate_<std::plus<int> >()) == Int_<1>()
+ ),
+ (process2_(OneSong,*(state_(m_src_it)++))/*,foobar_(fsm_,Int_<0>())*/ ) ),
+ no_action,
+ attributes_ << m_src_it
+ , configure_<< SomeFlag ),Foreach)
+
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ StringFind == Foreach + OneSong[if_then_else_(true_,true_,true_)],
+ Insert == StringFind + Found / (if_then_(true_,no_action)),
+ Foreach == StringFind + NotFound ,
+ Foreach == Insert + Done
+ // +------------------------------------------------------------------------------+
+ ),transition_table )
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Foreach, // Init
+ //insert_(state_(m_var4),begin_(state_(m_var2)),end_(state_(m_var2))),
+ (insert_(state_(m_var4),Int_<5>()),insert_(state_(m_var4),Int_<6>()),insert_(state_(m_var4),Int_<7>()),
+ insert_(state_(m_var4),Int_<8>()),insert_(state_(m_var4),Int_<9>()),
+ associative_erase_(state_(m_var4),Int_<6>()),associative_erase_(state_(m_var4),begin_(state_(m_var4))),
+ associative_erase_(state_(m_var4),begin_(state_(m_var4)),++begin_(state_(m_var4))),
+ insert_(state_(m_var2),begin_(state_(m_var2)),begin_(state_(m_var3)),end_(state_(m_var3))),
+ state_(m_var5)[Int_<0>()]=Int_<0>(),state_(m_var5)[Int_<1>()]=Int_<1>()
+ ,attribute_(substate_(Foreach,fsm_),m_src_it)
+ = begin_(fsm_(m_src_container))
+ //,fill_(begin_(state_(m_var9)),end_(state_(m_var9)),Int_<0>())
+ //,fill_n_(begin_(state_(m_var9)),Size_t_<2>(),Int_<0>())
+ //,transform_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var2)),begin_(state_(m_var4)),
+ // Predicate_<std::plus<int> >())
+ //,process_(Done,fsm_(),fsm_)
+ //,process_(Done,fsm_)
+ //,fsm_
+ //,foobar_(state_,Int_<0>(),Int_<1>())
+ //,nth_element_(begin_(state_(m_var9)),++begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,partial_sort_(begin_(state_(m_var9)),end_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,partial_sort_copy_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,list_sort_(state_(m_var2))
+ //,sort_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,inner_product_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),Int_<1>())
+ //,replace_copy_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var4)),Int_<8>(),Int_<7>())
+ //,replace_copy_if_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var4)),Predicate_<LookFor<9> >(),Int_<8>())
+ //,replace_(begin_(state_(m_var4)),end_(state_(m_var4)),Int_<8>(),Int_<7>())
+ //,replace_if_(begin_(state_(m_var4)),end_(state_(m_var4)),Predicate_<LookFor<9> >(),Int_<8>())
+ //,adjacent_difference_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
+ //,partial_sum_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
+ //,inner_product_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),Int_<1>())
+ //,next_permutation_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,prev_permutation_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,set_union_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
+ //,inplace_merge_(begin_(state_(m_var9)),end_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,merge_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9))
+ // ,begin_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,stable_sort_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,partition_(begin_(state_(m_var2)),end_(state_(m_var2)),Predicate_<LessThan<3> >())
+ //,stable_partition_(begin_(state_(m_var2)),end_(state_(m_var2)),Predicate_<LessThan<3> >())
+ //,rotate_copy_(begin_(state_(m_var2)),++begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
+ //,rotate_(begin_(state_(m_var2)),++begin_(state_(m_var2)),end_(state_(m_var2)))
+ //,unique_(begin_(state_(m_var2)),end_(state_(m_var2)))
+ //,unique_copy_(begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
+ //,random_shuffle_(begin_(state_(m_var9)),end_(state_(m_var9)))
+ //,generate_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<Generator>())
+ //,generate_n_(begin_(state_(m_var9)),Int_<2>(),Predicate_<Generator>())
+ //,reverse_copy_(begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
+ //erase_(state_(m_src_container),
+ // remove_if_(begin_(state_(m_src_container)),end_(state_(m_src_container)),
+ // Predicate_<RemoveDummy>()),
+ // end_(state_(m_src_container))),
+ //list_remove_(state_(m_var2),Int_<3>()),
+ //remove_copy_if_(begin_(state_(m_var9)),end_(state_(m_var9)),back_inserter_(state_(m_var2)),
+ // Predicate_<LookFor<2> >() )
+ //for_each_(begin_(state_(m_src_container)),end_(state_m_src_container()),
+ // Predicate_<Print>() ),
+ //copy_(begin_(state_(m_var9)),end_(state_(m_var9)),inserter_(state_(m_var2),end_(state_(m_var2)))),
+ //reverse_(begin_(state_(m_var2)),end_(state_(m_var2)))
+ ),
+ //no_action, // Entry
+ //splice_(state_(m_var2),begin_(state_(m_var2)),state_(m_var3),begin_(state_(m_var3)),end_(state_(m_var3))),
+ //(list_remove_(state_(m_var2),Int_<3>()),list_merge_(state_(m_var2),state_(m_var3),Comparator())),//no_action, // Entry
+ no_action, // Exit
+ attributes_ << m_src_container // song list
+ << m_tgt_container // result
+ << m_var2
+ << m_var3
+ << m_var4
+ << m_var5
+ << m_var6
+ << m_var7
+ << m_var8
+ << m_var9
+ << m_var10,
+ configure_<< no_configure_,
+ Log_No_Transition
+ ),iPodSearch_helper)
+
+ struct iPodSearch_ : public iPodSearch_helper, public some_base
+ {
+ };
+
+
+ // choice of back-end
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+
+ void test()
+ {
+ iPodSearch search;
+ // fill our song list
+ //search.get_attribute<m_src_container>().push_back(OneSong("She-Dummy. Remove this one"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("Let it be"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("Yellow submarine"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("Twist and Shout"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("She Loves You"));
+
+ search.get_attribute(m_var2).push_back(1);
+ search.get_attribute(m_var2).push_back(3);
+ search.get_attribute(m_var2).push_back(4);
+
+ search.get_attribute(m_var3).push_back(2);
+ search.get_attribute(m_var3).push_back(4);
+
+ search.get_attribute(m_var6) = "S";
+ search.get_attribute(m_var7) = "- Some text";
+
+ search.get_attribute(m_var8).push_back(1);
+ search.get_attribute(m_var8).push_back(2);
+ search.get_attribute(m_var8).push_back(3);
+ search.get_attribute(m_var8).push_back(4);
+
+ search.get_attribute(m_var9).push_back(1);
+ search.get_attribute(m_var9).push_back(2);
+
+
+ // look for "She Loves You" using the first letters
+ // BOOST_MSM_EUML_STATE_NAME returns the name of the event type of which StringFind is an instance
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="Sh";
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ search.start();
+ // display all the songs
+ for (list<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_data() << endl;
+ }
+ for (list<int>::const_iterator iti = search.get_attribute(m_var2).begin();
+ iti != search.get_attribute(m_var2).end();++iti)
+ {
+ cout << "int in attribute m_var2:" << (*iti) << endl;
+ }
+ for (set<int>::const_iterator its = search.get_attribute(m_var4).begin();
+ its != search.get_attribute(m_var4).end();++its)
+ {
+ cout << "int in attribute m_var4:" << (*its) << endl;
+ }
+ cout << "search using more letters" << endl;
+ // look for "She Loves You" using more letters
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="She";
+ search.get_attribute(m_tgt_container).clear();
+ search.start();
+ // display all the songs
+ for (list<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_data() << endl;
+ }
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/CompositeTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/CompositeTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,223 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+ p.process_event(play());
+
+ // at this point, Play is active
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/CompositeTutorialEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/CompositeTutorialEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,172 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(region2_evt)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+
+
+ // Playing is now a state machine itself.
+
+ // It has 5 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+ BOOST_MSM_EUML_STATE(( Region2State1_Entry,Region2State1_Exit ),Region2State1)
+ BOOST_MSM_EUML_STATE(( Region2State2_Entry,Region2State2_Exit ),Region2State2)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song,
+ Region2State2 == Region2State1 + region2_evt
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1 << Region2State1 // Init State
+ ),Playing_)
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format &&(event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
+ // you now have less to type.
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play);
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/DirectEntryEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/DirectEntryEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,376 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(event1)
+ BOOST_MSM_EUML_EVENT(event2)
+ BOOST_MSM_EUML_EVENT(event3)
+ BOOST_MSM_EUML_EVENT(event4)
+ BOOST_MSM_EUML_EVENT(event5)
+ // if we need something special, like a template constructor, we cannot use the helper macros
+ struct event6_impl : euml_event<event6_impl>
+ {
+ event6_impl(){}
+ template <class Event>
+ event6_impl(Event const&){}
+ };
+ event6_impl const event6;
+
+ //Sub fsm state definition
+ BOOST_MSM_EUML_ACTION(SubState1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState1_Entry,SubState1_Exit ),SubState1)
+
+ BOOST_MSM_EUML_ACTION(SubState1b_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState1b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState1b_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState1b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState1b_Entry,SubState1b_Exit ),SubState1b)
+
+ BOOST_MSM_EUML_ACTION(SubState1c_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState1c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState1c_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState1c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState1c_Entry,SubState1c_Exit ),SubState1c)
+
+ BOOST_MSM_EUML_ACTION(SubState2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0,( SubState2_Entry,SubState2_Exit ),SubState2)
+
+ BOOST_MSM_EUML_ACTION(SubState2b_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState2b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState2b_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState2b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(1,( SubState2b_Entry,SubState2b_Exit ),SubState2b)
+
+ BOOST_MSM_EUML_ACTION(SubState2c_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState2c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState2c_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState2c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(2,( SubState2c_Entry,SubState2c_Exit ),SubState2c)
+
+ BOOST_MSM_EUML_ACTION(PseudoEntry1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::PseudoEntry1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(PseudoEntry1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::PseudoEntry1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ENTRY_STATE(0,( PseudoEntry1_Entry,PseudoEntry1_Exit ),PseudoEntry1)
+
+ BOOST_MSM_EUML_ACTION(SubState3_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState3_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState3_Entry,SubState3_Exit ),SubState3)
+
+ BOOST_MSM_EUML_ACTION(SubState3b_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState3b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState3b_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState3b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState3b_Entry,SubState3b_Exit ),SubState3b)
+
+ BOOST_MSM_EUML_ACTION(PseudoExit1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::PseudoExit1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(PseudoExit1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::PseudoExit1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXIT_STATE(( event6,PseudoExit1_Entry,PseudoExit1_Exit ),PseudoExit1)
+
+ // actions
+ BOOST_MSM_EUML_ACTION(entry_action)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(FSM& ,EVT const& ,SourceState& ,TargetState& )
+ {
+ cout << "calling entry_action" << endl;
+ }
+ };
+ // SubFsm definition
+ BOOST_MSM_EUML_ACTION(SubFsm2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubFsm2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ SubState3 == PseudoEntry1 + event4 / entry_action ,
+ SubState1 == SubState2 + event6 ,
+ PseudoExit1 == SubState3 + event5
+ // +------------------------------------------------------------------------------+
+ ), SubFsm2_transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (SubFsm2_transition_table, //STT
+ init_ << SubState1 << SubState1b << SubState1c, // Init State
+ SubFsm2_Entry, // Entry
+ SubFsm2_Exit
+ ),SubFsm2_def)
+ // inherit to add some typedef
+ struct SubFsm2_ : public SubFsm2_def
+ {
+ // these 2 states are not found in the transition table because they are accessed only through
+ // a fork, so we need to create them explicitly
+ typedef mpl::vector<BOOST_MSM_EUML_STATE_NAME(SubState2b),
+ BOOST_MSM_EUML_STATE_NAME(SubState2c)> explicit_creation;
+ };
+
+ // back-end
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2_type;
+ SubFsm2_type const SubFsm2;
+
+ // Fsm state definitions
+ BOOST_MSM_EUML_ACTION(State1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( State1_Entry,State1_Exit ),State1)
+
+ BOOST_MSM_EUML_ACTION(State2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( State2_Entry,State2_Exit ),State2)
+
+ // Fsm definition
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ SubFsm2 == State1 + event1 ,
+ explicit_(SubFsm2,SubState2) == State1 + event2,
+ (explicit_(SubFsm2,SubState2),
+ explicit_(SubFsm2,SubState2b),
+ explicit_(SubFsm2,SubState2c)) == State1 + event3 ,
+ entry_pt_(SubFsm2,PseudoEntry1) == State1 + event4 ,
+ State1 == SubFsm2 + event1 ,
+ State2 == exit_pt_
+ (SubFsm2,PseudoExit1) + event6
+ // +------------------------------------------------------------------------------+
+ ),transition_table )
+
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const& e,FSM&,STATE& )
+ {
+ std::cout << "no transition in Fsm"
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << State1, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ Fsm_) //fsm name
+
+ //back-end
+ typedef msm::back::state_machine<Fsm_> Fsm;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "SubFsm2","State2" };
+ void pstate(Fsm const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ Fsm p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "Simply move in and out of the composite, activate init states" << std::endl;
+ p.process_event(event1); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "Direct entry into SubFsm2::SubState2, then transition to SubState1 and back to State1" << std::endl;
+ p.process_event(event2); pstate(p);
+ p.process_event(event6); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "processing fork to SubFsm2::SubState2, SubFsm2::SubState2b and SubFsm2::SubState2c" << std::endl;
+ p.process_event(event3); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "processing entry pseudo state" << std::endl;
+ p.process_event(event4); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "processing entry + exit pseudo state" << std::endl;
+ p.process_event(event4); pstate(p);
+ std::cout << "using exit pseudo state" << std::endl;
+ p.process_event(event5); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/DirectEntryTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/DirectEntryTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,211 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct event1 {};
+ struct event2 {};
+ struct event3 {};
+ struct event4 {};
+ struct event5 {};
+ struct event6
+ {
+ event6(){}
+ template <class Event>
+ event6(Event const&){}
+ };
+ // front-end: define the FSM structure
+ struct Fsm_ : public msm::front::state_machine_def<Fsm_>
+ {
+ // The list of FSM states
+ struct State1 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
+ };
+ struct State2 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
+ };
+ struct SubFsm2_ : public msm::front::state_machine_def<SubFsm2_>
+ {
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2" << std::endl;}
+
+ struct SubState1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState1" << std::endl;}
+ };
+ struct SubState1b : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState1b" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState1b" << std::endl;}
+ };
+ struct SubState2 : public msm::front::state<> , public msm::front::explicit_entry<0>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState2" << std::endl;}
+ };
+ struct SubState2b : public msm::front::state<> , public msm::front::explicit_entry<1>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState2b" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState2b" << std::endl;}
+ };
+ // test with a pseudo entry
+ struct PseudoEntry1 : public msm::front::entry_pseudo_state<0>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::PseudoEntry1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::PseudoEntry1" << std::endl;}
+ };
+ struct SubState3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState3" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState3" << std::endl;}
+ };
+ struct SubState3b : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState3b" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState3b" << std::endl;}
+ };
+ struct PseudoExit1 : public msm::front::exit_pseudo_state<event6>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::PseudoExit1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::PseudoExit1" << std::endl;}
+ };
+ // action methods
+ void entry_action(event4 const&)
+ {
+ std::cout << "calling entry_action" << std::endl;
+ }
+ // the initial state. Must be defined
+ typedef mpl::vector<SubState1,SubState1b> initial_state;
+
+ typedef mpl::vector<SubState2b> explicit_creation;
+
+ // Transition table for SubFsm2
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +--------------+-------------+------------+------------------------+----------------------+
+ a_row < PseudoEntry1 , event4 , SubState3 ,&SubFsm2_::entry_action >,
+ _row < SubState2 , event6 , SubState1 >,
+ _row < SubState3 , event5 , PseudoExit1 >
+ // +--------------+-------------+------------+------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2;
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ // guard conditions
+
+ // Transition table for Fsm
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------------------+--------+------------------------------------+-------+--------+
+ _row < State1 , event1 , SubFsm2 >,
+ _row < State1 , event2 , SubFsm2::direct<SubFsm2_::SubState2> >,
+ _row < State1 , event3 , mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
+ SubFsm2::direct<SubFsm2_::SubState2b> > >,
+ _row < State1 , event4 , SubFsm2::entry_pt
+ <SubFsm2_::PseudoEntry1> >,
+ // +---------------------+--------+------------------------------------+-------+--------+
+ _row < SubFsm2 , event1 , State1 >,
+ _row < SubFsm2::exit_pt
+ <SubFsm2_::PseudoExit1>, event6 , State2 >
+ // +---------------------+--------+------------------------------------+-------+--------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Fsm_> Fsm;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "SubFsm2","State2" };
+ void pstate(Fsm const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ Fsm p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "Simply move in and out of the composite, activate init states" << std::endl;
+ p.process_event(event1()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "Direct entry into SubFsm2::SubState2, then transition to SubState1 and back to State1" << std::endl;
+ p.process_event(event2()); pstate(p);
+ p.process_event(event6()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "processing fork to SubFsm2::SubState2 and SubFsm2::SubState2b" << std::endl;
+ p.process_event(event3()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "processing entry pseudo state" << std::endl;
+ p.process_event(event4()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "processing entry + exit pseudo state" << std::endl;
+ p.process_event(event4()); pstate(p);
+ std::cout << "using exit pseudo state" << std::endl;
+ p.process_event(event5()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/EumlInternal.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/EumlInternal.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,144 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+using namespace boost::msm::front;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(internal_event)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+ BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ Open + open_close [internal_guard1] / internal_action1,
+ Open + open_close [internal_guard2] / internal_action2,
+ Open + internal_event / internal_action ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ std::cout << "sending internal event (not rejected)" << std::endl;
+ p.process_event(internal_event);
+ std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/EumlInternalDistributed.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/EumlInternalDistributed.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,208 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+using namespace boost::msm::front;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ // note that unlike the SimpleTutorial, events must derive from euml_event.
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(internal_event)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+
+ // we just declare a state type but do not create any instance as we want to inherit from this type
+ BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
+ // derive to be able to add an internal transition table
+ struct Open_impl : public Open_def
+ {
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ open_close [internal_guard1] / internal_action1 ,
+ open_close [internal_guard2] / internal_action2 ,
+ internal_event / internal_action
+ ))
+ };
+ // declare an instance for the stt as we are manually declaring a state
+ Open_impl const Open;
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+
+ // Playing is a state machine itself.
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1 // Init State
+ ),Playing_def)
+
+ // some action for the internal transition
+ BOOST_MSM_EUML_ACTION(playing_internal_action)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Playing::internal action" << endl;
+ }
+ };
+ // derive to be able to add an internal transition table
+ struct Playing_ : public Playing_def
+ {
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ internal_event / playing_internal_action
+ ))
+ };
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Stopped + play / start_playback == Playing ,
+ Stopped + open_close / open_drawer == Open ,
+ Stopped + stop == Stopped ,
+ // +------------------------------------------------------------------------------+
+ Open + open_close / close_drawer == Empty ,
+ // +------------------------------------------------------------------------------+
+ Empty + open_close / open_drawer == Open ,
+ Empty + cd_detected
+ [good_disk_format&&(event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play))
+ == Stopped ,
+ // +------------------------------------------------------------------------------+
+ Playing + stop / stop_playback == Stopped ,
+ Playing + pause / pause_playback == Paused ,
+ Playing + open_close / stop_and_open == Open ,
+ // +------------------------------------------------------------------------------+
+ Paused + end_pause / resume_playback == Playing ,
+ Paused + stop / stop_playback == Stopped ,
+ Paused + open_close / stop_and_open == Open
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ std::cout << "sending internal event (not rejected)" << std::endl;
+ p.process_event(internal_event);
+ std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+ // at this point, Play is active
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+ // event handled internally in Playing, without region checking
+ std::cout << "sending internal event (not rejected)" << std::endl;
+ p.process_event(internal_event);
+
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/EumlSimple.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/EumlSimple.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,215 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+
+#include "stdafx.h"
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+#include <boost/msm/front/euml/stl.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front::euml;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(cd_detected)
+
+ BOOST_MSM_EUML_ACTION(start_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(open_drawer)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(close_drawer)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(store_cd_info)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& fsm ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(stop_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(pause_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(resume_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(stop_and_open)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(stopped_again)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE((),Empty)
+ BOOST_MSM_EUML_STATE((),Open)
+ BOOST_MSM_EUML_STATE((),Stopped)
+ BOOST_MSM_EUML_STATE((),Playing)
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer ,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer ,
+ Open == Paused + open_close / stop_and_open ,
+ Open == Stopped + open_close / open_drawer ,
+ Open == Playing + open_close / stop_and_open ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback ,
+ Stopped == Paused + stop / stop_playback ,
+ Stopped == Empty + cd_detected / store_cd_info ,
+ Stopped == Stopped + stop / stopped_again
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_exception << no_msg_queue, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(open_close);
+ p2.process_event(open_close);
+ p2.process_event(cd_detected);
+ p2.process_event(play);
+ p2.process_event(pause);
+ // go back to Playing
+ p2.process_event(end_pause);
+ p2.process_event(pause);
+ p2.process_event(stop);
+ // event leading to the same state
+ p2.process_event(stop);
+ p2.process_event(open_close);
+ p2.process_event(open_close);
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/Flags.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/Flags.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,244 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+ p.process_event(play());
+
+ // at this point, Play is active
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/History.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/History.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,230 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ };
+ // back-end
+ // demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+ p.process_event(play());
+
+ // at this point, Play is active
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // as you see, remembers the original state as end_pause is an history trigger
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+ // play does not trigger shallow history => start back from 1st song
+ p.process_event(play()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/HistoryEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/HistoryEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,170 @@
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+ // The list of FSM states
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+
+
+ // Playing is now a state machine itself.
+
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ // VC9 cannot compile the typedef with build_sm if one is also used for player
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1 // Init State
+ ),Playing_)
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_,
+ msm::back::ShallowHistory<mpl::vector<BOOST_MSM_EUML_EVENT_NAME(end_pause)> > > Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ // as you see, remembers the original state as end_pause is an history trigger
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(play); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/MsmComposite.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/MsmComposite.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,236 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct cd_detected{};
+ struct NextSong {};
+ struct PreviousSong {};
+
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<> {};
+ struct Song2 : public msm::front::state<> {};
+ struct Song3 : public msm::front::state<> {};
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { /*std::cout << "Playing::start_next_song\n";*/ }
+ void start_prev_song(PreviousSong const&) { /*std::cout << "Playing::start_prev_song\n"; */}
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) { }
+ void open_drawer(open_close const&) { }
+ void close_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const& cd) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&) {}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ test_fsm::player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::cd_detected());
+ p2.process_event(test_fsm::play());
+ for (int j=0;j<100;++j)
+ {
+ p2.process_event(test_fsm::NextSong());
+ p2.process_event(test_fsm::NextSong());
+ p2.process_event(test_fsm::PreviousSong());
+ p2.process_event(test_fsm::PreviousSong());
+ }
+
+ p2.process_event(test_fsm::pause());
+ // go back to Playing
+ p2.process_event(test_fsm::end_pause());
+ p2.process_event(test_fsm::pause());
+ p2.process_event(test_fsm::stop());
+ // event leading to the same state
+ p2.process_event(test_fsm::stop());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/MsmSimple.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/MsmSimple.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,192 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct cd_detected{};
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Playing" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Playing" << std::endl;*/}
+ };
+
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+ // transition actions
+ void start_playback(play const&) { }
+ void open_drawer(open_close const&) { }
+ void close_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const& cd) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&) {}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Stopped , play , Playing >,
+ _row < Stopped , open_close , Open >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Open , open_close , Empty >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Empty , open_close , Open >,
+ _row < Empty , cd_detected , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Playing , stop , Stopped >,
+ _row < Playing , pause , Paused >,
+ _row < Playing , open_close , Open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Paused , end_pause , Playing >,
+ _row < Paused , stop , Stopped >,
+ _row < Paused , open_close , Open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ test_fsm::player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::cd_detected());
+ p2.process_event(test_fsm::play());
+ p2.process_event(test_fsm::pause());
+ // go back to Playing
+ p2.process_event(test_fsm::end_pause());
+ p2.process_event(test_fsm::pause());
+ p2.process_event(test_fsm::stop());
+ // event leading to the same state
+ p2.process_event(test_fsm::stop());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/MsmSimpleFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/MsmSimpleFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,244 @@
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct cd_detected{};
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Playing" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Playing" << std::endl;*/}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+ // transition actions
+ struct start_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct open_drawer
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct close_drawer
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct store_cd_info
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& fsm ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stop_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct pause_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct resume_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stop_and_open
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stopped_again
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ // guard conditions
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Stopped , play , Playing , start_playback >,
+ Row < Stopped , open_close , Open , open_drawer >,
+ Row < Stopped , stop , Stopped , stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer >,
+ Row < Empty , cd_detected , Stopped , store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback >,
+ Row < Playing , pause , Paused , pause_playback >,
+ Row < Playing , open_close , Open , stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback >,
+ Row < Paused , stop , Stopped , stop_playback >,
+ Row < Paused , open_close , Open , stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+ test_fsm::player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::cd_detected());
+ p2.process_event(test_fsm::play());
+ p2.process_event(test_fsm::pause());
+ // go back to Playing
+ p2.process_event(test_fsm::end_pause());
+ p2.process_event(test_fsm::pause());
+ p2.process_event(test_fsm::stop());
+ // event leading to the same state
+ p2.process_event(test_fsm::stop());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/Orthogonal-deferred.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/Orthogonal-deferred.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,292 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // if the play event arrives in this state, defer it until a state handles it or
+ // rejects it
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ // if the play event arrives in this state, defer it until a state handles it or
+ // rejects it
+ typedef mpl::vector<play> deferred_events;
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ };
+ struct AllOk : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ // this state is also made terminal so that all the events are blocked
+ struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
+ public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
+ // the event end_error is generated
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
+
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+
+ // at this point, Play is active (was deferred)
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found()); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play());pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play());pstate(p);
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/Orthogonal-deferred2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/Orthogonal-deferred2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,293 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // we want deferred events and no state requires deferred events (only the fsm in the
+ // transition table), so the fsm does.
+ typedef int activate_deferred_events;
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ };
+ struct AllOk : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ // this state is also made terminal so that all the events are blocked
+ struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
+ public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
+ // the event end_error is generated
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ Row < Open , play , none , Defer , none >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ Row < Empty , play , none , Defer , none >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
+
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+
+ // at this point, Play is active (was deferred)
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found()); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play());pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play());pstate(p);
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/OrthogonalDeferredEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/OrthogonalDeferredEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,253 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(end_error)
+ BOOST_MSM_EUML_EVENT(error_found)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+
+ // Flags. Allow information about a property of the current state
+ BOOST_MSM_EUML_FLAG(PlayingPaused)
+ BOOST_MSM_EUML_FLAG(CDLoaded)
+ BOOST_MSM_EUML_FLAG(FirstSongPlaying)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+
+ BOOST_MSM_EUML_STATE(( Empty_Entry,
+ Empty_Exit,
+ attributes_ << no_attributes_,
+ configure_ << play // defer play
+ ),
+ Empty)
+
+ BOOST_MSM_EUML_STATE(( Open_Entry,
+ Open_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded << play // defer play, flag state with CDLoaded
+ ),
+ Open)
+
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,
+ Stopped_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded // flag state with CDLoaded
+ ),
+ Stopped)
+
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE(( no_action,
+ no_action,
+ attributes_ << no_attributes_,
+ configure_<< PlayingPaused << CDLoaded // flag state with CDLoaded and PlayingPaused
+ ),
+ Paused)
+
+ BOOST_MSM_EUML_STATE(( AllOk_Entry,AllOk_Exit ),AllOk)
+
+ // a terminate state
+ //BOOST_MSM_EUML_TERMINATE_STATE(( ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+ // or as an interrupt state
+ BOOST_MSM_EUML_INTERRUPT_STATE(( end_error,ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+
+ // Playing is now a state machine itself.
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,
+ Song1_Exit,
+ attributes_ << no_attributes_,
+ configure_<< FirstSongPlaying ),Song1)
+
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1, // Init State
+ no_action, // entry
+ no_action, // exit
+ attributes_ << no_attributes_, //attributes
+ configure_<< PlayingPaused << CDLoaded //flags
+ ),Playing_)
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop,
+ ErrorMode == AllOk + error_found / report_error,
+ AllOk == ErrorMode+ end_error / report_end_error
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty<< AllOk, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing","AllOk","ErrorMode" };
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() << std::endl;//=> false
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded),player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play);pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error);pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play);pstate(p);
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/OrthogonalDeferredEuml2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/OrthogonalDeferredEuml2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,241 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(end_error)
+ BOOST_MSM_EUML_EVENT(error_found)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Flags. Allow information about a property of the current state
+ BOOST_MSM_EUML_FLAG(PlayingPaused)
+ BOOST_MSM_EUML_FLAG(CDLoaded)
+ BOOST_MSM_EUML_FLAG(FirstSongPlaying)
+
+ // Concrete FSM implementation
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( Empty_Entry,
+ Empty_Exit,
+ attributes_ << no_attributes_,
+ configure_ << no_configure_
+ ),
+ Empty)
+
+ BOOST_MSM_EUML_STATE(( Open_Entry,
+ Open_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded // flag state with CDLoaded
+ ),
+ Open)
+
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,
+ Stopped_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded // flag state with CDLoaded
+ ),
+ Stopped)
+
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE(( no_action,
+ no_action,
+ attributes_ << no_attributes_,
+ configure_<< PlayingPaused << CDLoaded // flag state with CDLoaded and PlayingPaused
+ ),
+ Paused)
+
+ BOOST_MSM_EUML_STATE(( AllOk_Entry,AllOk_Exit ),AllOk)
+
+ // a terminate state
+ //BOOST_MSM_EUML_TERMINATE_STATE(( ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+ // or as an interrupt state
+ BOOST_MSM_EUML_INTERRUPT_STATE(( end_error,ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+
+ // Playing is now a state machine itself.
+
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,
+ Song1_Exit,
+ attributes_ << no_attributes_,
+ configure_<< FirstSongPlaying ),Song1)
+
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1, // Init State
+ no_action, // entry
+ no_action, // exit
+ attributes_ << no_attributes_, //attributes
+ configure_<< PlayingPaused << CDLoaded //flags
+ ),Playing_)
+
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // we now defer using the defer_ function. This will need deferred_events as config (see below)
+ Empty + play / defer_ ,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer ,
+ Open == Paused + open_close / stop_and_open ,
+ Open == Stopped + open_close / open_drawer ,
+ Open == Playing + open_close / stop_and_open ,
+ // we now defer using the defer_ function. This will need deferred_events as config (see below)
+ Open + play / defer_ ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback ,
+ Stopped == Paused + stop / stop_playback ,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop ,
+ ErrorMode == AllOk + error_found / report_error ,
+ AllOk == ErrorMode+ end_error / report_end_error
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty << AllOk, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << deferred_events, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing","AllOk","ErrorMode" };
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded),player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play);pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error);pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play);pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/ParsingDigits.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/ParsingDigits.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,471 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+#define FUSION_MAX_VECTOR_SIZE 20
+
+#include <boost/msm/back/state_machine.hpp>
+#include "char_event_dispatcher.hpp"
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/timer.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+// events
+struct end_sub {template <class Event> end_sub(Event const&){}};
+struct other_char {};
+struct default_char {};
+struct eos {};
+
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // Concrete FSM implementation
+ struct parsing_ : public msm::front::state_machine_def<parsing_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ struct Waiting : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Waiting" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Waiting" << std::endl;}
+ };
+ struct Digit1 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit1" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit1" << std::endl;}
+ };
+ struct Digit2 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit2" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit2" << std::endl;}
+ };
+ struct Digit3 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit3" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit3" << std::endl;}
+ };
+ struct Digit4 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit4" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit4" << std::endl;}
+ };
+ struct MinusChar1 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar1" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar1" << std::endl;}
+ };
+ struct Digit5 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit5" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit5" << std::endl;}
+ };
+ struct Digit6 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit6" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit6" << std::endl;}
+ };
+ struct Digit7 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit7" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit7" << std::endl;}
+ };
+ struct Digit8 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit8" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit8" << std::endl;}
+ };
+ struct MinusChar2 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar2" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar2" << std::endl;}
+ };
+ struct Digit9 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit9" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit9" << std::endl;}
+ };
+ struct Digit10 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit10" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit10" << std::endl;}
+ };
+ struct Digit11 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit11" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit11" << std::endl;}
+ };
+ struct Digit12 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit12" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit12" << std::endl;}
+ };
+ struct MinusChar3 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar3" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar3" << std::endl;}
+ };
+ struct Digit13 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit13" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit13" << std::endl;}
+ };
+ struct Digit14 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit14" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit14" << std::endl;}
+ };
+ struct Digit15 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit15" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit15" << std::endl;}
+ };
+ //struct Start : public msm::front::state<> {};
+ struct Parsed : public msm::front::state<> {};
+ //struct Failed : public msm::front::state<> {};
+
+ // the initial state of the player SM. Must be defined
+ typedef Waiting initial_state;
+ // transition actions
+ struct test_fct
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Parsed!" << std::endl;
+ }
+ };
+
+ // guard conditions
+
+
+ // Transition table for parsing_
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +-------------+-------------------+---------+---------------------+----------------------+
+ Row < Waiting , digit , Digit1 >,
+ Row < Digit1 , digit , Digit2 >,
+ Row < Digit2 , digit , Digit3 >,
+ Row < Digit3 , digit , Digit4 >,
+ Row < Digit4 , event_char<'-'> , MinusChar1 >,
+ Row < MinusChar1 , digit , Digit5 >,
+ Row < Digit5 , digit , Digit6 >,
+ Row < Digit6 , digit , Digit7 >,
+ Row < Digit7 , digit , Digit8 >,
+ Row < Digit8 , event_char<'-'> , MinusChar2 >,
+ Row < MinusChar2 , digit , Digit9 >,
+ Row < Digit9 , digit , Digit10 >,
+ Row < Digit10 , digit , Digit11 >,
+ Row < Digit11 , digit , Digit12 >,
+ Row < Digit12 , event_char<'-'> , MinusChar3 >,
+ Row < MinusChar3 , digit , Digit13 >,
+ Row < Digit13 , digit , Digit14 >,
+ Row < Digit14 , digit , Digit15 >,
+ Row < Digit15 , eos , Parsed >,
+ Row < Parsed , eos , Waiting >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<parsing_> parsing;
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+// This declares the statically-initialized char_event_dispatcher instance.
+template <class Fsm>
+const msm::back::char_event_dispatcher<Fsm>
+msm::back::char_event_dispatcher<Fsm>::instance;
+
+struct Parser
+{
+ Parser():p(){p.start();}
+ void new_char(char c)
+ {
+ typedef msm::back::char_event_dispatcher<test_fsm::parsing> table;
+ table::instance.process_event(p,c);
+ }
+ void finish_string(){p.process_event(eos());}
+ void reinit(){p.process_event(eos());}
+ test_fsm::parsing p;
+};
+
+void msm_match(const char* input)
+{
+ test_fsm::parsing p;
+ p.start();
+
+ int j=0;
+ while(input[j])
+ //for (size_t j=0;j<len;++j)
+ {
+ switch (input[j])
+ {
+ case '0':
+ p.process_event(char_0());
+ break;
+ case '1':
+ p.process_event(char_1());
+ break;
+ case '2':
+ p.process_event(char_2());
+ break;
+ case '3':
+ p.process_event(char_3());
+ break;
+ case '4':
+ p.process_event(char_4());
+ break;
+ case '5':
+ p.process_event(char_5());
+ break;
+ case '6':
+ p.process_event(char_6());
+ break;
+ case '7':
+ p.process_event(char_7());
+ break;
+ case '8':
+ p.process_event(char_8());
+ break;
+ case '9':
+ p.process_event(char_9());
+ break;
+ case '-':
+ p.process_event(event_char<'-'>());
+ break;
+ default:
+ p.process_event(default_char());
+ break;
+ }
+ ++j;
+ }
+ p.process_event(eos());
+ p.process_event(eos());
+}
+
+double time_match(const char* text)
+{
+ boost::timer tim;
+ int iter = 1;
+ int counter, repeats;
+ double result = 0;
+ double run;
+ do
+ {
+ tim.restart();
+ for(counter = 0; counter < iter; ++counter)
+ {
+ msm_match( text);
+ }
+ result = tim.elapsed();
+ iter *= 2;
+ } while(result < 0.5);
+ iter /= 2;
+
+ // repeat test and report least value for consistency:
+ for(repeats = 0; repeats < 10; ++repeats)
+ {
+ tim.restart();
+ for(counter = 0; counter < iter; ++counter)
+ {
+ msm_match( text);
+ }
+ run = tim.elapsed();
+ result = (std::min)(run, result);
+ }
+ return result / iter;
+}
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ test_fsm::parsing p;
+ p.start();
+ const char* input = "1234-5678-1234-456";
+ size_t len = strlen(input);
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<1000;++i)
+ {
+ int j=0;
+ while(input[j])
+ //for (size_t j=0;j<len;++j)
+ {
+ switch (input[j])
+ {
+ case '0':
+ p.process_event(char_0());
+ break;
+ case '1':
+ p.process_event(char_1());
+ break;
+ case '2':
+ p.process_event(char_2());
+ break;
+ case '3':
+ p.process_event(char_3());
+ break;
+ case '4':
+ p.process_event(char_4());
+ break;
+ case '5':
+ p.process_event(char_5());
+ break;
+ case '6':
+ p.process_event(char_6());
+ break;
+ case '7':
+ p.process_event(char_7());
+ break;
+ case '8':
+ p.process_event(char_8());
+ break;
+ case '9':
+ p.process_event(char_9());
+ break;
+ case '-':
+ p.process_event(event_char<'-'>());
+ break;
+ default:
+ p.process_event(default_char());
+ break;
+ }
+ ++j;
+ }
+ p.process_event(eos());
+ p.process_event(eos());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm(1) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm(1) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+
+ Parser parse;
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<1000;++i)
+ {
+ for (size_t j=0;j<len;++j)
+ {
+ parse.new_char(input[j]);
+ }
+ parse.finish_string();
+ parse.reinit();
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm(2) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm(2) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ std::cout << "msm(3) took in s:" << time_match(input) <<"\n" <<std::endl;
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/SC Composite.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SC Composite.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,197 @@
+#include <boost/statechart/event.hpp>
+#include <boost/statechart/state_machine.hpp>
+#include <boost/statechart/simple_state.hpp>
+#include <boost/statechart/transition.hpp>
+#include "boost/mpl/list.hpp"
+
+#include <vector>
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace sc = boost::statechart;
+namespace mpl = boost::mpl;
+
+namespace test_sc
+{
+
+ //events
+ struct play : sc::event< play > {};
+ struct end_pause : sc::event< end_pause > {};
+ struct stop : sc::event< stop > {};
+ struct pause : sc::event< pause > {};
+ struct open_close : sc::event< open_close > {};
+ struct cd_detected : sc::event< cd_detected > {};
+ struct NextSong: sc::event< NextSong > {};
+ struct PreviousSong : sc::event< PreviousSong >{};
+
+ struct Empty;
+ struct Open;
+ struct Stopped;
+ struct Playing;
+ struct Paused;
+ // SM
+ struct player : sc::state_machine< player, Empty >
+ {
+ void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ }
+ void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ }
+ void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ }
+ void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ }
+ void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/}
+ void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ }
+ void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */}
+ void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ }
+ void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ }
+ };
+
+ struct Empty : sc::simple_state< Empty, player >
+ {
+ Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry
+ ~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< cd_detected, Stopped,
+ player, &player::store_cd_info > > reactions;
+
+ };
+ struct Open : sc::simple_state< Open, player >
+ {
+ Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry
+ ~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit
+ typedef sc::transition< open_close, Empty,
+ player, &player::close_drawer > reactions;
+
+ };
+ struct Stopped : sc::simple_state< Stopped, player >
+ {
+ Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry
+ ~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< play, Playing,
+ player, &player::start_playback >,
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< stop, Stopped,
+ player, &player::stopped_again > > reactions;
+
+ };
+ struct Song1;
+ struct Playing : sc::simple_state< Playing, player,Song1 >
+ {
+ Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry
+ ~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< pause, Paused,
+ player, &player::pause_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ void start_next_song(NextSong const&) { /*std::cout << "Playing::start_next_song\n";*/ }
+ void start_prev_song(PreviousSong const&) { /*std::cout << "Playing::start_prev_song\n";*/ }
+ };
+ struct Song2;
+ struct Song1 : sc::simple_state< Song1, Playing >
+ {
+ Song1() { /*std::cout << "entering Song1" << std::endl;*/ } // entry
+ ~Song1() { /*std::cout << "leaving Song1" << std::endl;*/ } // exit
+ typedef sc::transition< NextSong, Song2,
+ Playing, &Playing::start_next_song > reactions;
+ };
+ struct Song3;
+ struct Song2 : sc::simple_state< Song2, Playing >
+ {
+ Song2() { /*std::cout << "entering Song2" << std::endl;*/ } // entry
+ ~Song2() { /*std::cout << "leaving Song2" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< NextSong, Song3,
+ Playing, &Playing::start_next_song >,
+ sc::transition< PreviousSong, Song1,
+ Playing, &Playing::start_prev_song > > reactions;
+ };
+ struct Song3 : sc::simple_state< Song3, Playing >
+ {
+ Song3() { /*std::cout << "entering Song3" << std::endl;*/ } // entry
+ ~Song3() { /*std::cout << "leaving Song3" << std::endl;*/ } // exit
+ typedef sc::transition< PreviousSong, Song2,
+ Playing, &Playing::start_prev_song > reactions;
+ };
+ struct Paused : sc::simple_state< Paused, player >
+ {
+ Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry
+ ~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< end_pause, Playing,
+ player, &player::resume_playback >,
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ };
+}
+
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+int main()
+{
+ test_sc::player p;
+ p.initiate();
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+ ::QueryPerformanceCounter(&li);
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ for (int i=0;i<100;++i)
+ {
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::cd_detected());
+ p.process_event(test_sc::play());
+ for (int j=0;j<100;++j)
+ {
+ p.process_event(test_sc::NextSong());
+ p.process_event(test_sc::NextSong());
+ p.process_event(test_sc::PreviousSong());
+ p.process_event(test_sc::PreviousSong());
+ }
+
+ p.process_event(test_sc::pause());
+ // go back to Playing
+ p.process_event(test_sc::end_pause());
+ p.process_event(test_sc::pause());
+ p.process_event(test_sc::stop());
+ // event leading to the same state
+ p.process_event(test_sc::stop());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/SC Simple.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SC Simple.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,159 @@
+#include <boost/statechart/event.hpp>
+#include <boost/statechart/state_machine.hpp>
+#include <boost/statechart/simple_state.hpp>
+#include <boost/statechart/transition.hpp>
+#include "boost/mpl/list.hpp"
+
+#include <vector>
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace sc = boost::statechart;
+namespace mpl = boost::mpl;
+
+namespace test_sc
+{
+
+ //events
+ struct play : sc::event< play > {};
+ struct end_pause : sc::event< end_pause > {};
+ struct stop : sc::event< stop > {};
+ struct pause : sc::event< pause > {};
+ struct open_close : sc::event< open_close > {};
+ struct cd_detected : sc::event< cd_detected > {};
+
+
+ struct Empty;
+ struct Open;
+ struct Stopped;
+ struct Playing;
+ struct Paused;
+ // SM
+ struct player : sc::state_machine< player, Empty >
+ {
+ void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ }
+ void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ }
+ void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ }
+ void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ }
+ void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/}
+ void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ }
+ void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */}
+ void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ }
+ void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ }
+ };
+
+ struct Empty : sc::simple_state< Empty, player >
+ {
+ Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry
+ ~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< cd_detected, Stopped,
+ player, &player::store_cd_info > > reactions;
+
+ };
+ struct Open : sc::simple_state< Open, player >
+ {
+ Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry
+ ~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit
+ typedef sc::transition< open_close, Empty,
+ player, &player::close_drawer > reactions;
+
+ };
+ struct Stopped : sc::simple_state< Stopped, player >
+ {
+ Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry
+ ~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< play, Playing,
+ player, &player::start_playback >,
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< stop, Stopped,
+ player, &player::stopped_again > > reactions;
+
+ };
+ struct Playing : sc::simple_state< Playing, player >
+ {
+ Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry
+ ~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< pause, Paused,
+ player, &player::pause_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ };
+ struct Paused : sc::simple_state< Paused, player >
+ {
+ Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry
+ ~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< end_pause, Playing,
+ player, &player::resume_playback >,
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ };
+}
+
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ test_sc::player p;
+ p.initiate();
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+ ::QueryPerformanceCounter(&li);
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::cd_detected());
+ p.process_event(test_sc::play());
+ p.process_event(test_sc::pause());
+ // go back to Playing
+ p.process_event(test_sc::end_pause());
+ p.process_event(test_sc::pause());
+ p.process_event(test_sc::stop());
+ // event leading to the same state
+ p.process_event(test_sc::stop());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/SM-2Arg.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SM-2Arg.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,459 @@
+#include <iostream>
+#include <string>
+#include "boost/mpl/vector/vector30.hpp"
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/back/tools.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct ThreeSec {};
+ struct TenSec {};
+ struct go_sleep {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+ // an easy visitor
+ struct SomeVisitor
+ {
+ template <class T>
+ void visit_state(T* astate,int i)
+ {
+ std::cout << "visiting state:" << typeid(*astate).name()
+ << " with data:" << i << std::endl;
+ }
+ };
+ // overwrite of the base state (not default)
+ struct my_visitable_state
+ {
+ // signature of the accept function
+ typedef msm::back::args<void,SomeVisitor&,int> accept_sig;
+
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept(SomeVisitor&,int) const {}
+ };
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_,my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: player" << std::endl;}
+ // The list of FSM states
+ struct Empty : public msm::front::state<my_visitable_state>
+ {
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ vis.visit_state(this,i);
+ }
+ };
+ struct Open : public msm::front::state<my_visitable_state>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ typedef mpl::vector<play> deferred_events;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ vis.visit_state(this,i);
+ }
+ };
+ // a state needing a pointer to the containing state machine
+ // and using for this the non-default policy
+ // if policy used, set_sm_ptr is needed
+ struct Stopped : public msm::front::state<my_visitable_state>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+ // the player state machine contains a state which is himself a state machine
+ // it demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ struct Playing_ : public msm::front::state_machine_def<Playing_,my_visitable_state >
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ // note that visiting will recursively visit sub-states
+ vis.visit_state(this,i);
+ }
+ // The list of FSM states
+ // the Playing state machine contains a state which is himself a state machine
+ // so we have a SM containing a SM containing a SM
+ struct Song1_ : public msm::front::state_machine_def<Song1_,my_visitable_state>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ vis.visit_state(this,i);
+ }
+ struct LightOn : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOn" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOn" << std::endl;}
+ };
+ struct LightOff : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOff" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOff" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef LightOn initial_state;
+ // transition actions
+ void turn_light_off(ThreeSec const&) { std::cout << "3s off::turn light off\n"; }
+ // guard conditions
+
+ typedef Song1_ s; // makes transition table cleaner
+ // Transition table for Song1
+ struct transition_table : mpl::vector1<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < LightOn , ThreeSec , LightOff, &s::turn_light_off >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Song1_> Song1;
+
+ struct Song2 : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
+ struct Paused_ : public msm::front::state_machine_def<Paused_,my_visitable_state>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
+
+ // The list of FSM states
+ struct StartBlinking : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: StartBlinking" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: StartBlinking" << std::endl;}
+ };
+ struct StopBlinking : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: StopBlinking" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: StopBlinking" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef StartBlinking initial_state;
+ // transition actions
+ void start_blinking(TenSec const&) { std::cout << "Paused::start_blinking\n"; }
+ void stop_blinking(TenSec const&) { std::cout << "Paused::stop_blinking\n"; }
+ // guard conditions
+
+ typedef Paused_ pa; // makes transition table cleaner
+ // Transition table
+ struct transition_table : mpl::vector2<
+ // Start Event Next Action Guard
+ // +---------------+-------------+--------------+---------------------+----------------------+
+ a_row < StartBlinking , TenSec , StopBlinking , &pa::stop_blinking >,
+ a_row < StopBlinking , TenSec , StartBlinking , &pa::start_blinking >
+ // +---------------+-------------+---------------+--------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Paused_> Paused;
+
+ struct SleepMode : public msm::front::state<my_visitable_state>
+ {
+ }; // dummy state just to test the automatic id generation
+
+ struct AllOk : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ struct ErrorMode : //public terminate_state<>
+ public msm::front::interrupt_state<end_error,my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+ //typedef Empty initial_state; // this is to have only one active state
+
+ // 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";
+ // generate another event to test the queue
+ //process_event(play());
+ }
+ 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void start_sleep(go_sleep const&) { }
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+ // guard conditions
+
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ a_row < Paused , go_sleep ,SleepMode, &p::start_sleep >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+
+ // back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+
+ void pstate(player const& p)
+ {
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode","SleepMode" };
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ // visiting Paused and AllOk, but only Paused cares
+ SomeVisitor vis;
+ p.visit_current_states(boost::ref(vis),1);
+ p.process_event(open_close()); pstate(p);
+ // visiting Empty and AllOk, but only Empty cares
+ p.visit_current_states(boost::ref(vis),2);
+
+
+ p.process_event(cd_detected("louie, louie"));
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+ // at this point, Play is active, along FirstSong and LightOn
+ pstate(p);
+ // visiting Playing+Song1 and AllOk, but only Playing+Song1 care
+ p.visit_current_states(boost::ref(vis),3);
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // call on_exit on LightOn,FirstSong,Play like stated in the UML spec.
+ // and of course on_entry on Paused and StartBlinking
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // forward events to Paused
+ p.process_event(TenSec());
+ p.process_event(TenSec());
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
+ p.process_event(ThreeSec()); pstate(p);
+ p.process_event(NextSong());pstate(p);
+ // We are now in second song, Flag inactive
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ // visiting Playing+Song2 and AllOk, but only Playing cares
+ p.visit_current_states(boost::ref(vis),4);
+
+ p.process_event(NextSong());pstate(p);
+ // 2nd song active
+ p.process_event(PreviousSong());pstate(p);
+ // Pause
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // but end_pause is an event activating the History
+ // => keep the last active State (SecondSong)
+ p.process_event(end_pause()); pstate(p);
+ // test of an event from a state to itself. According to UML spec, call again exit/entry from Stopped
+ p.process_event(stop()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+ std::cout << "CDLoaded active with OR:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_OR>() << std::endl;//=> true
+
+ // go back to Playing
+ // but play is not leading to Shallow History => do not remember the last active State (SecondSong)
+ // and activate again FirstSong and LightOn
+ p.process_event(play()); pstate(p);
+ p.process_event(error_found()); pstate(p);
+
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Simulate error. Event play is not valid" << std::endl;
+ p.process_event(play()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
+
Added: trunk/libs/msm/doc/HTML/examples/SimpleTimer.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTimer.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,149 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// how long the timer will ring when countdown elapsed.
+#define RINGING_TIME 5
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_timer)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_timer ), start_timer_attr)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(start_timer,start_timer_attr)
+
+ BOOST_MSM_EUML_EVENT(stop_timer)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_tick)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_tick ), tick_attr)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(tick,tick_attr)
+
+ BOOST_MSM_EUML_EVENT(start_ringing)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_ACTION(Stopped_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Stopped" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( Stopped_Entry ),Stopped)
+
+ BOOST_MSM_EUML_ACTION(Started_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Started" << std::endl;
+ }
+ };
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_counter)
+ BOOST_MSM_EUML_STATE(( Started_Entry,
+ no_action,
+ attributes_ << m_counter
+ ),
+ Started)
+
+ BOOST_MSM_EUML_ACTION(Ringing_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Ringing" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_ringing_cpt)
+ BOOST_MSM_EUML_STATE(( Ringing_Entry,
+ no_action,
+ attributes_ << m_ringing_cpt
+ ),
+ Ringing)
+
+ // external function
+ void do_ring(int ringing_time) {std::cout << "ringing " << ringing_time << " s" << std::endl;}
+ // create functor and eUML function
+ BOOST_MSM_EUML_FUNCTION(Ring_ , do_ring , ring_ , void , void )
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ // When we start the countdown, the countdown value is not hardcoded but contained in the start_timer event.
+ // We copy this value into Started
+ Started == Stopped + start_timer /(target_(m_counter)= event_(m_timer)) ,
+ Stopped == Started + stop_timer ,
+ // internal transition
+ Started + tick
+ // we here use the message queue to move to Started when the countdown is finished
+ // to do this we put start_ringing into the message queue
+ / if_then_( (source_(m_counter) -= event_(m_tick) ) <= Int_<0>(),
+ process_(start_ringing) ) ,
+ // when we start ringing, we give to the state its hard-coded ringing time.
+ Ringing == Started + start_ringing
+ / (target_(m_ringing_cpt) = Int_<RINGING_TIME>(),
+ // call the external do_ring function
+ ring_(Int_<RINGING_TIME>())) ,
+ // to change a bit, we now do not use the message queue but a transition conflict to solve the same problem.
+ // When tick is fired, we have an internal transition Ringing -> Ringing, as long as Counter > 0
+ Ringing + tick [ source_(m_ringing_cpt) - event_(m_tick) > Int_<0>() ]
+ /(target_(m_ringing_cpt) -= event_(m_tick) ) ,
+ // And we move to Stopped when the counter is 0
+ Stopped == Ringing + tick[source_(m_ringing_cpt)-event_(m_tick) <= Int_<0>()] ,
+ // we let the user manually stop the ringing by pressing any button
+ Stopped == Ringing + stop_timer ,
+ Stopped == Ringing + start_timer
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Stopped // Init State
+ ),
+ SimpleTimer_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<SimpleTimer_> SimpleTimer;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Started","Ringing" };
+ void pstate(SimpleTimer const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ SimpleTimer p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ p.process_event(start_timer(5));pstate(p); //timer set to 5 ticks
+ p.process_event(tick(2));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ // we are now ringing, let it ring a bit
+ p.process_event(tick(2));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,190 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // used to show a transition conflict. This guard will simply deactivate one transition and thus
+ // solve the conflict
+ bool auto_start(cd_detected const&)
+ {
+ return false;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ row < Empty , cd_detected , Playing , &p::store_cd_info ,&p::auto_start >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleTutorial2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTutorial2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,203 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/row2.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ void open_drawer(open_close const&) { std::cout << "Empty::open_drawer\n"; }
+ // actions for Empty's internal transitions
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ void close_drawer(open_close const&) { std::cout << "Open::close_drawer\n"; }
+ void stop_and_open(open_close const&) { std::cout << "Open::stop_and_open\n"; }
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ void start_playback(play const&) { std::cout << "Stopped::start_playback\n"; }
+ void stop_playback(stop const&) { std::cout << "Stopped::stop_playback\n"; }
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ // guard conditions
+ // used to show a transition conflict. This guard will simply deactivate one transition and thus
+ // solve the conflict
+ bool auto_start(cd_detected const&)
+ {
+ return false;
+ }
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ void pause_playback(pause const&) { std::cout << "Paused::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "Paused::resume_playback\n"; }
+ };
+
+ // action
+ void store_cd_info(cd_detected const&) { std::cout << "Player::store_cd_info\n"; }
+
+ // guard
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action/Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Stopped , play , Playing , Stopped , &Stopped::start_playback >,
+ a_row2 < Stopped , open_close , Open , Empty , &Empty::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Open , open_close , Empty , Open , &Open::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Empty , open_close , Open , Empty ,&Empty::open_drawer >,
+ row2 < Empty , cd_detected , Stopped , player_ ,&player_::store_cd_info
+ , player_ ,&player_::good_disk_format >,
+ row2 < Empty , cd_detected , Playing , player_ ,&player_::store_cd_info
+ , Playing ,&Playing::auto_start >,
+ // conflict with some internal rows
+ irow2 < Empty , cd_detected , Empty ,&Empty::internal_action
+ , Empty ,&Empty::internal_guard >,
+ g_irow2 < Empty , cd_detected , Empty ,&Empty::internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Playing , stop , Stopped , Stopped ,&Stopped::stop_playback >,
+ a_row2 < Playing , pause , Paused , Paused ,&Paused::pause_playback >,
+ a_row2 < Playing , open_close , Open , Open ,&Open::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Paused , end_pause , Playing , Paused ,&Paused::resume_playback >,
+ a_row2 < Paused , stop , Stopped , Stopped ,&Stopped::stop_playback >,
+ a_row2 < Paused , open_close , Open , Open ,&Open::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleTutorialEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTutorialEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,168 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+ // The list of FSM states
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // it is also possible to define a state which you can implement normally
+ // just make it a state, as usual, and also a grammar terminal, euml_state
+ struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
+ {
+ // this allows us to add some functions
+ void activate_empty() {std::cout << "switching to Empty " << std::endl;}
+ // standard entry behavior
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& fsm)
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const& evt,FSM& fsm)
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+ };
+ //instance for use in the transition table
+ Empty_impl const Empty;
+
+ // create a functor and a eUML function for the activate_empty method from Entry
+ BOOST_MSM_EUML_METHOD(ActivateEmpty_ , activate_empty , activate_empty_ , void , void )
+
+ // define more states
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+ BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
+
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / (close_drawer,activate_empty_(target_)),
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format &&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // or simply, if no no_transition handler needed:
+ //BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ // Empty // Init State
+ // ),player_)
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
+ // you now have less to type.
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleTutorialEuml2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTutorialEuml2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,139 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ // note that unlike the SimpleTutorial, events must derive from euml_event.
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+ BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Stopped + play / start_playback == Playing ,
+ Stopped + open_close / open_drawer == Open ,
+ Stopped + stop == Stopped,
+ // +------------------------------------------------------------------------------+
+ Open + open_close / close_drawer == Empty ,
+ // +------------------------------------------------------------------------------+
+ Empty + open_close / open_drawer == Open ,
+ Empty + cd_detected
+ [good_disk_format &&(event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)) == Stopped ,
+ // +------------------------------------------------------------------------------+
+ Playing + stop / stop_playback == Stopped ,
+ Playing + pause / pause_playback == Paused ,
+ Playing + open_close / stop_and_open == Open ,
+ // +------------------------------------------------------------------------------+
+ Paused + end_pause / resume_playback == Playing ,
+ Paused + stop / stop_playback == Stopped ,
+ Paused + open_close / stop_and_open == Open
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternal.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternal.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,216 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct to_ignore {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // transitions internal to Empty
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard functor\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal action functor" << std::endl;
+ }
+ };
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
+ _irow < Empty , to_ignore >,
+ g_irow < Empty , cd_detected ,&p::internal_guard >,
+ Row < Empty , cd_detected , none , internal_action_fct ,internal_guard_fct >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // this event will be ignored and not call no_transition
+ p.process_event(to_ignore());
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternal2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternal2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,221 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // actions for Empty's internal transitions
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard functor\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal action functor" << std::endl;
+ }
+ };
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Internal < cd_detected , internal_action_fct ,internal_guard_fct >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ // conflict between a normal and 2 internal transitions (irow/g_irow)
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
+ g_irow < Empty , cd_detected ,&p::internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ typedef int no_message_queue;
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternalFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleTutorialInternalFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,315 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+using namespace msm::front;
+namespace mpl = boost::mpl;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal_transition_table guard\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal_transition_table action" << std::endl;
+ }
+ };
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Internal < cd_detected , internal_action_fct ,internal_guard_fct >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ struct internal_guard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ };
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // internal transition inside the stt: none as Target
+ Row < Empty , cd_detected , none , none , internal_guard >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous transition does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,294 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ // we want to define one row with the classic look.
+ bool auto_start(cd_detected const& evt)
+ {
+ return false;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // we here also mix with some "classical row"
+ g_row < Empty , cd_detected , Playing , &p::auto_start >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,310 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+// for func_state and func_state_machine
+#include <boost/msm/front/euml/state_grammar.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ // entry and exit functors for Empty
+ struct Empty_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+ };
+ struct Empty_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+ };
+ // definition of Empty
+ struct Empty_tag {};
+ typedef msm::front::euml::func_state<Empty_tag,Empty_Entry,Empty_Exit> Empty;
+
+ struct Open_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Open" << std::endl;
+ }
+ };
+ struct Open_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Open" << std::endl;
+ }
+ };
+ struct Open_tag {};
+ typedef msm::front::euml::func_state<Open_tag,Open_Entry,Open_Exit> Open;
+
+ // states without entry/exit actions (can be declared as functor state, just without functors ;-) )
+ struct Stopped_tag {};
+ typedef msm::front::euml::func_state<Stopped_tag> Stopped;
+
+ struct Playing_tag {};
+ typedef msm::front::euml::func_state<Playing_tag> Playing;
+
+ // state not defining any entry or exit (declared as simple state. Equivalent)
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ // we want to define one row with the classic look.
+ bool auto_start(cd_detected const& evt)
+ {
+ return false;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // we here also mix with some "classical row"
+ g_row < Empty , cd_detected , Playing , &p::auto_start >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors3.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/SimpleWithFunctors3.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,297 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+// for func_state and func_state_machine
+#include <boost/msm/front/euml/state_grammar.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+
+ // The list of FSM states
+ // entry and exit functors for Empty
+ struct Empty_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+ };
+ struct Empty_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+ };
+ // definition of Empty
+ struct Empty_tag {};
+ typedef msm::front::euml::func_state<Empty_tag,Empty_Entry,Empty_Exit> Empty;
+
+ struct Open_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Open" << std::endl;
+ }
+ };
+ struct Open_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Open" << std::endl;
+ }
+ };
+ struct Open_tag {};
+ typedef msm::front::euml::func_state<Open_tag,Open_Entry,Open_Exit> Open;
+
+ // states without entry/exit actions (can be declared as functor state, just without functors ;-) )
+ struct Stopped_tag {};
+ typedef msm::front::euml::func_state<Stopped_tag> Stopped;
+
+ struct Playing_tag {};
+ typedef msm::front::euml::func_state<Playing_tag> Playing;
+
+ // state not defining any entry or exit (declared as simple state. Equivalent)
+ struct Paused_tag {};
+ typedef msm::front::euml::func_state<Paused_tag> Paused;
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+
+ // Transition table for player
+ struct player_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // fsm definition
+ struct player_tag {};
+ typedef msm::front::euml::func_state_machine<Playing_tag,
+ // transition table
+ player_transition_table,
+ //Initial state
+ Empty> player_;
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/TestInternal.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/TestInternal.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,327 @@
+#include <iostream>
+#include "boost/mpl/vector/vector30.hpp"
+
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/internal_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct internal_event {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct to_ignore {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // transitions internal to Empty
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ void internal_action(internal_event const&){ std::cout << "Playing::internal action\n"; }
+ bool internal_guard(internal_event const&)
+ {
+ std::cout << "Playing::internal guard\n";
+ return false;
+ }
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard functor\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal action functor" << std::endl;
+ }
+ };
+ void internal_action(to_ignore const&) { std::cout << "Empty::(almost)ignoring event\n"; }
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Row < Empty , cd_detected , none , internal_action_fct ,internal_guard_fct >,
+ Internal < cd_detected , internal_action_fct ,internal_guard_fct >,
+ a_internal< to_ignore , Empty,&Empty::internal_action >
+ // +---------+-------------+----------+------------------------+----------------------+
+ > {};
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&){std::cout << "Playing: start_next_song" << std::endl;}
+ void start_prev_song(PreviousSong const&){std::cout << "Playing: start_prev_song" << std::endl;}
+ // guard conditions
+ struct playing_internal_guard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::internal guard fct\n";
+ return true;
+ }
+ };
+ struct playing_false_guard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::false guard\n";
+ return false;
+ }
+ };
+ struct playing_internal_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::internal fct\n";
+ }
+ };
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+---------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong , Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong , Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Internal transition table for Playing
+ // +---------+----------------+---------+---------------------+-----------------------+
+ struct internal_transition_table : mpl::vector<
+ // normal internal transition
+ // Start Event Next Action Guard
+ Internal < internal_event , playing_internal_fct,playing_internal_guard >,
+ // conflict between internal and the external defined above
+ Internal < PreviousSong , playing_internal_fct,playing_false_guard >,
+ internal < internal_event , player_,&player_::internal_action,
+ player_,&player_::internal_guard >
+ // +---------+----------------+---------+---------------------+-----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ // conflict between a normal and 2 internal transitions (irow/g_irow)
+ // + a state-defined internals defined 2 ways (see Empty)
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
+ g_irow < Empty , cd_detected ,&p::internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // this event will be ignored and not call no_transition
+ p.process_event(to_ignore());
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+ p.process_event(NextSong());
+ std::cout << "sending an internal event" << std::endl;
+ p.process_event(internal_event());
+ std::cout << "conflict between the internal and normal transition. Internal is tried last" << std::endl;
+ p.process_event(PreviousSong());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/char_event_dispatcher.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/char_event_dispatcher.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,82 @@
+#ifndef BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
+#define BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
+
+#include <boost/msm/back/common_types.hpp>
+
+struct digit {};
+struct char_0 : public digit {};
+struct char_1 : public digit {};
+struct char_2 : public digit {};
+struct char_3 : public digit {};
+struct char_4 : public digit {};
+struct char_5 : public digit {};
+struct char_6 : public digit {};
+struct char_7 : public digit {};
+struct char_8 : public digit {};
+struct char_9 : public digit {};
+struct minus_char {};
+template <char c>
+struct event_char{};
+template <>
+struct event_char<'0'> : public digit{};
+template <>
+struct event_char<'1'> : public digit{};
+template <>
+struct event_char<'2'> : public digit{};
+template <>
+struct event_char<'3'> : public digit{};
+template <>
+struct event_char<'4'> : public digit{};
+template <>
+struct event_char<'5'> : public digit{};
+template <>
+struct event_char<'6'> : public digit{};
+template <>
+struct event_char<'7'> : public digit{};
+template <>
+struct event_char<'8'> : public digit{};
+template <>
+struct event_char<'9'> : public digit{};
+
+namespace boost { namespace msm { namespace back {
+
+
+template <class Fsm>
+struct char_event_dispatcher
+{
+ template <char c>
+ struct dispatch_event_helper
+ {
+ static execute_return apply(Fsm& fsm)
+ {
+ return fsm.process_event(event_char<c>());
+ }
+ };
+ char_event_dispatcher()
+ {
+ entries[0x30]=&dispatch_event_helper<'0'>::apply;
+ entries[0x31]=&dispatch_event_helper<'1'>::apply;
+ entries[0x32]=&dispatch_event_helper<'2'>::apply;
+ entries[0x33]=&dispatch_event_helper<'3'>::apply;
+ entries[0x34]=&dispatch_event_helper<'4'>::apply;
+ entries[0x35]=&dispatch_event_helper<'5'>::apply;
+ entries[0x36]=&dispatch_event_helper<'6'>::apply;
+ entries[0x37]=&dispatch_event_helper<'7'>::apply;
+ entries[0x38]=&dispatch_event_helper<'8'>::apply;
+ entries[0x39]=&dispatch_event_helper<'9'>::apply;
+ entries[0x2D]=&dispatch_event_helper<'-'>::apply;
+ entries[0x2B]=&dispatch_event_helper<'+'>::apply;
+ }
+ execute_return process_event(Fsm& fsm,char c) const
+ {
+ return entries[c](fsm);
+ }
+
+ // The singleton instance.
+ static const char_event_dispatcher instance;
+ typedef execute_return (*cell)(Fsm&);
+ cell entries[255];
+};
+
+}}} // boost::msm::back
+#endif //BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/examples/distributed_table/DistributedTable.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/distributed_table/DistributedTable.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,64 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+
+#include "Empty.hpp"
+#include "Open.hpp"
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+
+// front-end: define the FSM structure
+struct player_ : public msm::front::state_machine_def<player_>
+{
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+ typedef mpl::vector<Empty,Open> explicit_creation;
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+};
+// Pick a back-end
+typedef msm::back::state_machine<player_> player;
+
+//
+// Testing utilities.
+//
+static char const* const state_names[] = { "Empty", "Open" };
+void pstate(player const& p)
+{
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+}
+
+void test()
+{
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
Added: trunk/libs/msm/doc/HTML/examples/distributed_table/Empty.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/distributed_table/Empty.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,7 @@
+#include <iostream>
+#include "Empty.hpp"
+
+void Empty::open_drawer(open_close const&)
+{
+ std::cout << "Empty::open_drawer\n";
+}
Added: trunk/libs/msm/doc/HTML/examples/distributed_table/Empty.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/distributed_table/Empty.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,33 @@
+#ifndef EMPTY_HPP
+#define EMPTY_HPP
+
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/row2.hpp>
+
+#include "Events.hpp"
+
+struct Open;
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+struct Empty : public msm::front::state<>
+{
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ void open_drawer(open_close const&);
+
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ msm::front::a_row2 < Empty , open_close , Open , Empty,&Empty::open_drawer >
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ > {};
+};
+
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/examples/distributed_table/Events.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/distributed_table/Events.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,29 @@
+#ifndef EVENTS_HPP
+#define EVENTS_HPP
+
+// events
+struct play {};
+struct end_pause {};
+struct stop {};
+struct pause {};
+struct open_close {};
+
+// A "complicated" event type that carries some data.
+enum DiskTypeEnum
+{
+ DISK_CD=0,
+ DISK_DVD=1
+};
+struct cd_detected
+{
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+};
+
+
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/examples/distributed_table/Open.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/distributed_table/Open.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,7 @@
+#include <iostream>
+#include "Open.hpp"
+
+void Open::close_drawer(open_close const&)
+{
+ std::cout << "Open::close_drawer\n";
+}
Added: trunk/libs/msm/doc/HTML/examples/distributed_table/Open.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/distributed_table/Open.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,34 @@
+#ifndef OPEN_HPP
+#define OPEN_HPP
+
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/row2.hpp>
+
+#include "Events.hpp"
+
+struct Empty;
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+struct Open : public msm::front::state<>
+{
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ void close_drawer(open_close const&);
+
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ msm::front::a_row2 < Open , open_close , Empty , Open,&Open::close_drawer >
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ > {};
+};
+
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/examples/iPodEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPodEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,261 @@
+#include <vector>
+#include <set>
+#include <string>
+#include <iostream>
+// we need more than the default 20 states
+#define FUSION_MAX_VECTOR_SIZE 20
+// we need more than the default 20 transitions
+#include "boost/mpl/vector/vector50.hpp"
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// attribute names and types
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_Selected)
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_SongIndex)
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_NumberOfSongs)
+#include "ipod_functors.hpp"
+
+
+namespace // Concrete FSM implementation
+{
+ //flags
+ BOOST_MSM_EUML_FLAG(MenuActive)
+ BOOST_MSM_EUML_FLAG(NoFastFwd)
+ // hardware-generated events
+ BOOST_MSM_EUML_EVENT(Hold)
+ BOOST_MSM_EUML_EVENT(NoHold)
+ BOOST_MSM_EUML_EVENT(SouthPressed)
+ BOOST_MSM_EUML_EVENT(SouthReleased)
+ BOOST_MSM_EUML_EVENT(MiddleButton)
+ BOOST_MSM_EUML_EVENT(EastPressed)
+ BOOST_MSM_EUML_EVENT(EastReleased)
+ BOOST_MSM_EUML_EVENT(Off)
+ BOOST_MSM_EUML_EVENT(MenuButton)
+ // internally defined events
+ BOOST_MSM_EUML_EVENT(PlayPause)
+ BOOST_MSM_EUML_EVENT(EndPlay)
+ struct CloseMenu_impl : euml_event<CloseMenu_impl>
+ {
+ CloseMenu_impl(){}//defined only for stt
+ template<class EVENT>
+ CloseMenu_impl(EVENT const &) {}
+ };
+ CloseMenu_impl const CloseMenu;
+ BOOST_MSM_EUML_EVENT(OnOffTimer)
+ BOOST_MSM_EUML_EVENT(MenuMiddleButton)
+ BOOST_MSM_EUML_EVENT(SelectSong)
+ BOOST_MSM_EUML_EVENT(SongFinished)
+
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_Selected ), StartSongAttributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(StartSong,StartSongAttributes)
+ BOOST_MSM_EUML_EVENT(PreviousSong)
+ BOOST_MSM_EUML_EVENT(NextSong)
+ BOOST_MSM_EUML_EVENT(ForwardTimer)
+ BOOST_MSM_EUML_EVENT(PlayingMiddleButton)
+
+ // Concrete iPod implementation
+ // The list of iPod states
+ BOOST_MSM_EUML_STATE(( NotHolding_Entry ),NotHolding)
+ BOOST_MSM_EUML_INTERRUPT_STATE(( NoHold,Holding_Entry ),Holding)
+ BOOST_MSM_EUML_STATE(( NotPlaying_Entry ),NotPlaying)
+ BOOST_MSM_EUML_STATE(( NoMenuMode_Entry ),NoMenuMode)
+ BOOST_MSM_EUML_STATE(( NoOnOffButton_Entry ),NoOnOffButton)
+ BOOST_MSM_EUML_STATE(( OffDown_Entry ),OffDown)
+ BOOST_MSM_EUML_STATE(( PlayerOff_Entry ),PlayerOff)
+ BOOST_MSM_EUML_STATE(( CheckMiddleButton_Entry ),CheckMiddleButton)
+
+ // Concrete PlayingMode_ implementation
+ // The list of PlayingMode_ states
+ BOOST_MSM_EUML_STATE(( Playing_Entry ),Playing)
+ BOOST_MSM_EUML_STATE(( WaitingForNextPrev_Entry ),WaitingForNextPrev)
+ BOOST_MSM_EUML_STATE(( Paused_Entry ),Paused)
+ BOOST_MSM_EUML_STATE(( WaitingForEnd_Entry ),WaitingForEnd)
+ BOOST_MSM_EUML_STATE(( NoForward_Entry ),NoForward)
+ BOOST_MSM_EUML_STATE(( ForwardPressed_Entry,ForwardPressed_Exit ),ForwardPressed)
+ BOOST_MSM_EUML_STATE(( FastForward_Entry,FastForward_Exit ),FastForward)
+ BOOST_MSM_EUML_STATE(( StdDisplay_Entry ),StdDisplay)
+ BOOST_MSM_EUML_STATE(( SetPosition_Entry ),SetPosition)
+ BOOST_MSM_EUML_STATE(( SetMark_Entry ),SetMark)
+ BOOST_MSM_EUML_EXIT_STATE(( EndPlay,PlayingExit_Entry ),PlayingExit)
+
+ //stt
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + PlayPause ,
+ Paused == Playing + Off ,
+ Playing == Playing + StartSong
+ / (if_then_(event_(m_Selected) > Int_<0>() &&
+ event_(m_Selected) < fsm_(m_NumberOfSongs),
+ fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) ,
+ Playing == Playing + SongFinished
+ / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/
+ show_playing_song, /*then*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else*/ ) ) ,
+ Playing == Paused + PlayPause ,
+ Playing == Paused + StartSong
+ / (if_then_(event_(m_Selected) > Int_<0>() &&
+ event_(m_Selected) < fsm_(m_NumberOfSongs),
+ fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) ,
+ WaitingForNextPrev == WaitingForNextPrev+ PreviousSong
+ /( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(), /*if*/
+ show_playing_song, /*then*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ) ,
+ WaitingForNextPrev == WaitingForNextPrev+ NextSong
+ / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/
+ show_playing_song, /*then*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ),
+
+ PlayingExit == WaitingForEnd + EndPlay ,
+ ForwardPressed == NoForward + EastPressed [!is_flag_(NoFastFwd)] ,
+ NoForward == ForwardPressed + EastReleased / process_(NextSong) ,
+ FastForward == ForwardPressed + ForwardTimer / do_fast_forward ,
+ FastForward == FastForward + ForwardTimer / do_fast_forward ,
+ FastForward == NoForward + EastReleased ,
+ SetPosition == StdDisplay + PlayingMiddleButton ,
+ StdDisplay == SetPosition + StartSong ,
+ SetMark == SetPosition + PlayingMiddleButton ,
+ StdDisplay == SetMark + PlayingMiddleButton ,
+ StdDisplay == SetMark + StartSong
+ // +------------------------------------------------------------------------------+
+ ),playingmode_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playingmode_transition_table, //STT
+ init_ << Playing << WaitingForNextPrev << WaitingForEnd
+ << NoForward << StdDisplay, // Init States
+ fsm_(m_NumberOfSongs)=Int_<5>(), // entry
+ no_action, // exit
+ attributes_ << m_SongIndex << m_NumberOfSongs, //attributes
+ configure_<< NoFastFwd // Flags, Deferred events, configuration
+ ),PlayingMode_)
+
+ // choice of back-end
+ typedef msm::back::state_machine<PlayingMode_> PlayingMode_type;
+ PlayingMode_type const PlayingMode;
+
+ // Concrete MenuMode_ implementation
+ // The list of MenuMode_ states
+ BOOST_MSM_EUML_STATE(( WaitingForSongChoice_Entry ),WaitingForSongChoice)
+ BOOST_MSM_EUML_STATE(( StartCurrentSong_Entry ),StartCurrentSong)
+ BOOST_MSM_EUML_EXIT_STATE(( CloseMenu,MenuExit_Entry ),MenuExit)
+
+ //stt
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ StartCurrentSong == WaitingForSongChoice + MenuMiddleButton ,
+ MenuExit == StartCurrentSong + SelectSong
+ // +------------------------------------------------------------------------------+
+ ),menumode_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (menumode_transition_table, //STT
+ init_ << WaitingForSongChoice, // Init States
+ no_action, // entry
+ no_action, // exit
+ attributes_ << no_attributes_, //attributes
+ configure_<< MenuActive // Flags, Deferred events, configuration
+ ),MenuMode_)
+
+ typedef msm::back::state_machine<MenuMode_> MenuMode_type;
+ MenuMode_type const MenuMode;
+
+ // iPod stt
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Holding == NotHolding + Hold ,
+ NotHolding == Holding + NoHold ,
+ PlayingMode == NotPlaying + PlayPause ,
+ NotPlaying == exit_pt_(PlayingMode,PlayingExit) + EndPlay
+ / process_(MenuButton) ,
+ MenuMode == NoMenuMode + MenuButton ,
+ NoMenuMode == exit_pt_(MenuMode,MenuExit)+ CloseMenu
+ / process2_(StartSong,Int_<5>()) ,
+ OffDown == NoOnOffButton + SouthPressed ,
+ NoOnOffButton == OffDown + SouthReleased
+ / process_(PlayPause) ,
+ PlayerOff == OffDown + OnOffTimer
+ / (show_player_off,process_(Off)) ,
+ NoOnOffButton == PlayerOff + SouthPressed / show_player_on ,
+ NoOnOffButton == PlayerOff + NoHold / show_player_on ,
+ CheckMiddleButton == CheckMiddleButton + MiddleButton
+ [is_flag_(MenuActive)] / process_(PlayingMiddleButton) ,
+ CheckMiddleButton == CheckMiddleButton + MiddleButton
+ [!is_flag_(MenuActive)] / process_(PlayingMiddleButton)
+ // +------------------------------------------------------------------------------+
+ ),ipod_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( ipod_transition_table, //STT
+ init_ << NotHolding << NotPlaying << NoMenuMode
+ << NoOnOffButton << CheckMiddleButton
+ ),
+ iPod_) //fsm name
+ typedef msm::back::state_machine<iPod_> iPod;
+
+ void test()
+ {
+ iPod sm;
+ sm.start();
+ // we first press Hold
+ std::cout << "pressing hold" << std::endl;
+ sm.process_event(Hold);
+ // pressing a button is now ignored
+ std::cout << "pressing a button" << std::endl;
+ sm.process_event(SouthPressed);
+ // or even one contained in a submachine
+ sm.process_event(EastPressed);
+ // no more holding
+ std::cout << "no more holding, end interrupt event sent" << std::endl;
+ sm.process_event(NoHold);
+ std::cout << "pressing South button a short time" << std::endl;
+ sm.process_event(SouthPressed);
+ // we suppose a short pressing leading to playing a song
+ sm.process_event(SouthReleased);
+ // we move to the next song
+ std::cout << "we move to the next song" << std::endl;
+ sm.process_event(NextSong);
+ // then back to no song => exit from playing, menu active
+ std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
+ sm.process_event(PreviousSong);
+ sm.process_event(PreviousSong);
+ // even in menu mode, pressing play will start playing the first song
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(SouthReleased);
+ // of course pausing must be possible
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(SouthReleased);
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(SouthReleased);
+ // while playing, you can fast forward
+ std::cout << "pressing East button a long time" << std::endl;
+ sm.process_event(EastPressed);
+ // let's suppose the timer just fired
+ sm.process_event(ForwardTimer);
+ sm.process_event(ForwardTimer);
+ // end of fast forwarding
+ std::cout << "releasing East button" << std::endl;
+ sm.process_event(EastReleased);
+ // we now press the middle button to set playing at a given position
+ std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
+ sm.process_event(MiddleButton);
+ std::cout <<"pressing East button to fast forward" << std::endl;
+ sm.process_event(EastPressed);
+ // we switch off and on
+ std::cout <<"switch off player" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(OnOffTimer);
+ std::cout <<"switch on player" << std::endl;
+ sm.process_event(SouthPressed);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/iPodSearch.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPodSearch.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,198 @@
+#include <set>
+#include <string>
+#include <iostream>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct OneSong
+ {
+ OneSong(string const& asong):m_Song(asong){}
+ const string& get_data() const {return m_Song;}
+ private:
+ string m_Song;
+ };
+ template <class DATA>
+ struct NotFound
+ {
+ DATA get_data() const {return m_Data;}
+ DATA m_Data;
+ };
+ template <class DATA>
+ struct Found
+ {
+ DATA get_data() const {return m_Data;}
+ DATA m_Data;
+ };
+ struct Done {};
+
+ template <class Container,class BASE_TYPE,class FSMType>
+ struct Insert : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& )
+ {
+ //TODO other containers
+ if (m_Cont)
+ {
+ m_Cont->insert(evt.get_data());
+ }
+ m_fsm->process_event(Done());
+ }
+ void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
+ void set_container(Container* cont){m_Cont=cont;}
+ Container* m_Cont;
+
+ private:
+ FSMType* m_fsm;
+ };
+ template <class BASE_TYPE,class FSMType>
+ struct StringFind : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& )
+ {
+ //TODO other containers
+ // if the element in the event is found
+ if (evt.get_data().find(m_Cont) != std::string::npos )
+ {
+ Found<std::string> res;
+ res.m_Data = evt.get_data();
+ m_fsm->process_event(res);
+ }
+ // data not found
+ else
+ {
+ NotFound<std::string> res;
+ res.m_Data = evt.get_data();
+ m_fsm->process_event(res);
+ }
+ }
+ void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
+ void set_container(const char* cont){m_Cont=cont;}
+ private:
+ std::string m_Cont;
+ FSMType* m_fsm;
+ };
+ template <class EventType,class Container,class BASE_TYPE,class FSMType>
+ struct Foreach : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& )
+ {
+ //TODO other containers
+ if (!m_Cont.empty())
+ {
+ typename Container::value_type next_event = *m_Cont.begin();
+ m_Cont.erase(m_Cont.begin());
+ m_fsm->process_event(EventType(next_event));
+ }
+ }
+ void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
+ void set_container(Container* cont){m_Cont=*cont;}
+
+ private:
+ Container m_Cont;
+ FSMType* m_fsm;
+ };
+
+
+ // Concrete FSM implementation
+ struct iPodSearch_ : public msm::front::state_machine_def<iPodSearch_>
+ {
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+ // The list of FSM states
+ typedef std::set<std::string> Songset;
+ typedef Insert<Songset,boost::msm::front::default_base_state,iPodSearch> MyInsert;
+ typedef StringFind<boost::msm::front::default_base_state,iPodSearch> MyFind;
+ typedef Foreach<OneSong,Songset,boost::msm::front::default_base_state,iPodSearch> MyForeach;
+
+ // the initial state of the player SM. Must be defined
+ typedef MyForeach initial_state;
+
+ // transition actions
+
+ // guard conditions
+
+ typedef iPodSearch_ fsm; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +-----------+------------------+------------+---------------------+----------------------+
+ _row < MyForeach , OneSong , MyFind >,
+ _row < MyFind , NotFound<string> , MyForeach >,
+ _row < MyFind , Found<string> , MyInsert >,
+ _row < MyInsert , Done , MyForeach >
+ // +-----------+------------------+------------+---------------------+----------------------+
+ > {};
+ iPodSearch_():m_AllSongs(),m_ResultSearch()
+ {
+ // add a few songs for testing
+ m_AllSongs.insert("Let it be");
+ m_AllSongs.insert("Yellow submarine");
+ m_AllSongs.insert("Twist and Shout");
+ m_AllSongs.insert("She Loves You");
+ }
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<MyForeach&>().set_container(&m_AllSongs);
+ fsm.template get_state<MyInsert&>().set_container(&m_ResultSearch);
+ }
+ const Songset& get_result(){return m_ResultSearch;}
+ void reset_search(){m_ResultSearch.clear();}
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ private:
+ Songset m_AllSongs;
+ Songset m_ResultSearch;
+ };
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+
+
+ void test()
+ {
+ iPodSearch search;
+ // look for "She Loves You" using the first letters
+ search.get_state<iPodSearch::MyFind*>()->set_container("Sh");// will find 2 songs
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ search.start();
+ // display all the songs
+ const iPodSearch::Songset& res = search.get_result();
+ for (iPodSearch::Songset::const_iterator it = res.begin();it != res.end();++it)
+ {
+ cout << "candidate song:" << *it << endl;
+ }
+ cout << "search using more letters" << endl;
+ // look for "She Loves You" using more letters
+ search.reset_search();
+ search.get_state<iPodSearch::MyFind*>()->set_container("She");// will find 1 song
+ search.start();
+ const iPodSearch::Songset& res2 = search.get_result();
+ for (iPodSearch::Songset::const_iterator it = res2.begin();it != res2.end();++it)
+ {
+ cout << "candidate song:" << *it << endl;
+ }
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/iPodSearchEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPodSearchEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,156 @@
+// same as iPodSearch.cpp but using eUML
+// requires boost >= v1.40 because using mpl::string
+
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+#include <boost/msm/front/euml/stl.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+// how long the timer will ring when countdown elapsed.
+#define RINGING_TIME 5
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), OneSongDef)
+ struct OneSong_impl : euml_event<OneSong_impl>,OneSongDef
+ {
+ OneSong_impl(){}
+ OneSong_impl(const string& asong)
+ {
+ get_attribute(m_song)=asong;
+ }
+ OneSong_impl(const char* asong)
+ {
+ get_attribute(m_song)=asong;
+ }
+ OneSong_impl(const OneSong_impl& asong)
+ {
+ get_attribute(m_song)=asong.get_attribute(m_song);
+ }
+ const string& get_data() const {return get_attribute(m_song);}
+ };
+ OneSong_impl const OneSong;
+
+ // attribute definitions
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_src_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_tgt_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_letters)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>::iterator,m_src_it)
+
+ // the same attribute name can be reused
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), NotFoundDef)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(NotFound,NotFoundDef)
+
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(Found,FoundDef)
+
+ BOOST_MSM_EUML_EVENT(Done)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( (push_back_(fsm_(m_tgt_container),event_(m_song))
+ ,process_(Done)),
+ no_action ),Insert)
+
+ BOOST_MSM_EUML_STATE(( if_then_else_( string_find_(event_(m_song),state_(m_letters)) != Npos_<string>() ,
+ process2_(Found,event_(m_song)),
+ process2_(NotFound,event_(m_song)) ) ,
+ no_action,
+ attributes_ << m_letters ),StringFind)
+
+ BOOST_MSM_EUML_STATE(( if_then_( state_(m_src_it) != end_(fsm_(m_src_container)),
+ process2_(OneSong,*(state_(m_src_it)++)) ),
+ no_action,
+ attributes_ << m_src_it ),Foreach)
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ StringFind == Foreach + OneSong ,
+ Insert == StringFind + Found ,
+ Foreach == StringFind + NotFound ,
+ Foreach == Insert + Done
+ // +------------------------------------------------------------------------------+
+ ),transition_table )
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Foreach, // Init
+ (
+ clear_(fsm_(m_src_container)), //clear source
+ clear_(fsm_(m_tgt_container)), //clear results
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'Let ','it ','be'> >()),//add a song
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'Yell','ow s','ubma','rine'> >()),//add a song
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'Twis','t an','d Sh','out'> >()),//add a song
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'She ','love','s yo','u'> >()),//add a song
+ attribute_(substate_(Foreach()),m_src_it)
+ = begin_(fsm_(m_src_container)) //set the search begin
+ ), // Entry
+ no_action, // Exit
+ attributes_ << m_src_container // song list
+ << m_tgt_container, // result
+ configure_<< no_configure_,
+ Log_No_Transition
+ ),
+ iPodSearch_) //fsm name
+
+
+ // choice of back-end
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+
+ void test()
+ {
+ iPodSearch search;
+
+ // look for "She Loves You" using the first letters
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="Sh";// will find 2 songs
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ search.start();
+ // display all the songs
+ for (vector<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_attribute(m_song) << endl;
+ }
+
+ cout << "search using more letters" << endl;
+ // look for "She Loves You" using more letters
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="She";// will find 1 song
+ search.start();
+ // display all the songs
+ for (vector<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_attribute(m_song) << endl;
+ }
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/iPod_distributed/Events.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPod_distributed/Events.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,40 @@
+#ifndef EVENTS_HPP
+#define EVENTS_HPP
+
+//flags
+struct MenuActive{};
+// hardware-generated events
+struct Hold {};
+struct NoHold {};
+struct SouthPressed {};
+struct SouthReleased {};
+struct MiddleButton {};
+struct EastPressed{};
+struct EastReleased{};
+struct Off {};
+struct MenuButton {};
+
+// internally used events
+struct PlayPause {};
+struct EndPlay {};
+struct CloseMenu
+{
+ template<class EVENT>
+ CloseMenu(EVENT const &) {}
+};
+struct OnOffTimer {};
+struct MenuMiddleButton {};
+struct SelectSong {};
+struct SongFinished {};
+struct StartSong
+{
+ StartSong (int song_index):m_Selected(song_index){}
+ int m_Selected;
+};
+struct PreviousSong{};
+struct NextSong{};
+struct NextSongDerived : public NextSong{};
+struct ForwardTimer{};
+struct PlayingMiddleButton{};
+
+#endif // EVENTS_HPP
Added: trunk/libs/msm/doc/HTML/examples/iPod_distributed/MenuMode.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPod_distributed/MenuMode.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,2 @@
+#include "MenuMode.hpp"
+BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(MenuMode)
Added: trunk/libs/msm/doc/HTML/examples/iPod_distributed/MenuMode.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPod_distributed/MenuMode.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,52 @@
+#ifndef MENU_MODE_HPP
+#define MENU_MODE_HPP
+
+#include <iostream>
+#include <boost/any.hpp>
+
+#include "Events.hpp"
+#include <boost/msm/back/favor_compile_time.hpp>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+
+struct MenuMode_ : public msm::front::state_machine_def<MenuMode_>
+{
+ typedef mpl::vector1<MenuActive> flag_list;
+ struct WaitingForSongChoice : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::WaitingForSongChoice" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::WaitingForSongChoice" << std::endl;}
+ };
+ struct StartCurrentSong : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::StartCurrentSong" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::StartCurrentSong" << std::endl;}
+ };
+ struct MenuExit : public msm::front::exit_pseudo_state<CloseMenu>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::WaitingForSongChoice" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::WaitingForSongChoice" << std::endl;}
+ };
+ typedef WaitingForSongChoice initial_state;
+ typedef MenuMode_ fsm; // makes transition table cleaner
+ // Transition table for player
+ struct transition_table : mpl::vector2<
+ // Start Event Next Action Guard
+ // +---------------------+------------------+-------------------+---------------------+----------------------+
+ _row < WaitingForSongChoice , MenuMiddleButton , StartCurrentSong >,
+ _row < StartCurrentSong , SelectSong , MenuExit >
+ // +---------------------+------------------+-------------------+---------------------+----------------------+
+ > {};
+};
+typedef msm::back::state_machine<MenuMode_> MenuMode;
+
+#endif
Added: trunk/libs/msm/doc/HTML/examples/iPod_distributed/PlayingMode.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPod_distributed/PlayingMode.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,2 @@
+#include "PlayingMode.hpp"
+BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(PlayingMode)
Added: trunk/libs/msm/doc/HTML/examples/iPod_distributed/PlayingMode.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPod_distributed/PlayingMode.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,241 @@
+#ifndef PLAYING_MODE_HPP
+#define PLAYING_MODE_HPP
+
+#include <iostream>
+#include <boost/any.hpp>
+#define FUSION_MAX_VECTOR_SIZE 20
+
+#include "Events.hpp"
+#include <boost/msm/back/favor_compile_time.hpp>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace euml = boost::msm::front::euml;
+
+struct PlayingMode_ : public msm::front::state_machine_def<PlayingMode_>
+{
+ //flags
+ struct NoFastFwd{};
+
+ struct Playing : public msm::front::state<default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& )
+ {
+ std::cout << "starting: PlayingMode::Playing" << std::endl;
+ std::cout << "playing song:" << m_fsm->get_current_song() << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Playing" << std::endl;}
+ void set_sm_ptr(PlayingMode_* pl)
+ {
+ m_fsm = pl;
+ }
+ private:
+ PlayingMode_* m_fsm;
+ };
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Paused" << std::endl;}
+ };
+ struct WaitingForNextPrev : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForNextPrev" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForNextPrev" << std::endl;}
+ };
+ struct WaitingForEnd : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForEnd" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForEnd" << std::endl;}
+ };
+ struct NoForward : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::NoForward" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::NoForward" << std::endl;}
+ };
+ struct ForwardPressed : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& )
+ {
+ std::cout << "starting: PlayingMode::ForwardPressed," << "start timer" << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& )
+ {
+ std::cout << "finishing: PlayingMode::ForwardPressed," << "stop timer" << std::endl;
+ }
+ };
+ struct FastForward : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& )
+ {
+ std::cout << "starting: PlayingMode::FastForward," << "start timer" << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& )
+ {
+ std::cout << "finishing: PlayingMode::FastForward," << "stop timer" << std::endl;
+ }
+ };
+ struct StdDisplay : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::StdDisplay" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::StdDisplay" << std::endl;}
+ };
+ struct SetPosition : public msm::front::state<>
+ {
+ typedef mpl::vector1<NoFastFwd> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetPosition" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetPosition" << std::endl;}
+ };
+ struct SetMark : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetMark" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetMark" << std::endl;}
+ };
+ struct PlayingExit : public msm::front::exit_pseudo_state<EndPlay>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::PlayingExit" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::PlayingExit" << std::endl;}
+ };
+ // transition action methods
+ struct inc_song_counter : euml::euml_action<inc_song_counter>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ if (++fsm.m_SongIndex <= fsm.m_NumberOfSongs )
+ {
+ std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
+ }
+ else
+ {
+ // last song => end playing, next play will start at the beginning
+ fsm.m_SongIndex = 1;
+ fsm.process_event(EndPlay());
+ }
+ }
+ };
+
+ void select_song(StartSong const& evt)
+ {
+ if ((evt.m_Selected>0) && (evt.m_Selected<=m_NumberOfSongs))
+ {
+ m_SongIndex = evt.m_Selected;
+ std::cout << "selecting song:" << m_SongIndex << std::endl;
+ }
+ else
+ {
+ // play current song
+ std::cout << "selecting song:" << m_SongIndex << std::endl;
+ }
+ }
+ struct dec_song_counter : euml::euml_action<dec_song_counter>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ if (--fsm.m_SongIndex >0 )
+ {
+ std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
+ }
+ else
+ {
+ // before first song => end playing
+ fsm.m_SongIndex = 1;
+ fsm.process_event(EndPlay());
+ }
+ }
+ };
+ struct send_NextSong : euml::euml_action<send_NextSong>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ fsm.process_event(NextSong());
+ }
+ };
+
+ void do_fast_forward(ForwardTimer const&)
+ {
+ std::cout << "moving song forward..." << std::endl;
+ }
+
+ // transition guard methods
+ struct fast_fwd_ok : euml::euml_action<fast_fwd_ok>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ // guard accepts only if fast forward is possible (No SetPosition mode)
+ return !fsm.is_flag_active<NoFastFwd>();
+ }
+ };
+ // initial states / orthogonal zones
+ typedef mpl::vector5<Playing,WaitingForNextPrev,WaitingForEnd,NoForward,StdDisplay>
+ initial_state;
+ typedef PlayingMode_ fsm; // makes transition table cleaner
+ // Transition table for player
+ struct transition_table : mpl::vector19<
+ // Start Event Next Action Guard
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ _row < Playing , PlayPause , Paused >,
+ _row < Playing , Off , Paused >,
+ a_row < Playing , StartSong , Playing , &fsm::select_song >,
+ _row < Paused , PlayPause , Playing >,
+ msm::front::Row < Playing , SongFinished , Playing , inc_song_counter , msm::front::none >,
+ a_row < Paused , StartSong , Playing , &fsm::select_song >,
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ msm::front::Row < WaitingForNextPrev , PreviousSong , WaitingForNextPrev , dec_song_counter , msm::front::none >,
+ msm::front::Row < WaitingForNextPrev , NextSong , WaitingForNextPrev , inc_song_counter , msm::front::none >,
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ _row < WaitingForEnd , EndPlay , PlayingExit >,
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ msm::front::Row < NoForward , EastPressed , ForwardPressed , msm::front::none , fast_fwd_ok >,
+ msm::front::Row < ForwardPressed , EastReleased , NoForward , send_NextSong , msm::front::none >,
+ a_row < ForwardPressed , ForwardTimer , FastForward , &fsm::do_fast_forward >,
+ a_row < FastForward , ForwardTimer , FastForward , &fsm::do_fast_forward >,
+ _row < FastForward , EastReleased , NoForward >,
+ // +--------------------+---------------------+---------------------+--------------------------+----------------------+
+ _row < StdDisplay , PlayingMiddleButton , SetPosition >,
+ _row < SetPosition , StartSong , StdDisplay >,
+ _row < SetPosition , PlayingMiddleButton , SetMark >,
+ _row < SetMark , PlayingMiddleButton , StdDisplay >,
+ _row < SetMark , StartSong , StdDisplay >
+ // +--------------------+---------------------+---------------------+--------------------------+----------------------+
+ > {};
+ PlayingMode_():
+ m_SongIndex(1),
+ // for simplicity we decide there are 5 songs
+ m_NumberOfSongs(5){}
+
+ int get_current_song(){return m_SongIndex;}
+ int m_SongIndex;
+ int m_NumberOfSongs;
+
+};
+typedef msm::back::state_machine<PlayingMode_> PlayingMode;
+
+#endif // PLAYING_MODE_HPP
Added: trunk/libs/msm/doc/HTML/examples/iPod_distributed/iPod.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/iPod_distributed/iPod.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,234 @@
+#include <vector>
+#include <set>
+#include <string>
+#include <iostream>
+#define FUSION_MAX_VECTOR_SIZE 20
+
+#include "boost/mpl/vector/vector50.hpp"
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+#include "Events.hpp"
+#include "PlayingMode.hpp"
+#include "MenuMode.hpp"
+
+using namespace std;
+namespace msm = boost::msm;
+
+namespace // Concrete FSM implementation
+{
+ struct iPod_;
+ typedef msm::back::state_machine<iPod_,
+ ::boost::msm::back::NoHistory,
+ ::boost::msm::back::favor_compile_time> iPod;
+
+ // Concrete FSM implementation
+ struct iPod_ : public msm::front::state_machine_def<iPod_>
+ {
+ // The list of FSM states
+ struct NotHolding : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NotHolding" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotHolding" << std::endl;}
+ };
+ struct Holding : public msm::front::interrupt_state<NoHold>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Holding" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Holding" << std::endl;}
+ };
+ struct NotPlaying : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NotPlaying" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotPlaying" << std::endl;}
+ };
+ struct NoMenuMode : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NoMenuMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoMenuMode" << std::endl;}
+ };
+ struct NoOnOffButton : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NoOnOffButton" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoOnOffButton" << std::endl;}
+ };
+ struct OffDown : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: OffDown, start timer" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: OffDown, end timer" << std::endl;}
+ };
+ struct PlayerOff : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayerOff" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayerOff" << std::endl;}
+ };
+ struct CheckMiddleButton : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: CheckMiddleButton" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: CheckMiddleButton" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector5<NotHolding,NotPlaying,NoMenuMode,NoOnOffButton,CheckMiddleButton>
+ initial_state;
+ // transition actions
+ void send_ActivateMenu(EndPlay const&)
+ {
+ std::cout << "leaving Playing" << std::endl;
+ // we need to activate the menu and simulate its button
+ (static_cast<iPod*>(this))->process_event(MenuButton());
+ }
+ void send_StartSong(CloseMenu const&)
+ {
+ // we suppose the 5th song was selected
+ (static_cast<iPod*>(this))->process_event(StartSong(5));
+ }
+ void send_PlayPause(SouthReleased const&)
+ {
+ // action using the message queue to generate another event
+ (static_cast<iPod*>(this))->process_event(PlayPause());
+ }
+ void send_Off(OnOffTimer const&)
+ {
+ std::cout << "turning player off" << std::endl;
+ (static_cast<iPod*>(this))->process_event(Off());
+ }
+ void send_PlayingMiddleButton(MiddleButton const&)
+ {
+ (static_cast<iPod*>(this))->process_event(PlayingMiddleButton());
+ }
+ void send_MenuMiddleButton(MiddleButton const&)
+ {
+ (static_cast<iPod*>(this))->process_event(MenuMiddleButton());
+ }
+ // guard conditions
+ bool is_menu(MiddleButton const&)
+ {
+ return (static_cast<iPod*>(this))->is_flag_active<MenuActive>();
+ }
+ bool is_no_menu(MiddleButton const& evt)
+ {
+ return !is_menu(evt);
+ }
+ template <class EVENT>
+ void switch_on(EVENT const&)
+ {
+ std::cout << "turning player on" << std::endl;
+ }
+ typedef iPod_ fsm; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NotHolding , Hold , Holding >,
+ _row < Holding , NoHold , NotHolding >,
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NotPlaying , PlayPause , PlayingMode >,
+ a_row < PlayingMode::exit_pt<PlayingMode_::
+ PlayingExit> , EndPlay , NotPlaying , &fsm::send_ActivateMenu >,
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NoMenuMode , MenuButton , MenuMode >,
+ a_row < MenuMode::exit_pt<MenuMode_::
+ MenuExit> , CloseMenu , NoMenuMode , &fsm::send_StartSong >,
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NoOnOffButton , SouthPressed , OffDown >,
+ a_row < OffDown , SouthReleased , NoOnOffButton , &fsm::send_PlayPause >,
+ a_row < OffDown , OnOffTimer , PlayerOff , &fsm::send_Off >,
+ a_row < PlayerOff , SouthPressed , NoOnOffButton , &fsm::switch_on >,
+ a_row < PlayerOff , NoHold , NoOnOffButton , &fsm::switch_on >,
+ // +-------------------+---------------+--------------------+--------------------------------+----------------------+
+ row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_PlayingMiddleButton , &fsm::is_menu >,
+ row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_MenuMiddleButton , &fsm::is_no_menu >
+ // +-------------------+---------------+--------------------+--------------------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+
+ void test()
+ {
+ iPod sm;
+ sm.start();
+ // we first press Hold
+ std::cout << "pressing hold" << std::endl;
+ sm.process_event(Hold());
+ // pressing a button is now ignored
+ std::cout << "pressing a button" << std::endl;
+ sm.process_event(SouthPressed());
+ // or even one contained in a submachine
+ sm.process_event(EastPressed());
+ // no more holding
+ std::cout << "no more holding, end interrupt event sent" << std::endl;
+ sm.process_event(NoHold());
+ std::cout << "pressing South button a short time" << std::endl;
+ sm.process_event(SouthPressed());
+ // we suppose a short pressing leading to playing a song
+ sm.process_event(SouthReleased());
+ // we move to the next song
+ std::cout << "we move to the next song" << std::endl;
+ sm.process_event(NextSong());
+ // then back to no song => exit from playing, menu active
+ std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
+ sm.process_event(PreviousSong());
+ sm.process_event(PreviousSong());
+ // even in menu mode, pressing play will start playing the first song
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(SouthReleased());
+ // of course pausing must be possible
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(SouthReleased());
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(SouthReleased());
+ // while playing, you can fast forward
+ std::cout << "pressing East button a long time" << std::endl;
+ sm.process_event(EastPressed());
+ // let's suppose the timer just fired
+ sm.process_event(ForwardTimer());
+ sm.process_event(ForwardTimer());
+ // end of fast forwarding
+ std::cout << "releasing East button" << std::endl;
+ sm.process_event(EastReleased());
+ // we now press the middle button to set playing at a given position
+ std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
+ sm.process_event(MiddleButton());
+ std::cout <<"pressing East button to fast forward" << std::endl;
+ sm.process_event(EastPressed());
+ // we switch off and on
+ std::cout <<"switch off player" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(OnOffTimer());
+ std::cout <<"switch on player" << std::endl;
+ sm.process_event(SouthPressed());
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/HTML/examples/ipod_functors.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/ipod_functors.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,238 @@
+#ifndef IPOD_FUNCTORS_HPP
+#define IPOD_FUNCTORS_HPP
+#include <boost/msm/front/euml/euml.hpp>
+
+BOOST_MSM_EUML_ACTION(NotHolding_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NotHolding" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Holding_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Holding" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NotPlaying_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NotPlaying" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NoMenuMode_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NoMenuMode" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NoOnOffButton_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NoOnOffButton" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(OffDown_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: OffDown" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(PlayerOff_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: PlayerOff" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(CheckMiddleButton_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: CheckMiddleButton" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Playing_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM& fsm,STATE& )
+ {
+ std::cout << "entering: Playing" << std::endl;
+ std::cout << "playing song:" << fsm.get_attribute(m_SongIndex) << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(WaitingForNextPrev_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: WaitingForNextPrev" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Paused_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Paused" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(WaitingForEnd_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: OffDown" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NoForward_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NoForward" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(ForwardPressed_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: ForwardPressed" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(ForwardPressed_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: ForwardPressed" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(FastForward_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: FastForward" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(FastForward_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: FastForward" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(StdDisplay_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: StdDisplay" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(SetPosition_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SetPosition" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(SetMark_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SetMark" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(PlayingExit_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: PlayingExit" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(WaitingForSongChoice_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: WaitingForSongChoice" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(StartCurrentSong_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: StartCurrentSong" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(MenuExit_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: MenuExit" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_selected_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "selecting song:" << fsm.get_attribute(m_SongIndex) << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(do_fast_forward)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "moving song forward..." << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_playing_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "playing song:" << fsm.get_attribute(m_SongIndex) << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_player_off)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "turning player off" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_player_on)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "turning player on" << std::endl;
+ }
+};
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/examples/logging_functors.h
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/examples/logging_functors.h 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,360 @@
+#ifndef LOGGING_FUNCTORS
+#define LOGGING_FUNCTORS
+
+BOOST_MSM_EUML_ACTION(Empty_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Empty_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Open_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Open" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Open_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Open" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Stopped_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Stopped" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Stopped_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Stopped" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(AllOk_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: AllOk" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(AllOk_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: AllOk" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(ErrorMode_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: ErrorMode" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(ErrorMode_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: ErrorMode" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Playing_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Playing" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Playing_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Playing" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Song1_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: First song" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Song1_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: First Song" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Song2_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Second song" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Song2_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Second Song" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Song3_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Third song" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Song3_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Third Song" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Region2State1_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Region2State1" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Region2State1_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Region2State1" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Region2State2_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Region2State2" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Region2State2_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Region2State2" << std::endl;
+ }
+};
+// transition actions for Playing
+BOOST_MSM_EUML_ACTION(start_next_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::start_next_song" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(start_prev_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::start_prev_song" << endl;
+ }
+};
+
+// transition actions
+BOOST_MSM_EUML_ACTION(start_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(open_drawer)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(close_drawer)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(store_cd_info)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ // it is now easy to use the message queue.
+ // alternatively to the proces_ in the transition table, we could write:
+ // fsm.process_event(play());
+ }
+};
+BOOST_MSM_EUML_ACTION(stop_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(pause_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(resume_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(stop_and_open)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(stopped_again)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(report_error)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::report_error" << endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(report_end_error)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::report_end_error" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_action1)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal action1" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_action2)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal action2" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_action)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal action" << endl;
+ }
+};
+enum DiskTypeEnum
+{
+ DISK_CD=0,
+ DISK_DVD=1
+};
+
+// Handler called when no_transition detected
+BOOST_MSM_EUML_ACTION(Log_No_Transition)
+{
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(internal_guard1)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal guard1" << endl;
+ return false;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_guard2)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal guard2" << endl;
+ return false;
+ }
+};
+#endif // LOGGING_FUNCTORS
Added: trunk/libs/msm/doc/HTML/index.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/index.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,16 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Meta State Machine (MSM) V2.10</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="next" href="pr01.html" title="Preface"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Meta State Machine (MSM) V2.10</th></tr><tr><td width="20%" align="left"> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="pr01.html">Next</a></td></tr></table><hr></div><div class="book" title="Meta State Machine (MSM) V2.10"><div class="titlepage"><div><div><h1 class="title"><a name="d0e2"></a>Meta State Machine (MSM) V2.10</h1></div><div><div class="author"><h3 class="author">Christophe Henry</h3><code class="email"><<a class="email" href="mailto:christop
he.j.henry_at_[hidden]">christophe.j.henry_at_[hidden]</a>></code></div></div><div><p class="copyright">Copyright © 2008-2010
+ <span> Distributed under the Boost Software License, Version 1.0. (See
+ accompanying file LICENSE_1_0.txt or copy at <a class="link" href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt> ) </span>
+ </p></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="preface">Preface</span></dt><dt><span class="part">I. User' guide</span></dt><dd><dl><dt><span class="chapter">1. Founding idea</span></dt><dt><span class="chapter">2. UML Short Guide</span></dt><dd><dl><dt><span class="sect1">What are state machines?</span></dt><dt><span class="sect1">Concepts</span></dt><dd><dl><dt><span class="sect2">State machine, state, transition, event </span></dt><dt><span class="sect2">Submachines, orthogonal regions, pseudostates </span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e284">
+ History </a></span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e298">Completion transitions / anonymous
+ transitions</a></span></dt><dt><span class="sect2"> Internal transitions </span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e316">
+ Conflicting transitions </a></span></dt></dl></dd><dt><span class="sect1">State machine glossary</span></dt></dl></dd><dt><span class="chapter">3. Tutorial</span></dt><dd><dl><dt><span class="sect1">Design</span></dt><dt><span class="sect1">Basic front-end</span></dt><dd><dl><dt><span class="sect2">A simple example</span></dt><dt><span class="sect2">Transition table</span></dt><dt><span class="sect2">Defining states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Defining a submachine</span></dt><dt><span class="sect2">Orthogonal regions, terminate state, event deferring</span></dt><dt><span class=
"sect2">History</span></dt><dt><span class="sect2">Completion (anonymous) transitions</span></dt><dt><span class="sect2">Internal transitions</span></dt><dt><span class="sect2">more row types</span></dt><dt><span class="sect2">Explicit entry / entry and exit pseudo-state / fork</span></dt><dt><span class="sect2">Flags</span></dt><dt><span class="sect2">Event Hierarchy</span></dt><dt><span class="sect2">Customizing a state machine / Getting more speed</span></dt><dt><span class="sect2">Choosing the initial event</span></dt><dt><span class="sect2"> Containing state machine (deprecated)</span></dt></dl></dd><dt><span class="sect1"><a href="ch03s03.html">Functor front-
end</a></span></dt><dd><dl><dt><span class="sect2"> Transition table </span></dt><dt><span class="sect2">Defining states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Anonymous transitions</span></dt><dt><span class="sect2"><a href="ch03s03.html#d0e2462">Internal
+ transitions</a></span></dt></dl></dd><dt><span class="sect1">eUML (experimental)</span></dt><dd><dl><dt><span class="sect2">Transition table</span></dt><dt><span class="sect2">Defining events, actions and states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Defining a submachine</span></dt><dt><span class="sect2"><a href="ch03s04.html#d0e2958">
+ Attributes / Function call</a></span></dt><dt><span class="sect2">Orthogonal regions, flags, event deferring</span></dt><dt><span class="sect2"><a href="ch03s04.html#d0e3170">
+ Customizing a state machine / Getting
+ more speed</a></span></dt><dt><span class="sect2">Completion / Anonymous transitions</span></dt><dt><span class="sect2">Internal transitions</span></dt><dt><span class="sect2">Other state types</span></dt><dt><span class="sect2">Helper functions</span></dt><dt><span class="sect2">Phoenix-like STL support</span></dt></dl></dd><dt><span class="sect1">Back-end</span></dt><dd><dl><dt><span class="sect2">Creation </span></dt><dt><span class="sect2">Starting a state machine</span></dt><dt><span class="sect2">Event dispatching</span></dt><dt><span class="sect2">Active state(s)</span></dt><dt><span class="sect2"><a href="ch03s05.html#d0e3510">Base state ty
pe </a></span></dt><dt><span class="sect2">Visitor</span></dt><dt><span class="sect2">Flags</span></dt><dt><span class="sect2">Getting a state</span></dt><dt><span class="sect2"> State machine constructor with arguments </span></dt><dt><span class="sect2"><a href="ch03s05.html#d0e3620">Trading run-time speed for
+ better compile-time / multi-TU compilation</a></span></dt></dl></dd></dl></dd><dt><span class="chapter">4. Performance / Compilers</span></dt><dd><dl><dt><span class="sect1">Speed</span></dt><dt><span class="sect1">Executable size</span></dt><dt><span class="sect1">Supported compilers</span></dt><dt><span class="sect1"> Limitations </span></dt><dt><span class="sect1"> Compilers corner </span></dt></dl></dd><dt><span class="chapter">5. Questions & Answers</span></dt><dt><span class="chapter">6. Internals</span></dt><dd><dl><dt><span class="sect1">Backend: Run To Completion</span></dt><dt><span class="sect1"><a href="ch06s02.html">Frontend / Backend
+ interface</a></span></dt><dt><span class="sect1"> Generated state ids </span></dt><dt><span class="sect1">Metaprogramming tools</span></dt></dl></dd><dt><span class="chapter">7. Acknowledgements</span></dt><dd><dl><dt><span class="sect1">MSM v2</span></dt><dt><span class="sect1"> MSM v1</span></dt></dl></dd><dt><span class="chapter">8. Version history</span></dt><dd><dl><dt><span class="sect1">From V2.0 to V2.10</span></dt></dl></dd></dl></dd><dt><span class="part">II. Reference</span></dt><dd><dl><dt><span class="chapter">9. eUML operators and basic helpers</span></dt><dt><span class="chapter"><a href="ch10.html">10.
+ Functional programming </a></span></dt><dt><span class="refentrytitle">Common headers</span><span class="refpurpose"> — The common types used by front- and back-ends</span></dt><dt><span class="refentrytitle">Back-end</span><span class="refpurpose"> — The back-end headers</span></dt><dt><span class="refentrytitle">Front-end</span><span class="refpurpose"> — The front-end headers</span></dt></dl></dd></dl></div><div class="list-of-tables"><p><b>List of Tables</b></p><dl><dt>9.1. Operators and state machine helpers</dt><dt>10.1. STL algorithms</dt><dt>10.2. STL algorithms</dt><dt>10.3. STL algorithms</dt><dt>10.4. STL container methods</dt><dt>10.5. STL list methods</dt><dt>10.6. <a href="ch10.html#d0e5218">STL assoc
iative container methods </a></dt><dt>10.7. STL pair</dt><dt>10.8. STL string</dt></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="pr01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top"> </td><td width="20%" align="center"> </td><td width="40%" align="right" valign="top"> Preface</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/minimal.css
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/minimal.css 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,29 @@
+/*
+
+ © Copyright Beman Dawes, 2007
+
+ Distributed under the Boost Software License, Version 1.0.
+ See www.boost.org/LICENSE_1_0.txt
+
+*/
+
+/*******************************************************************************
+ Body
+*******************************************************************************/
+
+body { font-family: sans-serif; margin: 1em; }
+
+/*******************************************************************************
+ Table
+*******************************************************************************/
+
+table { margin: 0.5em; }
+
+/*******************************************************************************
+ Font sizes
+*******************************************************************************/
+
+p, td, li, blockquote { font-size: 10pt; }
+pre { font-size: 9pt; }
+
+/*** end ***/
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/pr01.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/pr01.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,61 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Preface</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="prev" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="next" href="pt01.html" title="Part I. User' guide"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Preface</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="pt01.html">Next</a></td></tr></table><hr></div><div class="preface" title="Preface"><div class="titlepage"><div><div><h2 class="title"><a name="d0e22"></a>Preface</h2></div></di
v></div><p>MSM is a library allowing you to easily and quickly define state machines of very high
+ performance. From this point, two main questions usually quickly arise, so please allow
+ me to try answering them upfront.</p><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>When do I need a state machine?</p><p>More often that you think. Very often, one defined a state machine
+ informally without even noticing it. For example, one declares inside a
+ class some boolean attribute, say to remember that a task has been
+ completed. Later the boolean actually needs a third value, so it becomes an
+ int. A few weeks, a second attribute is needed. Then a third. Soon, you find
+ yourself writing:</p><p><code class="code">void incoming_data(data)</code></p><p><code class="code">{</code></p><p><code class="code"> if (data == packet_3 && flag1 == work_done && flag2
+ > step3)...</code></p><p><code class="code">}</code></p><p>This starts to look like event processing (contained inside data) if some
+ stage of the object life has been achieved (but is ugly).</p><p>This could be a protocol definition and it is a common use case for state
+ machines. Another common one is a user interface. The stage of the user's
+ interaction defines if some button is active, a functionality is available,
+ etc.</p><p>But there are many more use cases if you start looking. Actually, a whole
+ model-driven development method, Executable UML
+ (http://en.wikipedia.org/wiki/Executable_UML) specifies its complete dynamic
+ behavior using state machines. Class diagram, state machine diagrams, and an
+ action language are all you absolutely need in the Executable UML
+ world.</p></li><li class="listitem"><p>Another state machine library? What for?</p><p>True, there are many state machine libraries. This should already be an
+ indication that if you're not using any of them, you might be missing
+ something. Why should you use this one? Unfortunately, when looking for a
+ good state machine library, you usually pretty fast hit one or several of
+ the following snags:</p><div class="itemizedlist"><ul class="itemizedlist" type="circle"><li class="listitem"><p>speed: "state machines are slow" is usually the first
+ criticism you might hear. While it is often an excuse not to use
+ any and instead resort to dirty, hand-written implementations (I
+ mean, no, yours are not dirty of course, I'm talking about other
+ developers). MSM removes this often feeble excuse because it is
+ blazingly fast. Most hand-written implementations will be beaten
+ by MSM.</p></li><li class="listitem"><p>ease of use: good argument. If you used another library, you
+ are probably right. Many state machine definitions will look
+ similar to:</p><p><code class="code">state s1 = new State; // a state</code></p><p><code class="code">state s2 = new State; // another state</code></p><p><code class="code">event e = new Event; // event</code></p><p><code class="code">s1->addTransition(e,s2); // transition s1 ->
+ s2</code></p><p>The more transitions you have, the less readable it is. A long
+ time ago, there was not so much Java yet, and many electronic
+ systems were built with a state machine defined by a simple
+ transition table. You could easily see the whole structure and
+ immediately see if you forgot some transitions. Thanks to our
+ new OO techniques, this ease of use was gone. MSM gives you back
+ the transition table and reduces the noise to the
+ minimum.</p></li><li class="listitem"><p>expressiveness: MSM offers several front-ends and constantly
+ tries to improve state machine definition techniques. For
+ example, you can define a transition with eUML (one of MSM's
+ front-ends) as:</p><p><code class="code">state1 == state2 + event [condition] /
+ action</code></p><p>This is not simply syntactic sugar. Such a formalized,
+ readable structure allows easy communication with domain experts
+ of a software to be constructed. Having domain experts
+ understand your code will greatly reduce the number of
+ bugs.</p></li><li class="listitem"><p>model-driven-development: a common difficulty of a
+ model-driven development is the complexity of making a
+ round-trip (generating code from model and then model from
+ code). This is due to the fact that if a state machine structure
+ is hard for you to read, chances are that your parsing tool will
+ also have a hard time. MSM's syntax will hopefully help tool
+ writers.</p></li><li class="listitem"><p>features: most developers use only 20% of the richly defined
+ UML standard. Unfortunately, these are never the same 20% for
+ all. And so, very likely, one will need something from the
+ standard which is not implemented. MSM offers a very large part
+ of the standard, with more on the way.</p></li></ul></div><p>Let us not wait any longer, I hope you will enjoy MSM and have fun with
+ it!</p></li></ul></div><p>
+ </p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="index.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="pt01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Meta State Machine (MSM) V2.10 </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Part I. User' guide</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/pt01.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/pt01.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,12 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Part I. User' guide</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="prev" href="pr01.html" title="Preface"><link rel="next" href="ch01.html" title="Chapter 1. Founding idea"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Part I. User' guide</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="pr01.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch01.html">Next</a></td></tr></table><hr></div><div class="part" title="Part I. User' guide"><div class="titlepage"><div><div><h1 class="title"
><a name="d0e96"></a>Part I. User' guide</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter">1. Founding idea</span></dt><dt><span class="chapter">2. UML Short Guide</span></dt><dd><dl><dt><span class="sect1">What are state machines?</span></dt><dt><span class="sect1">Concepts</span></dt><dd><dl><dt><span class="sect2">State machine, state, transition, event </span></dt><dt><span class="sect2">Submachines, orthogonal regions, pseudostates </span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e284">
+ History </a></span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e298">Completion transitions / anonymous
+ transitions</a></span></dt><dt><span class="sect2"> Internal transitions </span></dt><dt><span class="sect2"><a href="ch02s02.html#d0e316">
+ Conflicting transitions </a></span></dt></dl></dd><dt><span class="sect1">State machine glossary</span></dt></dl></dd><dt><span class="chapter">3. Tutorial</span></dt><dd><dl><dt><span class="sect1">Design</span></dt><dt><span class="sect1">Basic front-end</span></dt><dd><dl><dt><span class="sect2">A simple example</span></dt><dt><span class="sect2">Transition table</span></dt><dt><span class="sect2">Defining states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Defining a submachine</span></dt><dt><span class="sect2">Orthogonal regions, terminate state, event deferring</span></dt><dt><span class=
"sect2">History</span></dt><dt><span class="sect2">Completion (anonymous) transitions</span></dt><dt><span class="sect2">Internal transitions</span></dt><dt><span class="sect2">more row types</span></dt><dt><span class="sect2">Explicit entry / entry and exit pseudo-state / fork</span></dt><dt><span class="sect2">Flags</span></dt><dt><span class="sect2">Event Hierarchy</span></dt><dt><span class="sect2">Customizing a state machine / Getting more speed</span></dt><dt><span class="sect2">Choosing the initial event</span></dt><dt><span class="sect2"> Containing state machine (deprecated)</span></dt></dl></dd><dt><span class="sect1"><a href="ch03s03.html">Functor front-
end</a></span></dt><dd><dl><dt><span class="sect2"> Transition table </span></dt><dt><span class="sect2">Defining states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Anonymous transitions</span></dt><dt><span class="sect2"><a href="ch03s03.html#d0e2462">Internal
+ transitions</a></span></dt></dl></dd><dt><span class="sect1">eUML (experimental)</span></dt><dd><dl><dt><span class="sect2">Transition table</span></dt><dt><span class="sect2">Defining events, actions and states with entry/exit actions</span></dt><dt><span class="sect2">Defining a simple state machine</span></dt><dt><span class="sect2">Defining a submachine</span></dt><dt><span class="sect2"><a href="ch03s04.html#d0e2958">
+ Attributes / Function call</a></span></dt><dt><span class="sect2">Orthogonal regions, flags, event deferring</span></dt><dt><span class="sect2"><a href="ch03s04.html#d0e3170">
+ Customizing a state machine / Getting
+ more speed</a></span></dt><dt><span class="sect2">Completion / Anonymous transitions</span></dt><dt><span class="sect2">Internal transitions</span></dt><dt><span class="sect2">Other state types</span></dt><dt><span class="sect2">Helper functions</span></dt><dt><span class="sect2">Phoenix-like STL support</span></dt></dl></dd><dt><span class="sect1">Back-end</span></dt><dd><dl><dt><span class="sect2">Creation </span></dt><dt><span class="sect2">Starting a state machine</span></dt><dt><span class="sect2">Event dispatching</span></dt><dt><span class="sect2">Active state(s)</span></dt><dt><span class="sect2"><a href="ch03s05.html#d0e3510">Base state ty
pe </a></span></dt><dt><span class="sect2">Visitor</span></dt><dt><span class="sect2">Flags</span></dt><dt><span class="sect2">Getting a state</span></dt><dt><span class="sect2"> State machine constructor with arguments </span></dt><dt><span class="sect2"><a href="ch03s05.html#d0e3620">Trading run-time speed for
+ better compile-time / multi-TU compilation</a></span></dt></dl></dd></dl></dd><dt><span class="chapter">4. Performance / Compilers</span></dt><dd><dl><dt><span class="sect1">Speed</span></dt><dt><span class="sect1">Executable size</span></dt><dt><span class="sect1">Supported compilers</span></dt><dt><span class="sect1"> Limitations </span></dt><dt><span class="sect1"> Compilers corner </span></dt></dl></dd><dt><span class="chapter">5. Questions & Answers</span></dt><dt><span class="chapter">6. Internals</span></dt><dd><dl><dt><span class="sect1">Backend: Run To Completion</span></dt><dt><span class="sect1"><a href="ch06s02.html">Frontend / Backend
+ interface</a></span></dt><dt><span class="sect1"> Generated state ids </span></dt><dt><span class="sect1">Metaprogramming tools</span></dt></dl></dd><dt><span class="chapter">7. Acknowledgements</span></dt><dd><dl><dt><span class="sect1">MSM v2</span></dt><dt><span class="sect1"> MSM v1</span></dt></dl></dd><dt><span class="chapter">8. Version history</span></dt><dd><dl><dt><span class="sect1">From V2.0 to V2.10</span></dt></dl></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="pr01.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ch01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Preface </td>
<td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Chapter 1. Founding idea</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/pt02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/pt02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,4 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Part II. Reference</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="prev" href="ch08.html" title="Chapter 8. Version history"><link rel="next" href="ch09.html" title="Chapter 9. eUML operators and basic helpers"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Part II. Reference</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch08.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="ch09.html">Next</a></td></tr></table><hr></div><div class="part" title="Part II. Reference"><div
class="titlepage"><div><div><h1 class="title"><a name="d0e4286"></a>Part II. <span class="command"><strong><a name="Reference-begin"></a></strong></span>Reference</h1></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="chapter">9. eUML operators and basic helpers</span></dt><dt><span class="chapter"><a href="ch10.html">10.
+ Functional programming </a></span></dt><dt><span class="refentrytitle">Common headers</span><span class="refpurpose"> — The common types used by front- and back-ends</span></dt><dt><span class="refentrytitle">Back-end</span><span class="refpurpose"> — The back-end headers</span></dt><dt><span class="refentrytitle">Front-end</span><span class="refpurpose"> — The front-end headers</span></dt></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch08.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="ch09.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 8. Version history </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top">
Chapter 9. eUML operators and basic helpers</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/re01.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/re01.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,8 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Common headers</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt02.html" title="Part II. Reference"><link rel="prev" href="ch10.html" title="Chapter 10. Functional programming"><link rel="next" href="re02.html" title="Back-end"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Common headers</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch10.html">Prev</a> </td><th width="60%" align="center">Part II. Reference</th><td width="20%" align="right"> <a accesskey="n" href="re02.html">Next</a></td></tr></table><hr></div><div class="refentry" title="Common headers"><a name="d0e5757"></a><div class="titlepage"></div><div clas
s="refnamediv"><h2>Name</h2><p>Common headers — The common types used by front- and back-ends</p></div><div class="refsect1" title="msm/common.hpp"><a name="d0e5763"></a><h2>msm/common.hpp</h2><p>This header provides one type, wrap, which is an empty type whose only reason
+ to exist is to be cheap to construct, so that it can be used with mpl::for_each,
+ as shown in the Metaprogramming book, chapter 9.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Dummy> wrap{};</span></span> {<br>}</pre></div><div class="refsect1" title="msm/row_tags.hpp"><a name="d0e5772"></a><h2>msm/row_tags.hpp</h2><p>This header contains the row type tags which front-ends can support partially
+ or totally. Please see the <span class="command"><strong><a class="command" href="ch06s02.html#internals-front-back-interface">Internals</a></strong></span> section for a description of the different
+ types.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch10.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt02.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="re02.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 10.
+ Functional programming </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Back-end</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/re02.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/re02.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,113 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Back-end</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt02.html" title="Part II. Reference"><link rel="prev" href="re01.html" title="Common headers"><link rel="next" href="re03.html" title="Front-end"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Back-end</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="re01.html">Prev</a> </td><th width="60%" align="center">Part II. Reference</th><td width="20%" align="right"> <a accesskey="n" href="re03.html">Next</a></td></tr></table><hr></div><div class="refentry" title="Back-end"><a name="d0e5780"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>Back-end —
The back-end headers</p></div><div class="refsect1" title="msm/back/state_machine.hpp"><a name="d0e5786"></a><h2>msm/back/state_machine.hpp</h2><p> This header provides one type, state_machine, MSM's state machine engine
+ implementation.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Derived,class HistoryPolicy=NoHistory,class
+ CompilePolicy=favor_runtime_speed> state_machine</span></span> {<br>}</pre><div class="refsect2" title="Template arguments"><a name="d0e5795"></a><h3> Template arguments </h3><div class="refsect3" title="Derived"><a name="d0e5798"></a><h4> Derived </h4><p>The name of the front-end state machine definition. All three
+ front-ends are possible.</p></div><div class="refsect3" title="HistoryPolicy"><a name="d0e5803"></a><h4> HistoryPolicy </h4><p>The desired history. This can be: AlwaysHistory, NoHistory,
+ ShallowHistory. Default is NoHistory.</p></div><div class="refsect3" title="CompilePolicy"><a name="d0e5808"></a><h4> CompilePolicy </h4><p>The trade-off performance / compile-time. There are two predefined
+ policies, favor_runtime_speed and favor_compile_time. Default is
+ favor_runtime_speed, best performance, longer compile-time. See <a class="link" href="ch03s05.html#backend-tradeof-rt-ct">the backend</a>.</p></div></div><div class="refsect2" title="methods"><a name="d0e5816"></a><h3> methods </h3><div class="refsect3" title="start"><a name="d0e5819"></a><h4>start</h4><p> The start methods must be called before any call to process_event. It
+ activates the entry action of the initial state(s). This allows you to
+ choose when a state machine can start. See <a class="link" href="ch03s05.html#backend-start">backend</a>.</p><code class="methodsynopsis"><span class="methodname">void start</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="process_event"><a name="d0e5832"></a><h4>process_event</h4><p>The event processing method implements the double-dispatch. Each call
+ to this function with a new event type instantiates a new dispatch
+ algorithm and increases compile-time.</p><code class="methodsynopsis"><span class="methodname">template <class Event> HandledEnum
+ process_event</span>(<span class="methodparam">Event const&</span>);</code></div><div class="refsect3" title="current_state"><a name="d0e5843"></a><h4>current_state</h4><p>Returns the ids of currently active states. You will typically need it
+ only for debugging or logging purposes.</p><code class="methodsynopsis"><span class="methodname">const int* current_state const</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="get_state_by_id"><a name="d0e5853"></a><h4>get_state_by_id</h4><p>Returns the state whose id is given. As all states of a concrete state
+ machine share a common base state, the return value is a base state. If
+ the id corresponds to no state, a null pointer is returned.</p><code class="methodsynopsis"><span class="methodname">const BaseState* get_state_by_id const</span>(<span class="methodparam">int id</span>);</code></div><div class="refsect3" title="is_contained"><a name="d0e5864"></a><h4>is_contained</h4><p>Helper returning true if the state machine is contained as a
+ submachine of another state machine.</p><code class="methodsynopsis"><span class="methodname">bool is_contained const</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="get_state"><a name="d0e5874"></a><h4>get_state</h4><p>Returns the required state of the state machine as a pointer. A
+ compile error will occur if the state is not to be found in the state
+ machine.</p><code class="methodsynopsis"><span class="methodname">template <class State> State* get_state</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="get_state"><a name="d0e5884"></a><h4>get_state</h4><p>Returns the required state of the state machine as a reference. A
+ compile error will occur if the state is not to be found in the state
+ machine.</p><code class="methodsynopsis"><span class="methodname">template <class State> State& get_state</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="is_flag_active"><a name="d0e5894"></a><h4>is_flag_active</h4><p>Returns true if the given flag is currently active. A flag is active
+ if the active state of one region is tagged with this flag (using OR as
+ BinaryOp) or active states of <span class="underline">all</span>
+ regions (using AND as BinaryOp)</p><code class="methodsynopsis"><span class="methodname">template <class Flag,class BinaryOp> bool
+ is_flag_active</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="is_flag_active"><a name="d0e5907"></a><h4>is_flag_active</h4><p>Returns true if the given flag is currently active. A flag is active
+ if the active state of one region is tagged with this flag.</p><code class="methodsynopsis"><span class="methodname">template <class Flag> bool is_flag_active</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="visit_current_states"><a name="d0e5917"></a><h4>visit_current_states</h4><p>Visits all active states and their substates. A state is visited using
+ the <code class="code">accept</code> method without argument. The base class of all
+ states must provide an <code class="code">accept_sig</code> type.</p><code class="methodsynopsis"><span class="methodname">void visit_current_states</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="visit_current_states"><a name="d0e5933"></a><h4>visit_current_states</h4><p>Visits all active states and their substates. A state is visited using
+ the <code class="code">accept</code> method with arguments. The base class of all
+ states must provide an <code class="code">accept_sig</code> type defining the
+ signature and thus the number and type of the parameters.</p><code class="methodsynopsis"><span class="methodname">void visit_current_states</span>(<span class="methodparam">any-type param1, any-type param2,...</span>);</code></div><div class="refsect3" title="defer_event"><a name="d0e5950"></a><h4>defer_event</h4><p> Defers the provided event. This method can be called only if at least
+ one state defers an event or if the state machine provides the
+ <code class="code">activate_deferred_events</code>(see <a class="link" href="examples/Orthogonal-deferred2.cpp" target="_top">example</a>) type
+ either directly or using the deferred_events configuration of eUML
+ (<code class="code">configure_ << deferred_events</code>)</p><code class="methodsynopsis"><span class="methodname">template <class Event> void defer_event</span>(<span class="methodparam">Event const&</span>);</code></div></div><div class="refsect2" title="Types"><a name="d0e5970"></a><h3>Types</h3><div class="refsect3" title="nr_regions"><a name="d0e5973"></a><h4>nr_regions </h4><p>The number of orthogonal regions contained in the state machine</p></div><div class="refsect3" title="entry_pt"><a name="d0e5978"></a><h4>entry_pt</h4><p>This nested type provides the necessary typedef for entry point
+ pseudostates.
+ <code class="code">state_machine<...>::entry_pt<state_name></code> is a
+ transition's valid target inside the containing state machine's
+ transition table.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">entry_pt</span></span> {<br>}</pre></div><div class="refsect3" title="exit_pt"><a name="d0e5990"></a><h4>exit_pt</h4><p>This nested type provides the necessary typedef for exit point
+ pseudostates. <code class="code">state_machine<...>::exit_pt<state_name></code>
+ is a transition's valid source inside the containing state machine's
+ transition table.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">exit_pt</span></span> {<br>}</pre></div><div class="refsect3" title="direct"><a name="d0e6002"></a><h4>direct</h4><p>This nested type provides the necessary typedef for an explicit entry
+ inside a submachine.
+ <code class="code">state_machine<...>::direct<state_name></code> is a
+ transition's valid target inside the containing state machine's
+ transition table.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">direct</span></span> {<br>}</pre></div><div class="refsect3" title="stt"><a name="d0e6014"></a><h4>stt</h4><p>Calling state_machine<frontend>::stt returns a mpl::vector
+ containing the transition table of the state machine. This type can then
+ be used with generate_state_set or generate_event_set.</p></div></div></div><div class="refsect1" title="args.hpp"><a name="d0e6019"></a><h2>args.hpp</h2><p>This header provides one type, args. which provides the necessary types for a
+ visitor implementation.</p></div><div class="refsect1" title="msm/back/history_policies.hpp"><a name="d0e6024"></a><h2><span class="command"><strong><a name="history-interface"></a></strong></span>msm/back/history_policies.hpp</h2><p>This header provides the out-of-the-box history policies supported by MSM.
+ There are 3 such policies.</p><div class="refsect2" title="Every history policy must implement the following methods:"><a name="d0e6030"></a><h3>Every history policy must implement the following methods: </h3><div class="refsect3" title="set_initial_states"><a name="d0e6033"></a><h4> set_initial_states </h4><p> This method is called by msm::back::state_machine when constructed.
+ It gives the policy a chance to save the ids of all initial states
+ (passed as array).</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">void set_initial_states(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>int* const<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect3" title="history_exit"><a name="d0e6047"></a><h4> history_exit </h4><p>This method is called by msm::back::state_machine when the submachine
+ is exited. It gives the policy a chance to remember the ids of the last
+ active substates of this submachine (passed as array).</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">void history_exit(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>int* const<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect3" title="history_entry"><a name="d0e6061"></a><h4> history_entry </h4><p>This method is called by msm::back::state_machine when the submachine
+ is entered. It gives the policy a chance to set the active states
+ according to the policy's aim. The policy gets as parameter the event
+ which activated the submachine and returns an array of active states
+ ids.</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Event> int* const history_exit(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Event const&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div></div><div class="refsect2" title="Out-of-the-box policies:"><a name="d0e6075"></a><h3>Out-of-the-box policies: </h3><div class="refsect3" title="NoHistory"><a name="d0e6078"></a><h4>NoHistory</h4><p>This policy is the default used by state_machine. No active state of a
+ submachine is remembered and at every new activation of the submachine,
+ the initial state(s) are activated. </p></div><div class="refsect3" title="AlwaysHistory"><a name="d0e6083"></a><h4>AlwaysHistory</h4><p>This policy is a non-UML-standard extension. The active state(s) of a
+ submachine is (are) always remembered at every new activation of the
+ submachine. </p></div><div class="refsect3" title="ShallowHistory"><a name="d0e6088"></a><h4>ShallowHistory</h4><p>This policy activates the active state(s) of a submachine if the event
+ is found in the policy's event list. </p></div></div></div><div class="refsect1" title="msm/back/default_compile_policy.hpp"><a name="d0e6093"></a><h2>msm/back/default_compile_policy.hpp</h2><p>This header contains the definition of favor_runtime_speed. This policy has
+ two settings:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Submachines dispatch faster because their transitions are added
+ into their containing machine's transition table instead of simply
+ forwarding events.</p></li><li class="listitem"><p>It solves transition conflicts at compile-time</p></li></ul></div></div><div class="refsect1" title="msm/back/favor_compile_time.hpp"><a name="d0e6105"></a><h2>msm/back/favor_compile_time.hpp</h2><p>This header contains the definition of favor_compile_time. This policy has two settings:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Submachines dispatch is slower because all events, even those with
+ no dispatch chance, are forwarded to submachines. In exchange, no
+ row is added into the containing machine's transition table, which
+ reduces compile-time.</p></li><li class="listitem"><p>It solves transition conflicts at run-time.</p></li></ul></div></div><div class="refsect1" title="msm/back/metafunctions.hpp"><a name="d0e6117"></a><h2>msm/back/metafunctions.hpp </h2><p>This header contains metafunctions for use by the library. Three metafunctions
+ can be useful for the user:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">generate_state_set< stt ></code>: generates the list of
+ all states referenced by the transition table stt. If stt is a
+ recursive table (generated by
+ <code class="code">recursive_get_transition_table</code>), the metafunction
+ finds recursively all states of the submachines. A non-recursive
+ table can be obtained with some_backend_fsm::stt.</p></li><li class="listitem"><p><code class="code">generate_event_set< stt></code>: generates the list of
+ all events referenced by the transition table stt. If stt is a
+ recursive table (generated by
+ <code class="code">recursive_get_transition_table</code>), the metafunction
+ finds recursively all events of the submachines. A non-recursive
+ table can be obtained with some_backend_fsm::stt.</p></li><li class="listitem"><p><code class="code">recursive_get_transition_table<fsm></code>: recursively
+ extends the transition table of the state machine fsm with tables
+ from the submachines.</p></li></ul></div></div><div class="refsect1" title="msm/back/tools.hpp"><a name="d0e6144"></a><h2>msm/back/tools.hpp </h2><p> This header contains a few metaprogramming tools to get some information out
+ of a state machine.</p><div class="refsect2" title="fill_state_names"><a name="d0e6149"></a><h3>fill_state_names </h3><div class="refsect3" title="attributes"><a name="d0e6152"></a><h4>attributes </h4><p> fill_state_names has for attribute:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">char const** m_names</code>: an already allocated
+ array of const char* where the typeid-generated names of a
+ state machine states will be witten.</p></li></ul></div></div><div class="refsect3" title="constructor"><a name="d0e6163"></a><h4>constructor </h4><code class="constructorsynopsis"><span class="methodparam">char const** names_to_fill</span>(<span class="methodparam">char const** names_to_fill</span>);</code></div><div class="refsect3" title="usage"><a name="d0e6170"></a><h4>usage</h4><p> fill_state_names is made for use in a mpl::for_each iterating on a
+ state list and writing inside a pre-allocated array the state names.
+ Example:</p><pre class="programlisting">typedef some_fsm::stt Stt;
+typedef msm::back::generate_state_set<Stt>::type all_states; //states
+static char const* state_names[mpl::size<all_states>::value];
+// array to fill with names
+// fill the names of the states defined in the state machine
+mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
+ (msm::back::fill_state_names<Stt>(state_names));
+// display all active states
+for (unsigned int i=0;i<some_fsm::nr_regions::value;++i)
+{
+ std::cout << " -> "
+ << state_names[my_fsm_instance.current_state()[i]]
+ << std::endl;
+}</pre></div></div><div class="refsect2" title="get_state_name"><a name="d0e6177"></a><h3>get_state_name </h3><div class="refsect3" title="attributes"><a name="d0e6180"></a><h4> attributes </h4><p>get_state_name has for attributes:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>std::string& m_name: the return value of the
+ iteration</p></li><li class="listitem"><p>int m_state_id: the searched state's id</p></li></ul></div></div><div class="refsect3" title="constructor"><a name="d0e6192"></a><h4>constructor</h4><p>The constructor takes as argument a reference to the string to fill
+ with the state name and the id which must be searched.</p><code class="constructorsynopsis"><span class="methodparam">string& name_to_fill,int state_id</span>(<span class="methodparam">string& name_to_fill,int state_id</span>);</code></div><div class="refsect3" title="usage"><a name="d0e6201"></a><h4> usage</h4><p>This type is made for the same search as in the previous example,
+ using a mpl::for_each to iterate on states. After the iteration, the
+ state name reference has been set.</p></div></div><div class="refsect2" title="display_type"><a name="d0e6206"></a><h3>display_type </h3><div class="refsect3" title="attributes"><a name="d0e6209"></a><h4> attributes </h4><p>none</p></div><div class="refsect3" title="usage"><a name="d0e6214"></a><h4> usage</h4><p>Reusing the state list from the previous example, we can output all
+ state names:</p><p><code class="code">mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1>
+ >(msm::back::display_type ());</code></p></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="re01.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt02.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="re03.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Common headers </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Front-end</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/re03.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/re03.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,778 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Front-end</title><link rel="stylesheet" href="boostbook.css" type="text/css"><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM) V2.10"><link rel="up" href="pt02.html" title="Part II. Reference"><link rel="prev" href="re02.html" title="Back-end"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Front-end</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="re02.html">Prev</a> </td><th width="60%" align="center">Part II. Reference</th><td width="20%" align="right"> </td></tr></table><hr></div><div class="refentry" title="Front-end"><a name="d0e6222"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>Front-end — The front-end headers</p></div><div class="refsect1" title="msm/front/common_states.hpp"><a name
="d0e6228"></a><h2>msm/front/common_states.hpp</h2><p>This header contains the predefined types to serve as base for states or state machines:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>default_base_state: non-polymorphic empty type.</p></li><li class="listitem"><p>polymorphic_state: type with a virtual destructor, which makes all
+ states polymorphic.</p></li></ul></div></div><div class="refsect1" title="msm/front/completion_event.hpp"><a name="d0e6240"></a><h2>msm/front/completion_event.hpp</h2><p>This header contains one type, <code class="code">none</code>. This type has several
+ meanings inside a transition table:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>as action or guard: that there is no action or guard</p></li><li class="listitem"><p>as target state: that the transition is an internal
+ transition</p></li><li class="listitem"><p>as event: the transition is an anonymous (completion)
+ transition</p></li></ul></div></div><div class="refsect1" title="msm/front/functor_row.hpp"><a name="d0e6258"></a><h2>msm/front/functor_row.hpp</h2><p>This header implements the functor front-end's transitions and helpers.</p><div class="refsect2" title="Row"><a name="d0e6263"></a><h3>Row</h3><div class="refsect3" title="definition"><a name="d0e6266"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Source,class Event,class Target,class
+ Action,class Guard> Row</span></span> {<br>}</pre></div><div class="refsect3" title="tags"><a name="d0e6273"></a><h4>tags</h4><p>row_type_tag is defined differently for every specialization:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>all 5 template parameters means a normal transition with
+ action and guard: <code class="code">typedef row_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Row<Source,Event,Target,none,none> a normal transition
+ without action or guard: <code class="code">typedef _row_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Row<Source,Event,Target,Action,none> a normal
+ transition without guard: <code class="code">typedef a_row_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Row<Source,Event,Target,none,Guard> a normal transition
+ without action: <code class="code">typedef g_row_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Row<Source,Event,none,Action,none> an internal
+ transition without guard: <code class="code">typedef a_irow_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Row<Source,Event,none,none,Guard> an internal
+ transition without action: <code class="code">typedef g_irow_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Row<Source,Event,none,none,Guard> an internal
+ transition with action and guard: <code class="code">typedef irow_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Row<Source,Event,none,none,none> an internal transition
+ without action or guard: <code class="code">typedef _irow_tag
+ row_type_tag;</code></p></li></ul></div></div><div class="refsect3" title="methods"><a name="d0e6319"></a><h4>methods</h4><p>Like any other front-end, Row implements the two necessary static
+ functions for action and guard call. Each function receives as parameter
+ the (deepest-level) state machine processsing the event, the event
+ itself, the source and target states and all the states contained in a
+ state machine.</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div></div><div class="refsect2" title="Internal"><a name="d0e6342"></a><h3>Internal</h3><div class="refsect3" title="definition"><a name="d0e6345"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Event,class Action,class Guard>
+ Internal</span></span> {<br>}</pre></div><div class="refsect3" title="tags"><a name="d0e6352"></a><h4>tags</h4><p>row_type_tag is defined differently for every specialization:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>all 3 template parameters means an internal transition
+ with action and guard: <code class="code">typedef sm_i_row_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Internal<Event,none,none> an internal transition
+ without action or guard: <code class="code">typedef sm__i_row_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Internal<Event,Action,none> an internal transition
+ without guard: <code class="code">typedef sm_a_i_row_tag
+ row_type_tag;</code></p></li><li class="listitem"><p>Internal<Event,none,Guard> an internal transition
+ without action: <code class="code">typedef sm_g_i_row_tag
+ row_type_tag;</code></p></li></ul></div></div><div class="refsect3" title="methods"><a name="d0e6378"></a><h4>methods</h4><p>Like any other front-end, Internal implements the two necessary static
+ functions for action and guard call. Each function receives as parameter
+ the (deepest-level) state machine processsing the event, the event
+ itself, the source and target states and all the states contained in a
+ state machine.</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div></div><div class="refsect2" title="ActionSequence_"><a name="d0e6401"></a><h3>ActionSequence_</h3><p>This functor calls every element of the template Sequence (which are also
+ callable functors) in turn. It is also the underlying implementation of the
+ eUML sequence grammar (action1,action2,...).</p><div class="refsect3" title="definition"><a name="d0e6406"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Sequence> ActionSequence_</span></span> {<br>}</pre></div><div class="refsect3" title="methods"><a name="d0e6413"></a><h4>methods</h4><p>This helper functor is made for use in a transition table and in a
+ state behavior and therefore implements an operator() with 3 and with 4
+ arguments:</p><p>
+ </p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Evt,class Fsm,class
+ SourceState,class TargetState> operator()(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Evt const& ,Fsm& ,SourceState&
+ ,TargetState& </code>;</div><div class="funcprototype-spacer"> </div></div><p>
+ </p><p>
+ </p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Evt,class Fsm,class State>
+ operator()(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Evt const&, Fsm&, State&</code>;</div><div class="funcprototype-spacer"> </div></div><p>
+ </p></div></div><div class="refsect2" title="Defer"><a name="d0e6436"></a><h3>Defer</h3><div class="refsect3" title="definition"><a name="d0e6439"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">Defer</span></span> {<br>}</pre></div><div class="refsect3" title="methods"><a name="d0e6446"></a><h4>methods</h4><p>This helper functor is made for use in a transition table and
+ therefore implements an operator() with 4 arguments:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Evt,class Fsm,class SourceState,class
+ TargetState> operator()(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Evt const&, Fsm& , SourceState&,
+ TargetState&</code>;</div><div class="funcprototype-spacer"> </div></div></div></div></div><div class="refsect1" title="msm/front/internal_row.hpp"><a name="d0e6457"></a><h2>msm/front/internal_row.hpp</h2><p>This header implements the internal transition rows for use inside an
+ internal_transition_table. All these row types have no source or target state,
+ as the backend will recognize internal transitions from this
+ internal_transition_table.</p><div class="refsect2" title="methods"><a name="d0e6462"></a><h3>methods</h3><p>Like any other front-end, the following transition row types implements
+ the two necessary static functions for action and guard call. Each function
+ receives as parameter the (deepest-level) state machine processsing the
+ event, the event itself, the source and target states and all the states
+ contained in a state machine.</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect2" title="a_internal"><a name="d0e6485"></a><h3>a_internal</h3><div class="refsect3" title="definition"><a name="d0e6488"></a><h4>definition</h4><p>This is an internal transition with an action called during the
+ transition.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Event, class CalledForAction, void
+ (CalledForAction::*action)(Event const&)>
+ a_internal</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6497"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the internal
+ transition.</p></li><li class="listitem"><p>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>action: a pointer to the method which CalledForAction
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="g_internal"><a name="d0e6513"></a><h3>g_internal</h3><p>This is an internal transition with a guard called before the transition
+ and allowing the transition if returning true.</p><div class="refsect3" title="definition"><a name="d0e6518"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Event, class CalledForGuard, bool
+ (CalledForGuard::*guard)(Event const&)>
+ g_internal</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6525"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the internal
+ transition.</p></li><li class="listitem"><p>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>guard: a pointer to the method which CalledForGuard
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="internal"><a name="d0e6541"></a><h3>internal</h3><p>This is an internal transition with a guard called before the transition
+ and allowing the transition if returning true. It also calls an action
+ called during the transition.</p><div class="refsect3" title="definition"><a name="d0e6546"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Event, class CalledForAction, void
+ (CalledForAction::*action)(Event const&), class
+ CalledForGuard, bool (CalledForGuard::*guard)(Event const&)>
+ internal</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6553"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the internal transition</p></li><li class="listitem"><p>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>action: a pointer to the method which CalledForAction
+ provides.</p></li><li class="listitem"><p>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>guard: a pointer to the method which CalledForGuard
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="_internal"><a name="d0e6575"></a><h3>_internal</h3><p>This is an internal transition without action or guard. This is equivalent
+ to an explicit "ignore event".</p><div class="refsect3" title="definition"><a name="d0e6580"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Event > _internal</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6587"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the internal
+ transition.</p></li></ul></div><p>
+ </p></div></div></div><div class="refsect1" title="msm/front/row2.hpp"><a name="d0e6597"></a><h2>msm/front/row2.hpp</h2><p>This header contains the variants of row2, which are an extension of the
+ standard row transitions for use in the transition table. They offer the
+ possibility to define action and guard not only in the state machine, but in any
+ state of the state machine. They can also be used in internal transition tables
+ through their irow2 variants.</p><div class="refsect2" title="methods"><a name="d0e6602"></a><h3>methods</h3><p>Like any other front-end, the following transition row types implements
+ the two necessary static functions for action and guard call. Each function
+ receives as parameter the (deepest-level) state machine processsing the
+ event, the event itself, the source and target states and all the states
+ contained in a state machine.</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect2" title="_row2"><a name="d0e6625"></a><h3>_row2</h3><p>This is a transition without action or guard. The state machine only
+ changes active state.</p><div class="refsect3" title="definition"><a name="d0e6630"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Source, class Event, class Target >
+ _row2</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6637"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="a_row2"><a name="d0e6653"></a><h3>a_row2</h3><p>This is a transition with action and without guard.</p><div class="refsect3" title="definition"><a name="d0e6658"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Source, class Event, class Target,
+ </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForAction, void
+ (CalledForAction::*action)(Event const&) > _row2</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6669"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li><li class="listitem"><p>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>action: a pointer to the method which CalledForAction
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="g_row2"><a name="d0e6691"></a><h3>g_row2</h3><p>This is a transition with guard and without action.</p><div class="refsect3" title="definition"><a name="d0e6696"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Source, class Event, class Target,
+ </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6707"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li><li class="listitem"><p>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>guard: a pointer to the method which CalledForGuard
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="row2"><a name="d0e6729"></a><h3>row2</h3><p>This is a transition with guard and action.</p><div class="refsect3" title="definition"><a name="d0e6734"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Source, class Event, class Target,
+ </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForAction, void
+ (CalledForAction::*action)(Event const&), </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6749"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li><li class="listitem"><p>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>action: a pointer to the method which CalledForAction
+ provides.</p></li><li class="listitem"><p>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>guard: a pointer to the method which CalledForGuard
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="a_irow2"><a name="d0e6777"></a><h3>a_irow2</h3><p>This is an internal transition for use inside a transition table, with
+ action and without guard.</p><div class="refsect3" title="definition"><a name="d0e6782"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Source, class Event, </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForAction, void
+ (CalledForAction::*action)(Event const&) > _row2</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6793"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>action: a pointer to the method which CalledForAction
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="g_irow2"><a name="d0e6812"></a><h3>g_irow2</h3><p>This is an internal transition for use inside a transition table, with
+ guard and without action.</p><div class="refsect3" title="definition"><a name="d0e6817"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Source, class Event, </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6828"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>guard: a pointer to the method which CalledForGuard
+ provides.</p></li></ul></div><p>
+ </p></div></div><div class="refsect2" title="irow2"><a name="d0e6847"></a><h3>irow2</h3><p>This is an internal transition for use inside a transition table, with
+ guard and action.</p><div class="refsect3" title="definition"><a name="d0e6852"></a><h4>definition</h4><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template< class Source, class Event, </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForAction, void
+ (CalledForAction::*action)(Event const&), </span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</span></span> {<br>}</pre></div><div class="refsect3" title="template parameters"><a name="d0e6867"></a><h4>template parameters</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>action: a pointer to the method which CalledForAction
+ provides.</p></li><li class="listitem"><p>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</p></li><li class="listitem"><p>guard: a pointer to the method which CalledForGuard
+ provides.</p></li></ul></div><p>
+ </p></div></div></div><div class="refsect1" title="msm/front/state_machine_def.hpp"><a name="d0e6892"></a><h2>msm/front/state_machine_def.hpp</h2><p>This header provides the implementation of the <span class="command"><strong><a class="command" href="ch03s02.html#basic-front-end">basic front-end</a></strong></span>. It contains one
+ type, <code class="code">state_machine_def</code></p><div class="refsect2" title="state_machine_def definition"><a name="d0e6902"></a><h3>state_machine_def definition</h3><p>This type is the basic class for a basic (or possibly any other)
+ front-end. It provides the standard row types (which includes internal
+ transitions) and a default implementation of the required methods and
+ typedefs.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Derived,class BaseState =
+ default_base_state> state_machine_def</span></span> {<br>}</pre><div class="refsect3" title="typedefs"><a name="d0e6911"></a><h4>typedefs</h4><p>
+ </p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>flag_list: by default, no flag is set in the state
+ machine</p></li><li class="listitem"><p>deferred_events: by default, no event is deferred.</p></li><li class="listitem"><p>configuration: by default, no configuration customization
+ is done.</p></li></ul></div><p>
+ </p></div><div class="refsect3" title="row methods"><a name="d0e6927"></a><h4>row methods</h4><p>Like any other front-end, the following transition row types
+ implements the two necessary static functions for action and guard call.
+ Each function receives as parameter the (deepest-level) state machine
+ processsing the event, the event itself, the source and target states
+ and all the states contained in a state machine (ignored).</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect3" title="a_row"><a name="d0e6950"></a><h4>a_row</h4><p>This is a transition with action and without guard.</p><p><code class="classname">template< class Source, class Event, class Target,
+ void (Derived::*action)(Event const&) > a_row</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li><li class="listitem"><p>action: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li></ul></div></div><div class="refsect3" title="g_row"><a name="d0e6975"></a><h4>g_row</h4><p>This is a transition with guard and without action.</p><p><code class="classname">template< class Source, class Event, class Target,
+ bool (Derived::*guard)(Event const&) > g_row</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li><li class="listitem"><p>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li></ul></div></div><div class="refsect3" title="row"><a name="d0e7000"></a><h4>row</h4><p>This is a transition with guard and action.</p><p><code class="classname">template< class Source, class Event, class Target,
+ void (Derived::*action)(Event const&), bool
+ (Derived::*guard)(Event const&) > row</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li><li class="listitem"><p>action: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li><li class="listitem"><p>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li></ul></div></div><div class="refsect3" title="_row"><a name="d0e7031"></a><h4>_row</h4><p>This is a transition without action or guard. The state machine only
+ changes active state.</p><p><code class="classname">template< class Source, class Event, class Target >
+ _row</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>Target: the target state of the transition.</p></li></ul></div></div><div class="refsect3" title="a_irow"><a name="d0e7050"></a><h4>a_irow</h4><p>This is an internal transition for use inside a transition table, with
+ action and without guard.</p><p><code class="classname">template< class Source, class Event, void
+ (Derived::*action)(Event const&) > a_irow</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>action: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li></ul></div></div><div class="refsect3" title="g_irow"><a name="d0e7072"></a><h4>g_irow</h4><p>This is an internal transition for use inside a transition table, with
+ guard and without action.</p><p><code class="classname">template< class Source, class Event, bool
+ (Derived::*guard)(Event const&) > g_irow</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li></ul></div></div><div class="refsect3" title="irow"><a name="d0e7094"></a><h4>irow</h4><p>This is an internal transition for use inside a transition table, with
+ guard and action.</p><p><code class="classname">template< class Source, class Event, void
+ (Derived::*action)(Event const&), bool
+ (Derived::*guard)(Event const&) > irow</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li><li class="listitem"><p>action: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li><li class="listitem"><p>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code class="code">Derived</code>).</p></li></ul></div></div><div class="refsect3" title="_irow"><a name="d0e7122"></a><h4>_irow</h4><p>This is an internal transition without action or guard. As it does
+ nothing, it means "ignore event".</p><p><code class="classname">template< class Source, class Event >
+ _irow</code></p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>Event: the event triggering the transition.</p></li><li class="listitem"><p>Source: the source state of the transition.</p></li></ul></div></div><div class="refsect3" title="methods"><a name="d0e7138"></a><h4>methods</h4><p><code class="code">state_machine_def</code> provides a default implementation in
+ case of an event which cannot be processed by a state machine (no
+ transition found). The implementation is using a
+ <code class="code">BOOST_ASSERT</code> so that the error will only be noticed in
+ debug mode. Overwrite this method in your implementation to change the
+ behavior.</p><p>
+ </p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class Event> static void
+ no_transition(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Event const& ,Fsm&, int
+ state<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div><p>
+ </p><p><code class="code">state_machine_def</code> provides a default implementation in
+ case an exception is thrown by a state (entry/exit) or transition
+ (action/guard) behavior. The implementation is using a
+ <code class="code">BOOST_ASSERT</code> so that the error will only be noticed in
+ debug mode. Overwrite this method in your implementation to change the
+ behavior. This method will be called only if exception handling is not
+ deactivated (default) by defining
+ <code class="code">has_no_message_queue</code>.</p><p>
+ </p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Fsm,class Event> static void
+ exception_caught(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Event const& ,Fsm&,
+ std::exception&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div><p>
+ </p></div></div></div><div class="refsect1" title="msm/front/states.hpp"><a name="d0e7182"></a><h2>msm/front/states.hpp </h2><p>This header provides the different states (except state machines) for the
+ basic front-end (or mixed with other front-ends).</p><div class="refsect2" title="types"><a name="d0e7187"></a><h3>types</h3><p>This header provides the following types:</p><div class="refsect3" title="no_sm_ptr"><a name="d0e7192"></a><h4>no_sm_ptr</h4><p>deprecated: default policy for states. It means that states do not
+ need to save a pointer to their containing state machine.</p></div><div class="refsect3" title="sm_ptr"><a name="d0e7197"></a><h4>sm_ptr</h4><p>deprecated: state policy. It means that states need to save a pointer
+ to their containing state machine. When seeing this flag, the back-end
+ will call set_sm_ptr(fsm*) and give itself as argument.</p></div><div class="refsect3" title="state"><a name="d0e7202"></a><h4>state</h4><p>Basic type for simple states. Inherit from this type to define a
+ simple state. The first argument is needed if you want your state (and
+ all others used in a concrete state machine) to inherit a basic type for
+ logging or providing a common behavior.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template<class Base = default_base_state,class
+ SMPtrPolicy = no_sm_ptr> state</span></span> {<br>}</pre></div><div class="refsect3" title="terminate_state"><a name="d0e7211"></a><h4>terminate_state</h4><p>Basic type for terminate states. Inherit from this type to define a
+ terminate state. The first argument is needed if you want your state
+ (and all others used in a concrete state machine) to inherit a basic
+ type for logging or providing a common behavior.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template<class Base = default_base_state,class
+ SMPtrPolicy = no_sm_ptr> terminate_state</span></span> {<br>}</pre></div><div class="refsect3" title="interrupt_state"><a name="d0e7220"></a><h4>interrupt_state</h4><p>Basic type for interrupt states. Interrupt states prevent any further
+ event handling until EndInterruptEvent is sent. Inherit from this type
+ to define a terminate state. The first argument is the name of the event
+ ending the interrupt. The second argument is needed if you want your
+ state (and all others used in a concrete state machine) to inherit a
+ basic type for logging or providing a common behavior.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template<class EndInterruptEvent,class Base =
+ default_base_state,</span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class SMPtrPolicy = no_sm_ptr>
+ interrupt_state</span></span> {<br>}</pre></div><div class="refsect3" title="explicit_entry"><a name="d0e7233"></a><h4>explicit_entry</h4><p>Inherit from this type <span class="underline">in
+ addition</span> to the desired state type to enable this state
+ for direct entering. The template parameter gives the region id of the
+ state (regions are numbered in the order of the
+ <code class="code">initial_state</code> typedef).</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <int ZoneIndex=-1> explicit_entry</span></span> {<br>}</pre></div><div class="refsect3" title="entry_pseudo_state"><a name="d0e7248"></a><h4>entry_pseudo_state</h4><p>Basic type for entry pseudo states. Entry pseudo states are an
+ predefined entry into a submachine and connect two transitions. The
+ first argument is the id of the region entered by this state (regions
+ are numbered in the order of the <code class="code">initial_state</code> typedef).
+ The second argument is needed if you want your state (and all others
+ used in a concrete state machine) to inherit a basic type for logging or
+ providing a common behavior.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template<int RegionIndex=-1,class Base =
+ default_base_state,</span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class SMPtrPolicy = no_sm_ptr>
+ entry_pseudo_state</span></span> {<br>}</pre></div><div class="refsect3" title="exit_pseudo_state"><a name="d0e7264"></a><h4>exit_pseudo_state</h4><p>Basic type for exit pseudo states. Exit pseudo states are an
+ predefined exit from a submachine and connect two transitions. The first
+ argument is the name of the event which will be "thrown" out of the exit
+ point. This event does not need to be the same as the one sent by the
+ inner region but must be convertible from it. The second argument is
+ needed if you want your state (and all others used in a concrete state
+ machine) to inherit a basic type for logging or providing a common
+ behavior.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template<class Event,class Base =
+ default_base_state,</span></span> {<br>}</pre><pre class="classsynopsis"> <span class="ooclass"><span class="classname">class SMPtrPolicy = no_sm_ptr>
+ exit_pseudo_state</span></span> {<br>}</pre></div></div></div><div class="refsect1" title="msm/front/euml/euml.hpp"><a name="d0e7277"></a><h2>msm/front/euml/euml.hpp</h2><p>This header includes all of eUML except the STL functors.</p></div><div class="refsect1" title="msm/front/euml/stl.hpp"><a name="d0e7282"></a><h2>msm/front/euml/stl.hpp</h2><p>This header includes all the functors for STL support in eUML. These <span class="command"><strong><a class="command" href="ch10.html#eUML-STL-all">tables</a></strong></span> show a full description.</p></div><div class="refsect1" title="msm/front/euml/algorithm.hpp"><a name="d0e7290"></a><h2>msm/front/euml/algorithm.hpp</h2><p>This header includes all the functors for STL algorithms support in eUML.
+ These <span class="command"><strong><a class="command" href="ch10.html#eUML-STL-all">tables</a></strong></span> show a full
+ description.</p></div><div class="refsect1" title="msm/front/euml/iteration.hpp"><a name="d0e7298"></a><h2>msm/front/euml/iteration.hpp</h2><p>This header includes iteration functors for STL support in eUML. This <span class="command"><strong><a class="command" href="ch10.html#eUML-STL-iteration">tables</a></strong></span> shows a full
+ description.</p></div><div class="refsect1" title="msm/front/euml/querying.hpp"><a name="d0e7306"></a><h2>msm/front/euml/querying.hpp</h2><p>This header includes querying functors for STL support in eUML. This <span class="command"><strong><a class="command" href="ch10.html#eUML-STL-querying">tables</a></strong></span> shows a full
+ description.</p></div><div class="refsect1" title="msm/front/euml/transformation.hpp"><a name="d0e7314"></a><h2>msm/front/euml/transformation.hpp</h2><p>This header includes transformation functors for STL support in eUML. This
+ <span class="command"><strong><a class="command" href="ch10.html#eUML-STL-transformation">tables</a></strong></span> shows a full
+ description.</p></div><div class="refsect1" title="msm/front/euml/container.hpp"><a name="d0e7322"></a><h2>msm/front/euml/container.hpp</h2><p>This header includes container functors for STL support in eUML (functors
+ calling container methods). This <span class="command"><strong><a class="command" href="ch10.html#eUML-STL-container">tables</a></strong></span> shows a full description. It also provides npos for
+ strings.</p><div class="refsect2" title="Npos_<container type>"><a name="d0e7330"></a><h3>Npos_<container type></h3><p>Functor returning npos for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Example:</p><p><code class="code">string_find_(event_(m_song),Char_<'S'>(),Size_t_<0>()) !=
+ Npos_<string>() // compare result of string::find with
+ npos</code></p></div></div><div class="refsect1" title="msm/front/euml/stt_grammar.hpp"><a name="d0e7338"></a><h2>msm/front/euml/stt_grammar.hpp</h2><p>This header provides the transition table grammars. This includes internal
+ transition tables.</p><div class="refsect2" title="functions"><a name="d0e7343"></a><h3>functions</h3><div class="refsect3" title="build_stt"><a name="d0e7346"></a><h4>build_stt</h4><p>The function build_stt evaluates the grammar-conform expression as
+ parameter. It returns a transition table, which is a mpl::vector of
+ transitions (rows) or, if the expression is ill-formed (does not match
+ the grammar), the type <code class="code">invalid_type</code>, which will lead to a
+ compile-time static assertion when this transition table is passed to a
+ state machine. </p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template<class Expr> [mpl::vector<...> /
+ msm::front::euml::invalid_type] build_stt(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr const& expr</code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect3" title="build_internal_stt"><a name="d0e7360"></a><h4>build_internal_stt</h4><p>The function build_internal_stt evaluates the grammar-conform
+ expression as parameter. It returns a transition table, which is a
+ mpl::vector of transitions (rows) or, if the expression is ill-formed
+ (does not match the grammar), the type <code class="code">invalid_type</code>, which
+ will lead to a compile-time static assertion when this transition table
+ is passed to a state machine. </p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template<class Expr> [mpl::vector<...> /
+ msm::front::euml::invalid_type] build_internal_stt(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr const& expr</code>;</div><div class="funcprototype-spacer"> </div></div></div></div><div class="refsect2" title="grammars"><a name="d0e7374"></a><h3>grammars</h3><div class="refsect3" title="transition table"><a name="d0e7377"></a><h4><span class="command"><strong><a name="reference-stt-grammar"></a>transition
+ table</strong></span></h4><p>The transition table accepts the following grammar:</p><pre class="programlisting">Stt := Row | (Stt ',' Stt)
+Row := (Target '==' (SourcePlusEvent)) /* first syntax*/
+ | ( (SourcePlusEvent) '==' Target ) /* second syntax*/
+ | (SourcePlusEvent) /* internal transitions */
+SourcePlusEvent := (BuildSource '+' BuildEvent)/* standard transition*/
+ | (BuildSource) /* anonymous transition */
+BuildSource := state_tag | (state_tag '/' Action) | (state_tag '[' Guard ']')
+ | (state_tag '[' Guard ']' '/' Action)
+BuildEvent := event_tag | (event_tag '/' Action) | (event_tag '[' Guard ']')
+ | (event_tag '[' Guard ']' '/' Action)</pre><p>The grammars Action and Guard are defined in state_grammar.hpp and
+ guard_grammar.hpp respectively. state_tag and event_tag are inherited
+ from euml_state (or other state variants) and euml_event respectively.
+ For example, following declarations are possible:</p><pre class="programlisting">target == source + event [guard] / action,
+source + event [guard] / action == target,
+source + event [guard] / (action1,action2) == target,
+target == source + event [guard] / (action1,action2),
+target == source + event,
+source + event == target,
+target == source + event [guard],
+source + event [guard] == target,
+target == source + event / action,
+source + event /action == target,
+source / action == target, /*anonymous transition*/
+target == source / action, /*anonymous transition*/
+source + event /action, /* internal transition*/</pre></div><div class="refsect3" title="internal transition table"><a name="d0e7389"></a><h4>internal transition table</h4><p>The internal transition table accepts the following grammar:</p><pre class="programlisting">IStt := BuildEvent | (IStt ',' IStt)</pre><p>BuildEvent being defined for both internal and standard transition
+ tables.</p></div></div></div><div class="refsect1" title="msm/front/euml/guard_grammar.hpp"><a name="d0e7398"></a><h2>msm/front/euml/guard_grammar.hpp</h2><p>This header contains the <code class="code">Guard</code> grammar used in the previous
+ section. This grammar is long but pretty simple:</p><pre class="programlisting">Guard := action_tag | (Guard '&&' Guard)
+ | (Guard '||' Guard) | ... /* operators*/
+ | (if_then_else_(Guard,Guard,Guard)) | (function (Action,...Action))</pre><p>Most C++ operators are supported (address-of is not). With
+ <code class="code">function</code> is meant any eUML predefined function or any self-made
+ (using <code class="code">MSM_EUML_METHOD</code> or <code class="code">MSM_EUML_FUNCTION</code>). Action
+ is a grammar defined in state_grammar.hpp.</p></div><div class="refsect1" title="msm/front/euml/state_grammar.hpp"><a name="d0e7419"></a><h2>msm/front/euml/state_grammar.hpp</h2><p>This header provides the grammar for actions and the different grammars and
+ functions to build states using eUML.</p><div class="refsect2" title="action grammar"><a name="d0e7424"></a><h3>action grammar</h3><p>Like the guard grammar, this grammar supports relevant C++ operators and
+ eUML functions:</p><pre class="programlisting">Action := action_tag | (Action '+' Action)
+ | ('--' Action) | ... /* operators*/
+ | if_then_else_(Guard,Action,Action) | if_then_(Action)
+ | while_(Guard,Action)
+ | do_while_(Guard,Action) | for_(Action,Guard,Action,Action)
+ | (function(Action,...Action))
+ActionSequence := Action | (Action ',' Action)</pre><p>Relevant operators are: ++ (post/pre), -- (post/pre), dereferencing, +
+ (unary/binary), - (unary/binary), *, /, %, &(bitwise), | (bitwise),
+ ^(bitwise), +=, -=, *=, /=, %=, <<=, >>=, <<, >>, =, [].</p></div><div class="refsect2" title="attributes"><a name="d0e7433"></a><h3>attributes</h3><p>This grammar is used to add attributes to states (or state machines) or
+ events: It evaluates to a fusion::map. You can use two forms:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">attributes_ << no_attributes_</code></p></li><li class="listitem"><p><code class="code">attributes_ << attribute_1 << ... <<
+ attribute_n</code></p></li></ul></div><p>Attributes can be of any default-constructible type (fusion
+ requirement).</p></div><div class="refsect2" title="configure"><a name="d0e7449"></a><h3>configure</h3><p>This grammar also has two forms:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">configure_ << no_configure_</code></p></li><li class="listitem"><p><code class="code">configure_ << type_1 << ... <<
+ type_n</code></p></li></ul></div><p>This grammar is used to create inside one syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>flags: <code class="code">configure_ << some_flag</code> where
+ some_flag inherits from <code class="code">euml_flag<some_flag></code> or
+ is defined using BOOST_MSM_EUML_FLAG.</p></li><li class="listitem"><p>deferred events: <code class="code">configure_ << some_event</code>
+ where some_event inherits from
+ <code class="code">euml_event<some_event></code> or is defined using
+ BOOST_MSM_EUML_EVENT or
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES.</p></li><li class="listitem"><p>configuration (message queue, manual deferring, exception
+ handling): <code class="code">configure_ << some_config</code> where
+ some_config inherits from
+ <code class="code">euml_config<some_config></code>. At the moment,
+ three predefined objects exist (in msm//front/euml/common.hpp):</p><div class="itemizedlist"><ul class="itemizedlist" type="circle"><li class="listitem"><p>no_exception: disable catching exceptions</p></li><li class="listitem"><p>no_msg_queue: disable message queue</p></li><li class="listitem"><p>deferred_events: manually enable handling of
+ deferred events</p></li></ul></div></li></ul></div></div><div class="refsect2" title="initial states"><a name="d0e7503"></a><h3>initial states</h3><p>The grammar to define initial states for a state machine is: <code class="code">init_
+ << state_1 << ... << state_n</code> where
+ state_1...state_n inherit from euml_state or is defined using
+ BOOST_MSM_EUML_STATE, BOOST_MSM_EUML_INTERRUPT_STATE,
+ BOOST_MSM_EUML_TERMINATE_STATE, BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE,
+ BOOST_MSM_EUML_ENTRY_STATE or BOOST_MSM_EUML_EXIT_STATE.</p></div><div class="refsect2" title="functions"><a name="d0e7511"></a><h3>functions</h3><div class="refsect3" title="build_sm"><a name="d0e7514"></a><h4>build_sm</h4><p>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</p><p>Defines a state machine without entry or exit:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Stt,class Init>
+ func_state_machine<...> build_sm(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Stt ,Init</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a state machine with entry behavior:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Stt,class Init,class
+ Expr1> func_state_machine<...> build_sm(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Stt ,Init,Expr1 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a state machine with entry and exit behaviors:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2> func_state_machine<...>
+ build_sm(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Stt ,Init,Expr1 const&,Expr2 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a state machine with entry, exit behaviors and
+ attributes:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2, class Attributes> func_state_machine<...>
+ build_sm(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Stt ,Init,Expr1 const&, Expr2 const&, Attributes
+ const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a state machine with entry, exit behaviors, attributes and
+ configuration (deferred events, flags):</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2, class Attributes, class Configure>
+ func_state_machine<...> build_sm(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Stt ,Init,Expr1 const&, Expr2 const&, Attributes
+ const&, Configure const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a state machine with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2, class Attributes, class Configure, class
+ Base> func_state_machine<...> build_sm(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Stt ,Init,Expr1 const&, Expr2 const&, Attributes
+ const&, Configure const&, Base</code>;</div><div class="funcprototype-spacer"> </div></div><p>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate state machines having the same parameters
+ but still being different.</p></div><div class="refsect3" title="build_state"><a name="d0e7569"></a><h4>build_state</h4><p>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</p><p>Defines a simple state without entry or exit:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">func_state<class StateNameTag,...> build_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code></code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a simple state with entry behavior:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Expr1>
+ func_state<...> build_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a simple state with entry and exit behaviors:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Expr1, class Expr2>
+ func_state<...> build_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&,Expr2 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a simple state with entry, exit behaviors and
+ attributes:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Expr1, class Expr2,
+ class Attributes> func_state<...> build_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&, Expr2 const&, Attributes
+ const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a simple state with entry, exit behaviors, attributes and
+ configuration (deferred events, flags):</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Expr1, class Expr2,
+ class Attributes, class Configure> func_state<...>
+ build_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines a simple state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Expr1, class Expr2,
+ class Attributes, class Configure, class Base>
+ func_state<...> build_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&, Base</code>;</div><div class="funcprototype-spacer"> </div></div><p>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</p></div><div class="refsect3" title="build_terminate_state"><a name="d0e7623"></a><h4>build_terminate_state</h4><p>This function has the same overloads as build_state.</p></div><div class="refsect3" title="build_interrupt_state"><a name="d0e7628"></a><h4>build_interrupt_state</h4><p>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</p><p>Defines an interrupt state without entry or exit:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class EndInterruptEvent>
+ func_state<...> build_interrupt_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>EndInterruptEvent const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an interrupt state with entry behavior:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class
+ EndInterruptEvent,class Expr1> func_state<...>
+ build_interrupt_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>EndInterruptEvent const&,Expr1 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an interrupt state with entry and exit behaviors:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2> func_state<...>
+ build_interrupt_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>EndInterruptEvent const&,Expr1 const&,Expr2
+ const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an interrupt state with entry, exit behaviors and
+ attributes:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2, class Attributes>
+ func_state<...> build_interrupt_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>EndInterruptEvent const&,Expr1 const&, Expr2
+ const&, Attributes const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an interrupt state with entry, exit behaviors, attributes and
+ configuration (deferred events, flags):</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2, class Attributes,
+ class Configure> func_state<...>
+ build_interrupt_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>EndInterruptEvent const&,Expr1 const&, Expr2
+ const&, Attributes const&, Configure
+ const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an interrupt state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2, class Attributes,
+ class Configure, class Base> func_state<...>
+ build_interrupt_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>EndInterruptEvent const&,Expr1 const&, Expr2
+ const&, Attributes const&, Configure const&,
+ Base</code>;</div><div class="funcprototype-spacer"> </div></div><p>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</p></div><div class="refsect3" title="build_entry_state"><a name="d0e7683"></a><h4>build_entry_state</h4><p>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</p><p>Defines an entry pseudo state without entry or exit:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,int RegionIndex>
+ entry_func_state<...> build_entry_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code></code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an entry pseudo state with entry behavior:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,int RegionIndex,class
+ Expr1> entry_func_state<...> build_entry_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an entry pseudo state with entry and exit behaviors:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2> entry_func_state<...>
+ build_entry_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&,Expr2 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an entry pseudo state with entry, exit behaviors and
+ attributes:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2, class Attributes> entry_func_state<...>
+ build_entry_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&, Expr2 const&, Attributes
+ const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an entry pseudo state with entry, exit behaviors, attributes
+ and configuration (deferred events, flags):</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2, class Attributes, class Configure>
+ entry_func_state<...> build_entry_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an entry pseudo state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2, class Attributes, class Configure, class
+ Base> entry_func_state<...> build_entry_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&, Base</code>;</div><div class="funcprototype-spacer"> </div></div><p>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</p></div><div class="refsect3" title="build_exit_state"><a name="d0e7737"></a><h4>build_exit_state</h4><p>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</p><p>Defines an exit pseudo state without entry or exit:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Event>
+ exit_func_state<...> build_exit_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Event const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an exit pseudo state with entry behavior:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Event,class Expr1>
+ exit_func_state<...> build_exit_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Event const&,Expr1 const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an exit pseudo state with entry and exit behaviors:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Event,class Expr1,
+ class Expr2> exit_func_state<...> build_exit_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Event const&,Expr1 const&,Expr2
+ const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an exit pseudo state with entry, exit behaviors and
+ attributes:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Event,class Expr1,
+ class Expr2, class Attributes> exit_func_state<...>
+ build_exit_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Event const&,Expr1 const&, Expr2 const&,
+ Attributes const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an exit pseudo state with entry, exit behaviors, attributes
+ and configuration (deferred events, flags):</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Event,class Expr1,
+ class Expr2, class Attributes, class Configure>
+ exit_func_state<...> build_exit_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Event const&,Expr1 const&, Expr2 const&,
+ Attributes const&, Configure const&</code>;</div><div class="funcprototype-spacer"> </div></div><p>Defines an exit pseudo state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class StateNameTag,class Event,class Expr1,
+ class Expr2, class Attributes, class Configure, class Base>
+ exit_func_state<...> build_exit_state(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>Event const&,Expr1 const&, Expr2 const&,
+ Attributes const&, Configure const&, Base</code>;</div><div class="funcprototype-spacer"> </div></div><p>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</p></div><div class="refsect3" title="build_explicit_entry_state"><a name="d0e7792"></a><h4>build_explicit_entry_state</h4><p>This function has the same overloads as build_entry_state and
+ explicit_entry_func_state as return type.</p></div></div></div><div class="refsect1" title="msm/front/euml/common.hpp"><a name="d0e7797"></a><h2>msm/front/euml/common.hpp</h2><div class="refsect2" title="types"><a name="d0e7800"></a><h3>types</h3><div class="refsect3" title="euml_event"><a name="d0e7803"></a><h4>euml_event</h4><p>The basic type for events with eUML.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class EventName> euml_event;</span></span> {<br>}</pre><pre class="programlisting">struct play : euml_event<play>{};</pre></div><div class="refsect3" title="euml_state"><a name="d0e7814"></a><h4>euml_state</h4><p>The basic type for states with eUML. You will usually not use this
+ type directly as it is easier to use BOOST_MSM_EUML_STATE,
+ BOOST_MSM_EUML_INTERRUPT_STATE, BOOST_MSM_EUML_TERMINATE_STATE,
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE, BOOST_MSM_EUML_ENTRY_STATE or
+ BOOST_MSM_EUML_EXIT_STATE.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class StateName> euml_state;</span></span> {<br>}</pre><p>You can however use this type directly if you want to provide your
+ state with extra functions or provide entry or exit behaviors without
+ functors, for example:</p><pre class="programlisting">struct Empty : public msm::front::state<> , public euml_state<Empty>
+{
+ void foo() {...}
+ template <class Event,class Fsm>
+ void on_entry(Event const& evt,Fsm& fsm){...}
+};</pre></div><div class="refsect3" title="euml_flag"><a name="d0e7827"></a><h4>euml_flag</h4><p>The basic type for flags with eUML.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class FlagName> euml_flag;</span></span> {<br>}</pre><pre class="programlisting">struct PlayingPaused: euml_flag<PlayingPaused>{};</pre></div><div class="refsect3" title="euml_action"><a name="d0e7838"></a><h4>euml_action</h4><p>The basic type for state or transition behaviors and guards with
+ eUML.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class AcionName> euml_action;</span></span> {<br>}</pre><pre class="programlisting">struct close_drawer : euml_action<close_drawer>
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ void operator()(Evt const& , Fsm&, SourceState& ,TargetState& ) {...}
+};</pre><p>Or, as state entry or exit behavior:</p><pre class="programlisting">struct Playing_Entry : euml_action<Playing_Entry>
+{
+ template <class Event,class Fsm,class State>
+ void operator()(Event const&,Fsm& fsm,State& ){...}
+};</pre></div><div class="refsect3" title="euml_config"><a name="d0e7853"></a><h4>euml_config</h4><p>The basic type for configuration possibilities with eUML.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class ConfigName> euml_config;</span></span> {<br>}</pre><p>You normally do not use this type directly but instead the instances
+ of predefined configuration:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>no_exception: disable catching exceptions</p></li><li class="listitem"><p>no_msg_queue: disable message queue. The message queue
+ allows you to send an event for procesing while in an event
+ processing.</p></li><li class="listitem"><p>deferred_events: manually enable handling of deferred
+ events</p></li></ul></div></div><div class="refsect3" title="invalid_type"><a name="d0e7874"></a><h4>invalid_type</h4><p>Type returned by grammar parsers if the grammar is invalid. Seeing
+ this type will result in a static assertion.</p></div><div class="refsect3" title="no_action"><a name="d0e7879"></a><h4>no_action</h4><p>Placeholder type for use in entry/exit or transition behaviors, which
+ does absolutely nothing.</p></div><div class="refsect3" title="source_"><a name="d0e7884"></a><h4>source_</h4><p>Generic object or function for the source state of a given transition:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>as object: returns by reference the source state of a
+ transition, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</p><p>Example:
+ </p><pre class="programlisting">some_user_function_(source_)</pre></li><li class="listitem"><p>as function: returns by reference the attribute passed as
+ parameter.</p><p>Example:
+ </p><pre class="programlisting">source_(m_counter)++</pre></li></ul></div></div><div class="refsect3" title="target_"><a name="d0e7904"></a><h4>target_</h4><p>Generic object or function for the target state of a given transition:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>as object: returns by reference the target state of a
+ transition, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</p><p>Example:
+ </p><pre class="programlisting">some_user_function_(target_)</pre></li><li class="listitem"><p>as function: returns by reference the attribute passed as
+ parameter.</p><p>Example:
+ </p><pre class="programlisting">target_(m_counter)++</pre></li></ul></div></div><div class="refsect3" title="state_"><a name="d0e7924"></a><h4>state_</h4><p>Generic object or function for the state of a given entry / exit
+ behavior. state_ means source_ while in the context of an exit behavior
+ and target_ in the context of an entry behavior:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>as object: returns by reference the current state, usually
+ to be used by another function (usually one created by
+ MSM_EUML_METHOD or MSM_EUML_FUNCTION).</p><p>Example:
+ </p><pre class="programlisting">some_user_function_(state_) // calls some_user_function on the current state</pre></li><li class="listitem"><p>as function: returns by reference the attribute passed as
+ parameter.</p><p>Example:
+ </p><pre class="programlisting">state_(m_counter)++</pre></li></ul></div></div><div class="refsect3" title="event_"><a name="d0e7944"></a><h4>event_</h4><p>Generic object or function for the event triggering a given transition
+ (valid in a transition behavior, as well as in state entry/exit behaviors):</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>as object: returns by reference the event of a transition,
+ usually to be used by another function (usually one created
+ by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</p><p>Example:
+ </p><pre class="programlisting">some_user_function_(event_)</pre></li><li class="listitem"><p>as function: returns by reference the attribute passed as
+ parameter.</p><p>Example:
+ </p><pre class="programlisting">event_(m_counter)++</pre></li></ul></div></div><div class="refsect3" title="fsm_"><a name="d0e7964"></a><h4>fsm_</h4><p>Generic object or function for the state machine containing a given transition:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>as object: returns by reference the event of a transition,
+ usually to be used by another function (usually one created
+ by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</p><p>Example:
+ </p><pre class="programlisting">some_user_function_(fsm_)</pre></li><li class="listitem"><p>as function: returns by reference the attribute passed as
+ parameter.</p><p>Example:
+ </p><pre class="programlisting">fsm_(m_counter)++</pre></li></ul></div></div><div class="refsect3" title="substate_"><a name="d0e7984"></a><h4>substate_</h4><p>Generic object or function returning a state of a given state machine:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>with 1 parameter: returns by reference the state passed as
+ parameter, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</p><p>Example:
+ </p><pre class="programlisting">some_user_function_(substate_(my_state))</pre></li><li class="listitem"><p>with 2 parameters: returns by reference the state passed
+ as first parameter from the state machine passed as second
+ parameter, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION). This
+ makes sense when used in combination with attribute_.</p><p>Example (equivalent to the previous example):
+ </p><pre class="programlisting">some_user_function_(substate_(my_state,fsm_))</pre></li></ul></div></div><div class="refsect3" title="attribute_"><a name="d0e8004"></a><h4>attribute_</h4><p>Generic object or function returning the attribute passed (by name) as
+ second parameter of the thing passed as first (a state, event or state
+ machine). Example: </p><p>
+ </p><pre class="programlisting">attribute_(substate_(my_state),cd_name_attribute)++</pre><p>
+ </p></div><div class="refsect3" title="True_"><a name="d0e8014"></a><h4>True_</h4><p>Functor returning true for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Example:</p><p>
+ </p><pre class="programlisting">if_then_(True_(),/* some action always called*/)</pre><p>
+ </p></div><div class="refsect3" title="False_"><a name="d0e8024"></a><h4>False_</h4><p>Functor returning false for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Example:</p><p>
+ </p><pre class="programlisting">if_then_(False_(),/* some action never called */)</pre><p>
+ </p></div><div class="refsect3" title="Int_<int value>"><a name="d0e8034"></a><h4>Int_<int value></h4><p>Functor returning an integer value for transition or state behaviors.
+ Like all constants, only the functor form exists, so parenthesis are
+ necessary. Example:</p><p>
+ </p><pre class="programlisting">target_(m_ringing_cpt) = Int_<RINGING_TIME>() // RINGING_TIME is a constant</pre><p>
+ </p></div><div class="refsect3" title="Char_<char value>"><a name="d0e8044"></a><h4>Char_<char value></h4><p>Functor returning a char value for transition or state behaviors. Like
+ all constants, only the functor form exists, so parenthesis are
+ necessary. Example:</p><p>
+ </p><pre class="programlisting">// look for 'S' in event.m_song
+[string_find_(event_(m_song),Char_<'S'>(),Size_t_<0>()) != Npos_<string>()]</pre><p>
+ </p></div><div class="refsect3" title="Size_t_<size_t value>"><a name="d0e8054"></a><h4>Size_t_<size_t value></h4><p>Functor returning a size_t value for transition or state behaviors.
+ Like all constants, only the functor form exists, so parenthesis are
+ necessary. Example:</p><p>
+ </p><pre class="programlisting">substr_(event_(m_song),Size_t_<1>()) // returns a substring of event.m_song</pre><p>
+ </p></div><div class="refsect3" title="String_ < mpl::string >"><a name="d0e8064"></a><h4>String_ < mpl::string ></h4><p>Functor returning a string for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Requires boost >= 1.40 for mpl::string.</p><p>Example:</p><p>
+ </p><pre class="programlisting">// adds "Let it be" to fsm.m_src_container
+push_back_(fsm_(m_src_container), String_<mpl::string<'Let','it ','be'> >())</pre><p>
+ </p></div><div class="refsect3" title="Predicate_ < some_stl_compatible_functor >"><a name="d0e8076"></a><h4>Predicate_ < some_stl_compatible_functor ></h4><p>This functor eUML-enables a STL functor (for use in an algorithm).
+ This is necessary because all what is in the transition table must be a
+ eUML terminal.</p><p>Example:</p><pre class="programlisting">//equivalent to:
+//std::accumulate(fsm.m_vec.begin(),fsm.m_vec.end(),1,std::plus<int>())== 1
+accumulate_(begin_(fsm_(m_vec)),end_(fsm_(m_vec)),Int_<1>(),
+ Predicate_<std::plus<int> >()) == Int_<1>())</pre></div><div class="refsect3" title="process_"><a name="d0e8085"></a><h4>process_</h4><p>This function sends an event to up to 4 state machines by calling
+ <code class="code">process_event</code> on them:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">process_(some_event)</code> : processes an event in
+ the current (containing) state machine.</p></li><li class="listitem"><p><code class="code">process_(some_event [,fsm1...fsm4] )</code> :
+ processes the same event in the 1-4 state machines passed as
+ argument.</p></li></ul></div></div><div class="refsect3" title="process2_"><a name="d0e8104"></a><h4>process2_</h4><p>This function sends an event to up to 3 state machines by calling
+ <code class="code">process_event</code> on them and copy-constructing the event
+ from the data passed as second parameter:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">process2_(some_event, some_data)</code> : processes
+ an event in the current (containing) state machine.</p></li><li class="listitem"><p><code class="code">process2_(some_event, some_data [,fsm1...fsm3]
+ )</code> : processes the same event in the 1-3 state
+ machines passed as argument.</p></li></ul></div><p>Example: </p><p>
+ </p><pre class="programlisting">// processes NotFound on current state machine,
+// copy-constructed with event.m_song
+process2_(NotFound,event_(m_song))</pre><p>
+ </p><p>With the following definitions:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)//declaration of m_song
+NotFound (const string& data) // copy-constructor of NotFound</pre></div><div class="refsect3" title="is_flag_"><a name="d0e8134"></a><h4>is_flag_</h4><p>This function tells if a flag is active by calling
+ <code class="code">is_flag_active</code> on the current state machine or one
+ passed as parameter:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="code">is_flag_(some_flag)</code> : calls
+ <code class="code">is_flag_active</code> on the current (containing)
+ state machine.</p></li><li class="listitem"><p><code class="code">is_flag_(some_flag, some_fsm)</code> :calls
+ <code class="code">is_flag_active</code> on the state machine.passed
+ as argument.</p></li></ul></div></div><div class="refsect3" title="defer_"><a name="d0e8159"></a><h4>defer_</h4><p>This object defers the current event by calling
+ <code class="code">defer_event</code> on the current state machine.
+ Example:</p><pre class="programlisting">Empty() + play() / defer_</pre></div><div class="refsect3" title="explicit_(submachine-name,state-name)"><a name="d0e8169"></a><h4>explicit_(submachine-name,state-name)</h4><p>Used as transition's target, causes an explicit entry into the given
+ state from the given submachine. Several explicit_ as targets, separated
+ by commas, means a fork. The state must have been declared as such using
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE.</p></div><div class="refsect3" title="entry_pt_(submachine-name,state-name)"><a name="d0e8174"></a><h4>entry_pt_(submachine-name,state-name)</h4><p>Used as transition's target from a containing state machine, causes
+ submachine-name to be entered using the given entry pseudo-state. This
+ state must have been declared as pseudo entry using
+ BOOST_MSM_EUML_ENTRY_STATE.</p></div><div class="refsect3" title="exit_pt_(submachine-name,state-name)"><a name="d0e8179"></a><h4>exit_pt_(submachine-name,state-name)</h4><p>Used as transition's source from a containing state machine, causes
+ submachine-name to be left using the given exit pseudo-state. This state
+ must have been declared as pseudo exit using
+ BOOST_MSM_EUML_EXIT_STATE.</p></div><div class="refsect3" title="MSM_EUML_FUNCTION"><a name="d0e8184"></a><h4>MSM_EUML_FUNCTION</h4><p>This macro creates a eUML function and a functor for use with the
+ functor front-end, based on a free function:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>first parameter: the name of the functor</p></li><li class="listitem"><p>second parameter: the underlying function</p></li><li class="listitem"><p>third parameter: the eUML function name</p></li><li class="listitem"><p>fourth parameter: the return type if used in a transition
+ behavior</p></li><li class="listitem"><p>fifth parameter: the return type if used in a state
+ behavior (entry/exit)</p></li></ul></div><p> Note that the function itself can take up to 5
+ arguments.</p><p>Example:</p><p>
+ </p><pre class="programlisting">MSM_EUML_FUNCTION(BinarySearch_,std::binary_search,binary_search_,bool,bool)</pre><p>
+ </p><p>Can be used like:</p><p>
+ </p><pre class="programlisting">binary_search_(begin_(fsm_(m_var)),end_(fsm_(m_var)),Int_<9>())</pre><p>
+ </p></div><div class="refsect3" title="MSM_EUML_METHOD"><a name="d0e8220"></a><h4>MSM_EUML_METHOD</h4><p>This macro creates a eUML function and a functor for use with the
+ functor front-end, based on a method:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>first parameter: the name of the functor</p></li><li class="listitem"><p>second parameter: the underlying function</p></li><li class="listitem"><p>third parameter: the eUML function name</p></li><li class="listitem"><p>fourth parameter: the return type if used in a transition
+ behavior</p></li><li class="listitem"><p>fifth parameter: the return type if used in a state
+ behavior (entry/exit)</p></li></ul></div><p> Note that the method itself can take up to 4 arguments
+ (5 like for a free function - 1 for the object on which the method is
+ called).</p><p>Example:</p><pre class="programlisting">struct Empty : public msm::front::state<> , public euml_state<Empty>
+{
+ void activate_empty() {std::cout << "switching to Empty " << std::endl;}
+...
+};
+MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</pre><p>Can be used like:</p><p>
+ </p><pre class="programlisting">Empty == Open + open_close / (close_drawer , activate_empty_(target_))</pre><p>
+ </p></div><div class="refsect3" title="BOOST_MSM_EUML_ACTION(action-instance-name)"><a name="d0e8253"></a><h4>BOOST_MSM_EUML_ACTION(action-instance-name)</h4><p>This macro declares a behavior type and a const instance for use in
+ state or transition behaviors. The action implementation itself follows
+ the macro declaration, for example:</p><pre class="programlisting">BOOST_MSM_EUML_ACTION(good_disk_format)
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ void/bool operator()(Evt const& evt,Fsm&,SourceState& ,TargetState& ){...}
+};</pre></div><div class="refsect3" title="BOOST_MSM_EUML_FLAG(flag-instance-name)"><a name="d0e8260"></a><h4>BOOST_MSM_EUML_FLAG(flag-instance-name)</h4><p>This macro declares a flag type and a const instance for use in
+ behaviors.</p></div><div class="refsect3" title="BOOST_MSM_EUML_FLAG_NAME(flag-instance-name)"><a name="d0e8265"></a><h4>BOOST_MSM_EUML_FLAG_NAME(flag-instance-name)</h4><p>This macro returns the name of the flag type generated by
+ BOOST_MSM_EUML_FLAG. You need this where the type is required (usually
+ with the back-end method is_flag_active). For example:</p><pre class="programlisting">fsm.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>()</pre></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_ATTRIBUTE(event-type,event-name)"><a name="d0e8272"></a><h4>BOOST_MSM_EUML_DECLARE_ATTRIBUTE(event-type,event-name)</h4><p>This macro declares an attribute called event-name of type event-type.
+ This attribute can then be made part of an attribute list using
+ BOOST_MSM_EUML_ATTRIBUTES.</p></div><div class="refsect3" title="BOOST_MSM_EUML_ATTRIBUTES(attributes-expression,attributes-name)"><a name="d0e8277"></a><h4>BOOST_MSM_EUML_ATTRIBUTES(attributes-expression,attributes-name)</h4><p>This macro declares an attribute list called attributes-name based on
+ the expression as first argument. These attributes can then be made part
+ of an event using BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES, of a state as
+ 3rd parameter of BOOST_MSM_EUML_STATE or of a state machine as 5th
+ parameter of BOOST_MSM_EUML_DECLARE_STATE_MACHINE.</p><p>Attributes are added using left-shift, for example:</p><pre class="programlisting">// m_song is of type std::string
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
+// contains one attribute, m_song
+BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)</pre></div><div class="refsect3" title="BOOST_MSM_EUML_EVENT(event-instance name)"><a name="d0e8286"></a><h4>BOOST_MSM_EUML_EVENT(event-instance name)</h4><p>This macro defines an event type (event-instance-name_helper) and
+ declares a const instance of this event type called event-instance-name
+ for use in a transition table or state behaviors.</p></div><div class="refsect3" title="BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(event-instance-name,attributes)"><a name="d0e8291"></a><h4>BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(event-instance-name,attributes)</h4><p>This macro defines an event type (event-instance-name_helper) and
+ declares a const instance of this event type called event-instance-name
+ for use in a transition table or state behaviors. The event will have as
+ attributes the ones passed by the second argument:</p><p><code class="code">BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(Found,FoundDef)</code>
+ </p><p>The created event instance supports operator()(attributes) so that
+ </p><pre class="programlisting">my_back_end.process_event(Found(some_string))</pre><p>
+ is possible.</p></div><div class="refsect3" title="BOOST_MSM_EUML_EVENT_NAME(event-instance-name)"><a name="d0e8305"></a><h4>BOOST_MSM_EUML_EVENT_NAME(event-instance-name)</h4><p>This macro returns the name of the event type generated by
+ BOOST_MSM_EUML_EVENT or BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES. You need
+ this where the type is required (usually inside a back-end definition).
+ For example:</p><p>
+ </p><pre class="programlisting">typedef msm::back::state_machine<Playing_,
+msm::back::ShallowHistory<mpl::vector<BOOST_MSM_EUML_EVENT_NAME(end_pause)
+> > > Playing_type;</pre><p>
+ </p></div><div class="refsect3" title="BOOST_MSM_EUML_STATE(build-expression,state-instance-name)"><a name="d0e8315"></a><h4>BOOST_MSM_EUML_STATE(build-expression,state-instance-name)</h4><p>This macro defines a state type (state-instance-name_helper) and
+ declares a const instance of this state type called state-instance-name
+ for use in a transition table or state behaviors.</p><p>There are several possibilitites for the expression syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(): state without entry or exit action.</p></li><li class="listitem"><p>(Expr1): state with entry but no exit action.</p></li><li class="listitem"><p>(Expr1,Expr2): state with entry and exit action.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes): state with entry and exit
+ action, defining some attributes.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure): state with entry and
+ exit action, defining some attributes and flags (standard
+ MSM flags) or deferred events (standard MSM deferred
+ events).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure,Base): state with entry
+ and exit action, defining some attributes, flags and
+ deferred events (plain msm deferred events) and a
+ non-default base state (as defined in standard MSM).</p></li></ul></div></div><div class="refsect3" title="BOOST_MSM_EUML_INTERRUPT_STATE(build-expression,state-instance-name)"><a name="d0e8341"></a><h4>BOOST_MSM_EUML_INTERRUPT_STATE(build-expression,state-instance-name)</h4><p>This macro defines an interrupt state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</p><p>There are several possibilitites for the expression syntax. In all of
+ them, the first argument is the name of the event (generated by one of
+ the previous macros) ending the interrupt:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(end_interrupt_event): interrupt state without entry or
+ exit action.</p></li><li class="listitem"><p>(end_interrupt_event,Expr1): interrupt state with entry
+ but no exit action.</p></li><li class="listitem"><p>(end_interrupt_event,Expr1,Expr2): interrupt state with
+ entry and exit action.</p></li><li class="listitem"><p>(end_interrupt_event,Expr1,Expr2,Attributes): interrupt
+ state with entry and exit action, defining some
+ attributes.</p></li><li class="listitem"><p>(end_interrupt_event,Expr1,Expr2,Attributes,Configure):
+ interrupt state with entry and exit action, defining some
+ attributes and flags (standard MSM flags) or deferred events
+ (standard MSM deferred events).</p></li><li class="listitem"><p>(end_interrupt_event,Expr1,Expr2,Attributes,Configure,Base):
+ interrupt state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</p></li></ul></div></div><div class="refsect3" title="BOOST_MSM_EUML_TERMINATE_STATE(build-expression,state-instance-name)"><a name="d0e8367"></a><h4>BOOST_MSM_EUML_TERMINATE_STATE(build-expression,state-instance-name)</h4><p>This macro defines a terminate pseudo-state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</p><p>There are several possibilitites for the expression syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(): terminate pseudo-state without entry or exit
+ action.</p></li><li class="listitem"><p>(Expr1): terminate pseudo-state with entry but no exit
+ action.</p></li><li class="listitem"><p>(Expr1,Expr2): terminate pseudo-state with entry and exit
+ action.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes): terminate pseudo-state with
+ entry and exit action, defining some attributes.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure): terminate pseudo-state
+ with entry and exit action, defining some attributes and
+ flags (standard MSM flags) or deferred events (standard MSM
+ deferred events).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure,Base): terminate
+ pseudo-state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</p></li></ul></div></div><div class="refsect3" title="BOOST_MSM_EUML_EXIT_STATE(build-expression,state-instance-name)"><a name="d0e8393"></a><h4>BOOST_MSM_EUML_EXIT_STATE(build-expression,state-instance-name)</h4><p>This macro defines an exit pseudo-state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</p><p>There are several possibilitites for the expression syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(forwarded_event):exit pseudo-state without entry or exit
+ action.</p></li><li class="listitem"><p>(forwarded_event,Expr1): exit pseudo-state with entry but
+ no exit action.</p></li><li class="listitem"><p>(forwarded_event,Expr1,Expr2): exit pseudo-state with
+ entry and exit action.</p></li><li class="listitem"><p>(forwarded_event,Expr1,Expr2,Attributes): exit
+ pseudo-state with entry and exit action, defining some
+ attributes.</p></li><li class="listitem"><p>(forwarded_event,Expr1,Expr2,Attributes,Configure): exit
+ pseudo-state with entry and exit action, defining some
+ attributes and flags (standard MSM flags) or deferred events
+ (standard MSM deferred events).</p></li><li class="listitem"><p>(forwarded_event,Expr1,Expr2,Attributes,Configure,Base):
+ exit pseudo-state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</p></li></ul></div><p>Note that the forwarded_event must be constructible from the event
+ sent by the submachine containing the exit point.</p></div><div class="refsect3" title="BOOST_MSM_EUML_ENTRY_STATE(int region-index,build-expression,state-instance-name)"><a name="d0e8421"></a><h4>BOOST_MSM_EUML_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</h4><p>This macro defines an entry pseudo-state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</p><p>There are several possibilitites for the expression syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(): entry pseudo-state without entry or exit
+ action.</p></li><li class="listitem"><p>(Expr1): entry pseudo-state with entry but no exit
+ action.</p></li><li class="listitem"><p>(Expr1,Expr2): entry pseudo-state with entry and exit
+ action.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes): entry pseudo-state with entry
+ and exit action, defining some attributes.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure): entry pseudo-state
+ with entry and exit action, defining some attributes and
+ flags (standard MSM flags) or deferred events (standard MSM
+ deferred events).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure,Base): entry
+ pseudo-state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</p></li></ul></div></div><div class="refsect3" title="BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(int region-index,build-expression,state-instance-name)"><a name="d0e8447"></a><h4>BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</h4><p>This macro defines a submachine's substate type
+ (state-instance-name_helper), which can be explicitly entered and also
+ declares a const instance of this state type called state-instance-name
+ for use in a transition table or state behaviors.</p><p>There are several possibilitites for the expression syntax:</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>(): state without entry or exit action.</p></li><li class="listitem"><p>(Expr1): state with entry but no exit action.</p></li><li class="listitem"><p>(Expr1,Expr2): state with entry and exit action.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes): state with entry and exit
+ action, defining some attributes.</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure): state with entry and
+ exit action, defining some attributes and flags (standard
+ MSM flags) or deferred events (standard MSM deferred
+ events).</p></li><li class="listitem"><p>(Expr1,Expr2,Attributes,Configure,Base): state with entry
+ and exit action, defining some attributes, flags and
+ deferred events (plain msm deferred events) and a
+ non-default base state (as defined in standard MSM).</p></li></ul></div></div><div class="refsect3" title="BOOST_MSM_EUML_STATE_NAME(state-instance-name)"><a name="d0e8473"></a><h4>BOOST_MSM_EUML_STATE_NAME(state-instance-name)</h4><p>This macro returns the name of the state type generated by
+ BOOST_MSM_EUML_STATE or other state macros. You need this where the type
+ is required (usually using a backend function). For example:</p><p>
+ </p><pre class="programlisting">fsm.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().some_state_function();</pre><p>
+ </p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_STATE(build-expression,state-instance-name)"><a name="d0e8483"></a><h4>BOOST_MSM_EUML_DECLARE_STATE(build-expression,state-instance-name)</h4><p>Like BOOST_MSM_EUML_STATE but does not provide an instance, simply a
+ type declaration.</p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_INTERRUPT_STATE(build-expression,state-instance-name)"><a name="d0e8488"></a><h4>BOOST_MSM_EUML_DECLARE_INTERRUPT_STATE(build-expression,state-instance-name)</h4><p>Like BOOST_MSM_EUML_INTERRUPT_STATE but does not provide an instance,
+ simply a type declaration.</p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_TERMINATE_STATE(build-expression,state-instance-name)"><a name="d0e8493"></a><h4>BOOST_MSM_EUML_DECLARE_TERMINATE_STATE(build-expression,state-instance-name)</h4><p>Like BOOST_MSM_EUML_TERMINATE_STATE but does not provide an instance,
+ simply a type declaration.</p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_EXIT_STATE(build-expression,state-instance-name)"><a name="d0e8498"></a><h4>BOOST_MSM_EUML_DECLARE_EXIT_STATE(build-expression,state-instance-name)</h4><p>Like BOOST_MSM_EUML_EXIT_STATE but does not provide an instance,
+ simply a type declaration.</p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_ENTRY_STATE(int region-index,build-expression,state-instance-name)"><a name="d0e8503"></a><h4>BOOST_MSM_EUML_DECLARE_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</h4><p>Like BOOST_MSM_EUML_ENTRY_STATE but does not provide an instance,
+ simply a type declaration.</p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_EXPLICIT_ENTRY_STATE(int region-index,build-expression,state-instance-name)"><a name="d0e8508"></a><h4>BOOST_MSM_EUML_DECLARE_EXPLICIT_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</h4><p>Like BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE but does not provide an
+ instance, simply a type declaration.</p></div><div class="refsect3" title="BOOST_MSM_EUML_TRANSITION_TABLE(expression, table-instance-name)"><a name="d0e8513"></a><h4>BOOST_MSM_EUML_TRANSITION_TABLE(expression,
+ table-instance-name)</h4><p>This macro declares a transition table type and also declares a const
+ instance of the table which can then be used in a state machine
+ declaration (see BOOST_MSM_EUML_DECLARE_STATE_MACHINE).The expression
+ must follow the <span class="command"><strong><a class="command" href="re03.html#reference-stt-grammar">transition
+ table grammar</a></strong></span>.</p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE(iexpression,table-instance-name)"><a name="d0e8521"></a><h4>BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE(iexpression,table-instance-name)</h4><p>Like BOOST_MSM_EUML_TRANSITION_TABLE but does not provide an instance,
+ simply a type declaration.</p></div><div class="refsect3" title="BOOST_MSM_EUML_INTERNAL_TRANSITION_TABLE(expression, table-instance-name)"><a name="d0e8526"></a><h4>BOOST_MSM_EUML_INTERNAL_TRANSITION_TABLE(expression,
+ table-instance-name)</h4><p>This macro declares a transition table type and also declares a const
+ instance of the table.The expression must follow the <span class="command"><strong><a class="command" href="re03.html#reference-stt-grammar">transition table
+ grammar</a></strong></span>. For the moment, this macro is not used.</p></div><div class="refsect3" title="BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE(iexpression,table-instance-name)"><a name="d0e8534"></a><h4>BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE(iexpression,table-instance-name)</h4><p>Like BOOST_MSM_EUML_TRANSITION_TABLE but does not provide an instance,
+ simply a type declaration. This is currently the only way to declare an
+ internal transition table with eUML. For example:</p><pre class="programlisting">BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
+struct Open_impl : public Open_def
+{
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ open_close [internal_guard1] / internal_action1 ,
+ open_close [internal_guard2] / internal_action2
+ ))
+}; </pre></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="re02.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt02.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Back-end </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/reference.css
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/reference.css 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,11 @@
+/*============================================================================
+ Copyright 2003-2004 Douglas Gregor
+ 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)
+============================================================================*/
+
+PRE.synopsis {
+ background-color: #e0ffff;
+ border: thin solid blue;
+ padding: 1em
+}
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/rn01.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/rn01.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,3 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Reference</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="pt02.html" title="Part II. Reference"><link rel="prev" href="ch09.html" title="Chapter 9. Functional programming"><link rel="next" href="rn01re01.html" title="Back-end classes"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Reference</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch09.html">Prev</a> </td><th width="60%" align="center">Part II. Reference</th><td width="20%" align="right"> <a accesskey="n" href="rn01re01.html">Next</a></td></tr></table><hr></div><div class="reference" title="Reference"><div class="titlepage"><div><div><h1 class="title"><a name="d0e5672"></a>Reference</h1></div></div><hr></div><div class="toc"
><p><b>Table of Contents</b></p><dl><dt><span class="refentrytitle">Back-end classes</span><span class="refpurpose"> — the types provided by the back-end (boost::msm::back)</span></dt></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch09.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="pt02.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="rn01re01.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 9. Functional programming </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Back-end classes</td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/HTML/rn01re01.html
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/HTML/rn01re01.html 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,73 @@
+<html><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+ <title>Back-end classes</title><meta name="generator" content="DocBook XSL-NS Stylesheets V1.75.2"><link rel="home" href="index.html" title="Meta State Machine (MSM)"><link rel="up" href="rn01.html" title="Reference"><link rel="prev" href="rn01.html" title="Reference"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Back-end classes</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="rn01.html">Prev</a> </td><th width="60%" align="center">Reference</th><td width="20%" align="right"> </td></tr></table><hr></div><div class="refentry" title="Back-end classes"><a name="d0e5675"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>Back-end classes — the types provided by the back-end (boost::msm::back)</p></div><div class="refsect1" title="state_machine.hpp"><a name="d0e5681"></a><h2>state_machine.hpp</h2><p> This hea
der provides one type, state_machine, MSM's state machine engine
+ implementation.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">template <class Derived,class
+ HistoryPolicy=NoHistory,class CompilePolicy=favor_runtime_speed>
+ state_machine</span></span> {<br>}</pre><div class="refsect2" title="methods"><a name="d0e5690"></a><h3> methods </h3><div class="refsect3" title="start"><a name="d0e5693"></a><h4>start</h4><p> The start methods must be called before any call to
+ process_event. It activates the entry action of the initial
+ state(s). This allows you to choose when a state machine can start.
+ (TODO in user guide)</p><code class="methodsynopsis"><span class="methodname">void start</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="process_event"><a name="d0e5703"></a><h4>process_event</h4><p>The event processing method implements the double-dispatch. Each
+ call to this function with a new event type instantiates a new
+ dispatch algorithm and increases compile-time.</p><code class="methodsynopsis"><span class="methodname">template <class Event> HandledEnum
+ process_event</span>(<span class="methodparam">Event const&</span>);</code></div><div class="refsect3" title="current_state"><a name="d0e5714"></a><h4>current_state</h4><p>Returns the ids of currently active states. You will typically
+ need it only for debugging or logging purposes.</p><code class="methodsynopsis"><span class="methodname">const int* current_state const</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="get_state_by_id"><a name="d0e5724"></a><h4>get_state_by_id</h4><p>Returns the state whose id is given. As all states of a concrete
+ state machine share a common base state, the return value is a base
+ state. If the id corresponds to no state, a null pointer is
+ returned.</p><code class="methodsynopsis"><span class="methodname">const BaseState* get_state_by_id const</span>(<span class="methodparam">int id</span>);</code></div><div class="refsect3" title="is_contained"><a name="d0e5735"></a><h4>is_contained</h4><p>Helper returning true if the state machine is contained as a
+ submachine of another state machine.</p><code class="methodsynopsis"><span class="methodname">bool is_contained const</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="get_state"><a name="d0e5745"></a><h4>get_state</h4><p>Returns the required state of the state machine as a pointer. A
+ compile error will occur if the state is not to be found in the
+ state machine.</p><code class="methodsynopsis"><span class="methodname">template <class State> State* get_state</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="get_state"><a name="d0e5755"></a><h4>get_state</h4><p>Returns the required state of the state machine as a reference. A
+ compile error will occur if the state is not to be found in the
+ state machine.</p><code class="methodsynopsis"><span class="methodname">template <class State> State&
+ get_state</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="is_flag_active"><a name="d0e5765"></a><h4>is_flag_active</h4><p>Returns true if the given flag is currently active. A flag is
+ active if the active state of one region is tagged with this flag
+ (using OR as BinaryOp) or active states of <span class="underline">all</span> regions (using AND as
+ BinaryOp)</p><code class="methodsynopsis"><span class="methodname">template <class Flag,class BinaryOp> bool
+ is_flag_active</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="is_flag_active"><a name="d0e5778"></a><h4>is_flag_active</h4><p>Returns true if the given flag is currently active. A flag is
+ active if the active state of one region is tagged with this
+ flag.</p><code class="methodsynopsis"><span class="methodname">template <class Flag> bool
+ is_flag_active</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="visit_current_states"><a name="d0e5788"></a><h4>visit_current_states</h4><p>Visits all active states and their substates. A state is visited
+ using the <code class="code">accept</code> method without argument. The base
+ class of all states must provide an <code class="code">accept_sig</code>
+ type.</p><code class="methodsynopsis"><span class="methodname">void visit_current_states</span>(<span class="methodparam"></span>);</code></div><div class="refsect3" title="visit_current_states"><a name="d0e5804"></a><h4>visit_current_states</h4><p>Visits all active states and their substates. A state is visited
+ using the <code class="code">accept</code> method with arguments. The base class
+ of all states must provide an <code class="code">accept_sig</code> type defining
+ the signature and thus the number and type of the parameters.</p><code class="methodsynopsis"><span class="methodname">void visit_current_states</span>(<span class="methodparam">any-type param1, any-type param2,...</span>);</code></div><div class="refsect3" title="defer_event"><a name="d0e5821"></a><h4>defer_event</h4><p> Defers the provided event. This method can be called only if at
+ least one state defers an event or if the state machine provides the
+ <code class="code">activate_deferred_events</code>(TODO example) type either
+ directly or using the deferred_events configuration of eUML
+ (<code class="code">configure_ << deferred_events</code>)</p><code class="methodsynopsis"><span class="methodname">template <class Event> void defer_event</span>(<span class="methodparam">Event const&</span>);</code></div></div><div class="refsect2" title="Types"><a name="d0e5838"></a><h3>Types</h3><div class="refsect3" title="entry_pt"><a name="d0e5841"></a><h4>entry_pt</h4><p>This nested type provides the necessary typedef for entry point
+ pseudostates.
+ <code class="code">state_machine<...>::entry_pt<state_name></code> is a
+ transition's valid target inside the containing state machine's
+ transition table.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">entry_pt</span></span> {<br>}</pre></div><div class="refsect3" title="exit_pt"><a name="d0e5853"></a><h4>exit_pt</h4><p>This nested type provides the necessary typedef for exit point
+ pseudostates.
+ <code class="code">state_machine<...>::exit_pt<state_name></code> is a
+ transition's valid source inside the containing state machine's
+ transition table.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">exit_pt</span></span> {<br>}</pre></div><div class="refsect3" title="direct"><a name="d0e5865"></a><h4>direct</h4><p>This nested type provides the necessary typedef for an explicit
+ entry inside a submachine.
+ <code class="code">state_machine<...>::direct<state_name></code> is a
+ transition's valid target inside the containing state machine's
+ transition table.</p><pre class="classsynopsis"> <span class="ooclass"><span class="classname">direct</span></span> {<br>}</pre></div></div></div><div class="refsect1" title="args.hpp"><a name="d0e5877"></a><h2>args.hpp</h2><p>This header provides one type, args. which provides the necessary types
+ for a visitor implementation.</p></div><div class="refsect1" title="history_policies.hpp"><a name="d0e5882"></a><h2>history_policies.hpp</h2><p>This header provides the out-of-the-box history policies supported by MSM.
+ There are 3 such policies. Every history policy must implement the following
+ methods:</p><div class="refsect2" title="set_initial_states"><a name="d0e5887"></a><h3> set_initial_states </h3><p> This method is called by msm::back::state_machine when constructed.
+ It gives the policy a chance to save the ids of all initial states
+ (passed as array).</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">void set_initial_states(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>int* const<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect2" title="history_exit"><a name="d0e5901"></a><h3> history_exit </h3><p>This method is called by msm::back::state_machine when the submachine
+ is exited. It gives the policy a chance to remember the ids of the last
+ active substates of this submachine states (passed as array).</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">void history_exit(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>int* const<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect2" title="history_entry"><a name="d0e5915"></a><h3> history_entry </h3><p>This method is called by msm::back::state_machine when the submachine
+ is entered. It gives the policy a chance to set the the active states
+ according to the policy's aim. The policy gets as parameter the event
+ which activated the submachine and returns an array of active states
+ ids.</p><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0" class="funcprototype-table"><tr><td><code class="funcdef">template <class Event> int* const history_exit(</code></td><td><code>)</code>;</td><td> </td></tr></table><div class="paramdef-list"><code>
+ <code>(</code>Event const&<code>)</code>
+ </code>;</div><div class="funcprototype-spacer"> </div></div></div><div class="refsect2" title="NoHistory"><a name="d0e5929"></a><h3>NoHistory</h3><p>This policy is the default used by state_machine. No active state of a
+ submachine is remembered and at every new activation of the submachine,
+ the initial state(s) are activated. </p></div><div class="refsect2" title="AlwaysHistory"><a name="d0e5934"></a><h3>AlwaysHistory</h3><p>This policy is a non-UML-standard extension. The active state(s) of a
+ submachine is (are) always remembered at every new activation of the
+ submachine. </p></div><div class="refsect2" title="ShallowHistory"><a name="d0e5939"></a><h3>ShallowHistory</h3><p>This policy activates the active state(s) of a submachine if the event
+ is found in the policy's event list. </p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="rn01.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="rn01.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Reference </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
\ No newline at end of file
Added: trunk/libs/msm/doc/PDF/examples/AnonymousTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/AnonymousTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,123 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+
+
+ // front-end: define the FSM structure
+ struct my_machine_ : public msm::front::state_machine_def<my_machine_>
+ {
+ // The list of FSM states
+ struct State1 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
+ };
+ struct State2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
+ };
+
+ struct State3 : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State3" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State3" << std::endl;}
+ };
+
+ struct State4 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State4" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State4" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ void State2ToState3(none const&) { std::cout << "my_machine::State2ToState3\n"; }
+ void State3ToState4(none const&) { std::cout << "my_machine::State3ToState4\n"; }
+ // guard conditions
+ bool always_true(none const& evt)
+ {
+ std::cout << "always_true" << std::endl;
+ return true;
+ }
+ bool always_false(none const& evt)
+ {
+ std::cout << "always_false" << std::endl;
+ return false;
+ }
+
+ typedef my_machine_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < State1 , none , State2 >,
+ a_row < State2 , none , State3 , &p::State2ToState3 >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ row < State3 , none , State4 , &p::State3ToState4 , &p::always_true >,
+ g_row < State3 , none , State4 , &p::always_false >,
+ _row < State4 , event1 , State1 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+ void pstate(my_machine const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1());
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/AnonymousTutorialEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/AnonymousTutorialEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,165 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+namespace msm = boost::msm;
+using namespace boost::msm::front::euml;
+
+namespace
+{
+ // events
+ BOOST_MSM_EUML_EVENT(event1)
+
+ BOOST_MSM_EUML_ACTION(State1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State3_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State3_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State4_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State4" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State4_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State4" << std::endl;
+ }
+ };
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( State1_Entry,State1_Exit ),State1)
+ BOOST_MSM_EUML_STATE(( State2_Entry,State2_Exit ),State2)
+ BOOST_MSM_EUML_STATE(( State3_Entry,State3_Exit ),State3)
+ BOOST_MSM_EUML_STATE(( State4_Entry,State4_Exit ),State4)
+
+ // transition actions
+ BOOST_MSM_EUML_ACTION(State2ToState3)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State2ToState3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State3ToState4)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State3ToState4" << std::endl;
+ }
+ };
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(always_true)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "always_true" << std::endl;
+ return true;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(always_false)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "always_false" << std::endl;
+ return false;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ State2 == State1 ,
+ State3 == State2 / State2ToState3,
+ State4 == State3 [always_true] / State3ToState4,
+ State4 == State3 [always_false],
+ State1 == State4 + event1
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << State1 // Init State
+ ),
+ my_machine_) //fsm name
+
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+ void pstate(my_machine const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/AnonymousTutorialWithFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/AnonymousTutorialWithFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,148 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct event1 {};
+
+
+ // front-end: define the FSM structure
+ struct my_machine_ : public msm::front::state_machine_def<my_machine_>
+ {
+ // The list of FSM states
+ struct State1 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
+ };
+ struct State2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
+ };
+
+ struct State3 : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: State3" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State3" << std::endl;}
+ };
+
+ struct State4 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State4" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State4" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ struct State2ToState3
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State2ToState3" << std::endl;
+ }
+ };
+ struct State3ToState4
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "my_machine::State3ToState4" << std::endl;
+ }
+ };
+ // guard conditions
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ std::cout << "always_true" << std::endl;
+ return true;
+ }
+ };
+ struct always_false
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ std::cout << "always_false" << std::endl;
+ return true;
+ }
+ };
+
+ typedef my_machine_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State1 , none , State2 >,
+ Row < State2 , none , State3 , State2ToState3 >,
+ Row < State3 , none , State4 , none , always_false >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < State3 , none , State4 , State3ToState4 , always_true >,
+ Row < State4 , event1 , State1 >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<my_machine_> my_machine;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "State2", "State3", "State4" };
+ void pstate(my_machine const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ my_machine p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ // in this case it will also immediately trigger all anonymous transitions
+ p.start();
+ // this event will bring us back to the initial state and thus, a new "loop" will be started
+ p.process_event(event1());
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/BoostCon09Full.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/BoostCon09Full.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,360 @@
+#include <vector>
+#include <iostream>
+#include <boost/mpl/vector/vector50.hpp>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/back/tools.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ // event which every other event can convert to
+ struct AllSongsPlayed
+ {
+ template <class Event>
+ AllSongsPlayed(Event const&){}
+ };
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(DiskTypeEnum diskType): disc_type(diskType) {}
+ DiskTypeEnum disc_type;
+ };
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ typedef mpl::vector<play> deferred_events;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+ // a state needing a pointer to the containing state machine
+ // and using for this the non-default policy
+ // if policy used, set_sm_ptr is needed
+ struct Stopped : public msm::front::state<default_base_state,msm::front::sm_ptr>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl){m_player=pl;}
+ player_* m_player;
+ };
+ // the player state machine contains a state which is himself a state machine
+ // it demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ struct CDFinished : public msm::front::exit_pseudo_state<AllSongsPlayed>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing::CDFinished" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing::CDFinished" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ void all_songs_played(NextSong const&) { std::cout << "Playing::all_songs_played\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+---------------+------------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >,
+ a_row < Song3 , NextSong , CDFinished , &pl::all_songs_played >
+ // +---------+---------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
+ };
+
+ struct AllOk : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ struct ErrorMode : //public msm::front::terminate_state<>
+ public msm::front::interrupt_state<end_error>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // 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";
+ // generate another event to test the queue
+ //cd.m_player.process_event(play());
+ }
+ void stop_playback(stop const&) { std::cout << "player::stop_playback\n"; }
+ void end_playback (AllSongsPlayed const&) { std::cout << "player::end_playback\n"; }
+ void pause_playback(pause const&) { std::cout << "player::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ a_row < Playing::exit_pt<
+ Playing_::CDFinished> , AllSongsPlayed, Stopped , &p::end_playback >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +-------------+---------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row < ErrorMode ,end_error ,AllOk , &p::report_end_error >
+ // +-------------+---------------+---------+---------------------+----------------------+
+ > {};
+
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+
+ void pstate(player const& p)
+ {
+ typedef player::stt Stt;
+ typedef msm::back::generate_state_set<Stt>::type all_states;
+ static char const* state_names[mpl::size<all_states>::value];
+ // fill the names of the states defined in the state machine
+ mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
+ (msm::back::fill_state_names<Stt>(state_names));
+
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ std::cout << "play is not handled in the current state but is marked as delayed" << std::endl;
+ p.process_event(play()); pstate(p);
+ std::cout << "cd_detected will cause play to be handled also" << std::endl;
+ // will be rejected, wrong disk type
+ p.process_event(cd_detected(DISK_DVD)); pstate(p);
+ // will be accepted, wrong disk type
+ p.process_event(cd_detected(DISK_CD)); pstate(p);
+
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
+ p.process_event(NextSong());pstate(p);
+ // We are now in second song, Flag inactive
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ p.process_event(NextSong());pstate(p);
+ // 2nd song active
+ p.process_event(PreviousSong());pstate(p);
+ // Pause
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // but end_pause is an event activating the History
+ // => keep the last active State (SecondSong)
+ p.process_event(end_pause()); pstate(p);
+ // force an exit by listening all the songs
+ p.process_event(NextSong());
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ // go back to Playing
+ // but play is not leading to Shallow History => do not remember the last active State (SecondSong)
+ // and activate again FirstSong and LightOn
+ p.process_event(play()); pstate(p);
+ p.process_event(error_found()); pstate(p);
+
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(NextSong());pstate(p);
+
+ // the states and events of the higher level FSM (player)
+ typedef player::stt Stt;
+ typedef msm::back::generate_state_set<Stt>::type simple_states;
+
+ std::cout << "the state list:" << std::endl;
+ mpl::for_each<simple_states,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+
+ std::cout << "the event list:" << std::endl;
+ typedef msm::back::generate_event_set<Stt>::type event_list;
+ mpl::for_each<event_list,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+ std::cout << std::endl;
+
+ // the states and events recursively searched
+ typedef msm::back::recursive_get_transition_table<player>::type recursive_stt;
+
+ std::cout << "the state list (including sub-SMs):" << std::endl;
+
+ typedef msm::back::generate_state_set<recursive_stt>::type all_states;
+ mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+
+ std::cout << "the event list (including sub-SMs):" << std::endl;
+ typedef msm::back::generate_event_set<recursive_stt>::type all_events;
+ mpl::for_each<all_events,boost::msm::wrap<mpl::placeholders::_1> >(msm::back::display_type ());
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
+
Added: trunk/libs/msm/doc/PDF/examples/CompilerStressTestEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/CompilerStressTestEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,436 @@
+#include <vector>
+#include <list>
+#include <set>
+#include <map>
+#include <iostream>
+
+// we need more than the default 10 states
+#define FUSION_MAX_VECTOR_SIZE 15
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+#include <boost/msm/front/euml/stl.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// how long the timer will ring when countdown elapsed.
+#define RINGING_TIME 5
+
+namespace // Concrete FSM implementation
+{
+ // flag
+ BOOST_MSM_EUML_FLAG(SomeFlag)
+
+ // declares attributes with type and name. Can be used anywhere after
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_song_id)
+
+ // declare that a type inheriting from OneSongDef will get these 2 attributes
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song << m_song_id ), OneSongDef)
+ // events
+ // this event is done "manually", not using any predefined macro
+ struct OneSong_impl : euml_event<OneSong_impl>,OneSongDef
+ {
+ OneSong_impl(){}
+ OneSong_impl(const string& asong)
+ {
+ get_attribute(m_song)=asong;
+ get_attribute(m_song_id)=1;
+ }
+ OneSong_impl(const OneSong_impl& asong)
+ {
+ get_attribute(m_song)=asong.get_attribute(m_song);
+ get_attribute(m_song_id)=1;
+ }
+ const string& get_data() const {return get_attribute(m_song);}
+ };
+ // declare an instance for use in the transition table
+ OneSong_impl const OneSong;
+
+ struct SongComparator : euml_action<SongComparator>
+ {
+ bool operator()(const OneSong_impl& lhs,const OneSong_impl& rhs)const
+ {
+ return lhs.get_data() == rhs.get_data();
+ }
+ };
+ struct SongLessComparator : euml_action<SongLessComparator>
+ {
+ bool operator()(const OneSong_impl& lhs,const OneSong_impl& rhs)const
+ {
+ return lhs.get_data() < rhs.get_data();
+ }
+ };
+ struct Comparator
+ {
+ template <class T>
+ bool operator()(const T& lhs,const T& rhs)const
+ {
+ return lhs < rhs;
+ }
+ };
+ struct RemoveDummy
+ {
+ bool operator()(const OneSong_impl& lhs)const
+ {
+ return (lhs.get_attribute(m_song).compare(std::string("She-Dummy. Remove this one"))==0 );
+ }
+ };
+ template <int val>
+ struct LookFor
+ {
+ template <class T>
+ bool operator()(const T& lhs)const
+ {
+ return lhs == val;
+ }
+ };
+ template <int val>
+ struct LessThan
+ {
+ template <class T>
+ bool operator()(const T& lhs)const
+ {
+ return lhs < val;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SongDeleter)
+ {
+ bool operator()(const OneSong_impl& lhs)const
+ {
+ return lhs.get_data() == "Twist and Shout";
+ }
+ };
+ struct Generator
+ {
+ int operator()()const
+ {
+ return 1;
+ }
+ };
+ struct Print
+ {
+ template <class T>
+ void operator()(const T& lhs)const
+ {
+ std::cout << "Song:" << lhs.get_data() << endl;
+ }
+ };
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), NotFoundDef)
+ // declare an event instance called NotFound with the defined attributes
+ // these attributes can then be referenced anywhere (stt, state behaviors)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(NotFound,NotFoundDef)
+
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)
+ struct Found_impl : euml_event<Found_impl>,FoundDef
+ {
+ Found_impl(){}
+ Found_impl (const string& data)
+ {
+ get_attribute(m_song)=data;
+ }
+ int foo()const {std::cout << "foo()" << std::endl; return 0;}
+ int foo(int i)const {std::cout << "foo(int):" << i << std::endl; return 1;}
+ int foo(int i,int j)const {std::cout << "foo(int,int):" << i <<"," << j << std::endl; return 2;}
+
+ };
+ Found_impl const Found;
+ // some functions to call
+ // this macro creates a functor and an eUML function wrapper. Now, foo_ can be used anywhere
+ BOOST_MSM_EUML_METHOD(FoundFoo_ , foo , foo_ , int , int )
+
+ template <class T>
+ int do_print(T& t ) {std::cout << "print(T):" << typeid(T).name() << std::endl;return 1;}
+ BOOST_MSM_EUML_FUNCTION(PrintState_ , do_print , print_ , int , int )
+
+ BOOST_MSM_EUML_EVENT(Done)
+
+ // Concrete FSM implementation
+ struct some_base
+ {
+ int foobar()const {std::cout << "foobar()" << std::endl; return 0;}
+ int foobar(int i)const {std::cout << "foobar(int):" << i << std::endl; return 1;}
+ int foobar(int i,int j)const {std::cout << "foobar(int,int):" << i <<"," << j << std::endl; return 2;}
+ };
+ // some functions to call
+ BOOST_MSM_EUML_METHOD(FooBar_ , foobar , foobar_ , int , int )
+
+ // fsm attributes
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_src_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<OneSong_impl>,m_tgt_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<int>,m_var2)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(list<int>,m_var3)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(set<int>,m_var4)
+ typedef std::map<int,int> int_int_map;
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int_int_map,m_var5)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_var6)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_var7)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<int>,m_var8)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<int>,m_var9)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_var10)
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( ( insert_(fsm_(m_tgt_container),end_(fsm_(m_tgt_container)),
+ append_(event_(m_song),fsm_(m_var7)) ),//foo_(event_,Int_<0>()) ,
+ //foo_(event_,Int_<0>(),Int_<1>()),print_(state_),
+ process_(Done/*,fsm_*/),if_then_(true_,true_) ),
+ no_action
+ ),Insert)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_letters)
+ BOOST_MSM_EUML_STATE(( if_then_else_( (string_find_(event_(m_song),state_(m_letters),Size_t_<0>()) != Npos_<string>()&&
+ string_find_(event_(m_song),Char_<'S'>(),Size_t_<0>()) != Npos_<string>()&&
+ string_find_first_of_(event_(m_song),Char_<'S'>()) == Size_t_<0>() &&
+ string_compare_(event_(m_song),Int_<0>(),size_(event_(m_song)),event_(m_song)) == Int_<0>()
+ //&& is_flag_(SomeFlag(),fsm_())
+ //&& ( event_(m_song_id) == Int_<1>())
+ //&& string_find_(event_(m_song),String_<mpl::string<'Sh','e'> >())
+ // != Npos_<string>()
+
+ ),
+ process2_(Found,
+ //string_insert_(event_(m_song),Size_t_<0>(),fsm_(m_var6)) ),
+ string_replace_(
+ string_assign_(
+ string_erase_(
+ string_insert_(
+ substr_(event_(m_song),Size_t_<1>()),
+ Size_t_<0>(),
+ Size_t_<1>(),
+ Char_<'S'>()),
+ Size_t_<0>(),
+ Size_t_<1>() ),
+ event_(m_song) ),
+ Size_t_<0>(),
+ Size_t_<1>(),
+ c_str_(fsm_(m_var6))
+ /*Size_t_<1>(),
+ Char_<'s'>()*/ ) ),
+ process2_(NotFound,event_(m_song),fsm_) ) ,
+ no_action,
+ attributes_ << m_letters,
+ configure_<< SomeFlag ),StringFind)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>::iterator,m_src_it)
+ BOOST_MSM_EUML_STATE(( if_then_( (state_(m_src_it) != end_(fsm_(m_src_container)) &&
+ //associative_find_(fsm_(m_var4),Int_<9>()) != end_(fsm_(m_var4))&&
+ //associative_count_(fsm_(m_var4),Int_<9>()) == Size_t_<1>() &&
+ //*associative_upper_bound_(fsm_(m_var4),Int_<8>()) == Int_<9>()&&
+ //*associative_lower_bound_(fsm_(m_var4),Int_<9>()) == Int_<9>() &&
+ //second_(associative_equal_range_(fsm_(m_var4),Int_<8>())) == associative_upper_bound_(fsm_(m_var4),Int_<8>()) &&
+ //first_(associative_equal_range_(fsm_(m_var4),Int_<8>())) == associative_lower_bound_(fsm_(m_var4),Int_<8>())&&
+ //second_(*associative_lower_bound_(fsm_(m_var5),Int_<0>())) == Int_<0>() && //map => pair as return
+ //find_if_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<LookFor<8> >()) != end_(fsm_(m_var4))&&
+ //*lower_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >()) == Int_<9>()&&
+ //*upper_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>(),Predicate_<std::less<int> >()) == Int_<9>() &&
+ //second_(equal_range_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>()))
+ // == upper_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<8>()) &&
+ //first_(equal_range_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >()))
+ // == lower_bound_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >())&&
+ //binary_search_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>(),Predicate_<std::less<int> >())&&
+ //binary_search_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>())&&
+ //count_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Int_<9>()) == Int_<1>()&&
+ //count_if_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<LookFor<9> >()) == Int_<1>()&&
+ //distance_(begin_(fsm_(m_var4)),end_(fsm_(m_var4))) == Int_<2>()&&
+ //*min_element_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<std::less<int> >()) == Int_<8>()&&
+ //*max_element_(begin_(fsm_(m_var4)),end_(fsm_(m_var4)),Predicate_<std::less<int> >()) == Int_<9>()&&
+ //adjacent_find_(begin_(fsm_(m_var4)),end_(fsm_(m_var4))) == end_(fsm_(m_var4))&&
+ //*find_end_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
+ // == Int_<1>()&&
+ //*find_first_of_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
+ // == Int_<1>()&&
+ //equal_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),begin_(fsm_(m_var8)))&&
+ //*search_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))
+ // == Int_<1>()&&
+ //includes_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),begin_(fsm_(m_var9)),end_(fsm_(m_var9)))&&
+ //!lexicographical_compare_(begin_(fsm_(m_var8)),end_(fsm_(m_var8)),
+ // begin_(fsm_(m_var9)),end_(fsm_(m_var9)))&&
+ //first_(mismatch_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),begin_(fsm_(m_var8))))
+ // == end_(fsm_(m_var9)) &&
+ accumulate_(begin_(fsm_(m_var9)),end_(fsm_(m_var9)),Int_<1>(),
+ Predicate_<std::plus<int> >()) == Int_<1>()
+ ),
+ (process2_(OneSong,*(state_(m_src_it)++))/*,foobar_(fsm_,Int_<0>())*/ ) ),
+ no_action,
+ attributes_ << m_src_it
+ , configure_<< SomeFlag ),Foreach)
+
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ StringFind == Foreach + OneSong[if_then_else_(true_,true_,true_)],
+ Insert == StringFind + Found / (if_then_(true_,no_action)),
+ Foreach == StringFind + NotFound ,
+ Foreach == Insert + Done
+ // +------------------------------------------------------------------------------+
+ ),transition_table )
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Foreach, // Init
+ //insert_(state_(m_var4),begin_(state_(m_var2)),end_(state_(m_var2))),
+ (insert_(state_(m_var4),Int_<5>()),insert_(state_(m_var4),Int_<6>()),insert_(state_(m_var4),Int_<7>()),
+ insert_(state_(m_var4),Int_<8>()),insert_(state_(m_var4),Int_<9>()),
+ associative_erase_(state_(m_var4),Int_<6>()),associative_erase_(state_(m_var4),begin_(state_(m_var4))),
+ associative_erase_(state_(m_var4),begin_(state_(m_var4)),++begin_(state_(m_var4))),
+ insert_(state_(m_var2),begin_(state_(m_var2)),begin_(state_(m_var3)),end_(state_(m_var3))),
+ state_(m_var5)[Int_<0>()]=Int_<0>(),state_(m_var5)[Int_<1>()]=Int_<1>()
+ ,attribute_(substate_(Foreach,fsm_),m_src_it)
+ = begin_(fsm_(m_src_container))
+ //,fill_(begin_(state_(m_var9)),end_(state_(m_var9)),Int_<0>())
+ //,fill_n_(begin_(state_(m_var9)),Size_t_<2>(),Int_<0>())
+ //,transform_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var2)),begin_(state_(m_var4)),
+ // Predicate_<std::plus<int> >())
+ //,process_(Done,fsm_(),fsm_)
+ //,process_(Done,fsm_)
+ //,fsm_
+ //,foobar_(state_,Int_<0>(),Int_<1>())
+ //,nth_element_(begin_(state_(m_var9)),++begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,partial_sort_(begin_(state_(m_var9)),end_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,partial_sort_copy_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,list_sort_(state_(m_var2))
+ //,sort_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,inner_product_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),Int_<1>())
+ //,replace_copy_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var4)),Int_<8>(),Int_<7>())
+ //,replace_copy_if_(begin_(state_(m_var4)),end_(state_(m_var4)),begin_(state_(m_var4)),Predicate_<LookFor<9> >(),Int_<8>())
+ //,replace_(begin_(state_(m_var4)),end_(state_(m_var4)),Int_<8>(),Int_<7>())
+ //,replace_if_(begin_(state_(m_var4)),end_(state_(m_var4)),Predicate_<LookFor<9> >(),Int_<8>())
+ //,adjacent_difference_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
+ //,partial_sum_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
+ //,inner_product_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),Int_<1>())
+ //,next_permutation_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,prev_permutation_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,set_union_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)))
+ //,inplace_merge_(begin_(state_(m_var9)),end_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,merge_(begin_(state_(m_var9)),end_(state_(m_var9)),begin_(state_(m_var9)),end_(state_(m_var9))
+ // ,begin_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,stable_sort_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<std::less<int> >())
+ //,partition_(begin_(state_(m_var2)),end_(state_(m_var2)),Predicate_<LessThan<3> >())
+ //,stable_partition_(begin_(state_(m_var2)),end_(state_(m_var2)),Predicate_<LessThan<3> >())
+ //,rotate_copy_(begin_(state_(m_var2)),++begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
+ //,rotate_(begin_(state_(m_var2)),++begin_(state_(m_var2)),end_(state_(m_var2)))
+ //,unique_(begin_(state_(m_var2)),end_(state_(m_var2)))
+ //,unique_copy_(begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
+ //,random_shuffle_(begin_(state_(m_var9)),end_(state_(m_var9)))
+ //,generate_(begin_(state_(m_var9)),end_(state_(m_var9)),Predicate_<Generator>())
+ //,generate_n_(begin_(state_(m_var9)),Int_<2>(),Predicate_<Generator>())
+ //,reverse_copy_(begin_(state_(m_var2)),end_(state_(m_var2)),begin_(state_(m_var2)))
+ //erase_(state_(m_src_container),
+ // remove_if_(begin_(state_(m_src_container)),end_(state_(m_src_container)),
+ // Predicate_<RemoveDummy>()),
+ // end_(state_(m_src_container))),
+ //list_remove_(state_(m_var2),Int_<3>()),
+ //remove_copy_if_(begin_(state_(m_var9)),end_(state_(m_var9)),back_inserter_(state_(m_var2)),
+ // Predicate_<LookFor<2> >() )
+ //for_each_(begin_(state_(m_src_container)),end_(state_m_src_container()),
+ // Predicate_<Print>() ),
+ //copy_(begin_(state_(m_var9)),end_(state_(m_var9)),inserter_(state_(m_var2),end_(state_(m_var2)))),
+ //reverse_(begin_(state_(m_var2)),end_(state_(m_var2)))
+ ),
+ //no_action, // Entry
+ //splice_(state_(m_var2),begin_(state_(m_var2)),state_(m_var3),begin_(state_(m_var3)),end_(state_(m_var3))),
+ //(list_remove_(state_(m_var2),Int_<3>()),list_merge_(state_(m_var2),state_(m_var3),Comparator())),//no_action, // Entry
+ no_action, // Exit
+ attributes_ << m_src_container // song list
+ << m_tgt_container // result
+ << m_var2
+ << m_var3
+ << m_var4
+ << m_var5
+ << m_var6
+ << m_var7
+ << m_var8
+ << m_var9
+ << m_var10,
+ configure_<< no_configure_,
+ Log_No_Transition
+ ),iPodSearch_helper)
+
+ struct iPodSearch_ : public iPodSearch_helper, public some_base
+ {
+ };
+
+
+ // choice of back-end
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+
+ void test()
+ {
+ iPodSearch search;
+ // fill our song list
+ //search.get_attribute<m_src_container>().push_back(OneSong("She-Dummy. Remove this one"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("Let it be"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("Yellow submarine"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("Twist and Shout"));
+ search.get_attribute(m_src_container).push_back(OneSong_impl("She Loves You"));
+
+ search.get_attribute(m_var2).push_back(1);
+ search.get_attribute(m_var2).push_back(3);
+ search.get_attribute(m_var2).push_back(4);
+
+ search.get_attribute(m_var3).push_back(2);
+ search.get_attribute(m_var3).push_back(4);
+
+ search.get_attribute(m_var6) = "S";
+ search.get_attribute(m_var7) = "- Some text";
+
+ search.get_attribute(m_var8).push_back(1);
+ search.get_attribute(m_var8).push_back(2);
+ search.get_attribute(m_var8).push_back(3);
+ search.get_attribute(m_var8).push_back(4);
+
+ search.get_attribute(m_var9).push_back(1);
+ search.get_attribute(m_var9).push_back(2);
+
+
+ // look for "She Loves You" using the first letters
+ // BOOST_MSM_EUML_STATE_NAME returns the name of the event type of which StringFind is an instance
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="Sh";
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ search.start();
+ // display all the songs
+ for (list<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_data() << endl;
+ }
+ for (list<int>::const_iterator iti = search.get_attribute(m_var2).begin();
+ iti != search.get_attribute(m_var2).end();++iti)
+ {
+ cout << "int in attribute m_var2:" << (*iti) << endl;
+ }
+ for (set<int>::const_iterator its = search.get_attribute(m_var4).begin();
+ its != search.get_attribute(m_var4).end();++its)
+ {
+ cout << "int in attribute m_var4:" << (*its) << endl;
+ }
+ cout << "search using more letters" << endl;
+ // look for "She Loves You" using more letters
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="She";
+ search.get_attribute(m_tgt_container).clear();
+ search.start();
+ // display all the songs
+ for (list<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_data() << endl;
+ }
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/CompositeTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/CompositeTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,223 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+ p.process_event(play());
+
+ // at this point, Play is active
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/CompositeTutorialEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/CompositeTutorialEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,172 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(region2_evt)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+
+
+ // Playing is now a state machine itself.
+
+ // It has 5 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+ BOOST_MSM_EUML_STATE(( Region2State1_Entry,Region2State1_Exit ),Region2State1)
+ BOOST_MSM_EUML_STATE(( Region2State2_Entry,Region2State2_Exit ),Region2State2)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song,
+ Region2State2 == Region2State1 + region2_evt
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1 << Region2State1 // Init State
+ ),Playing_)
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format &&(event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
+ // you now have less to type.
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play);
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/DirectEntryEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/DirectEntryEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,376 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(event1)
+ BOOST_MSM_EUML_EVENT(event2)
+ BOOST_MSM_EUML_EVENT(event3)
+ BOOST_MSM_EUML_EVENT(event4)
+ BOOST_MSM_EUML_EVENT(event5)
+ // if we need something special, like a template constructor, we cannot use the helper macros
+ struct event6_impl : euml_event<event6_impl>
+ {
+ event6_impl(){}
+ template <class Event>
+ event6_impl(Event const&){}
+ };
+ event6_impl const event6;
+
+ //Sub fsm state definition
+ BOOST_MSM_EUML_ACTION(SubState1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState1_Entry,SubState1_Exit ),SubState1)
+
+ BOOST_MSM_EUML_ACTION(SubState1b_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState1b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState1b_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState1b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState1b_Entry,SubState1b_Exit ),SubState1b)
+
+ BOOST_MSM_EUML_ACTION(SubState1c_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState1c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState1c_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState1c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState1c_Entry,SubState1c_Exit ),SubState1c)
+
+ BOOST_MSM_EUML_ACTION(SubState2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0,( SubState2_Entry,SubState2_Exit ),SubState2)
+
+ BOOST_MSM_EUML_ACTION(SubState2b_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState2b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState2b_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState2b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(1,( SubState2b_Entry,SubState2b_Exit ),SubState2b)
+
+ BOOST_MSM_EUML_ACTION(SubState2c_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState2c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState2c_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState2c" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(2,( SubState2c_Entry,SubState2c_Exit ),SubState2c)
+
+ BOOST_MSM_EUML_ACTION(PseudoEntry1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::PseudoEntry1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(PseudoEntry1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::PseudoEntry1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ENTRY_STATE(0,( PseudoEntry1_Entry,PseudoEntry1_Exit ),PseudoEntry1)
+
+ BOOST_MSM_EUML_ACTION(SubState3_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState3_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState3" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState3_Entry,SubState3_Exit ),SubState3)
+
+ BOOST_MSM_EUML_ACTION(SubState3b_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::SubState3b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubState3b_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::SubState3b" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( SubState3b_Entry,SubState3b_Exit ),SubState3b)
+
+ BOOST_MSM_EUML_ACTION(PseudoExit1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2::PseudoExit1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(PseudoExit1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2::PseudoExit1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_EXIT_STATE(( event6,PseudoExit1_Entry,PseudoExit1_Exit ),PseudoExit1)
+
+ // actions
+ BOOST_MSM_EUML_ACTION(entry_action)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(FSM& ,EVT const& ,SourceState& ,TargetState& )
+ {
+ cout << "calling entry_action" << endl;
+ }
+ };
+ // SubFsm definition
+ BOOST_MSM_EUML_ACTION(SubFsm2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SubFsm2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(SubFsm2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: SubFsm2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ SubState3 == PseudoEntry1 + event4 / entry_action ,
+ SubState1 == SubState2 + event6 ,
+ PseudoExit1 == SubState3 + event5
+ // +------------------------------------------------------------------------------+
+ ), SubFsm2_transition_table)
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (SubFsm2_transition_table, //STT
+ init_ << SubState1 << SubState1b << SubState1c, // Init State
+ SubFsm2_Entry, // Entry
+ SubFsm2_Exit
+ ),SubFsm2_def)
+ // inherit to add some typedef
+ struct SubFsm2_ : public SubFsm2_def
+ {
+ // these 2 states are not found in the transition table because they are accessed only through
+ // a fork, so we need to create them explicitly
+ typedef mpl::vector<BOOST_MSM_EUML_STATE_NAME(SubState2b),
+ BOOST_MSM_EUML_STATE_NAME(SubState2c)> explicit_creation;
+ };
+
+ // back-end
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2_type;
+ SubFsm2_type const SubFsm2;
+
+ // Fsm state definitions
+ BOOST_MSM_EUML_ACTION(State1_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State1_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State1" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( State1_Entry,State1_Exit ),State1)
+
+ BOOST_MSM_EUML_ACTION(State2_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_ACTION(State2_Exit)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: State2" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( State2_Entry,State2_Exit ),State2)
+
+ // Fsm definition
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ SubFsm2 == State1 + event1 ,
+ explicit_(SubFsm2,SubState2) == State1 + event2,
+ (explicit_(SubFsm2,SubState2),
+ explicit_(SubFsm2,SubState2b),
+ explicit_(SubFsm2,SubState2c)) == State1 + event3 ,
+ entry_pt_(SubFsm2,PseudoEntry1) == State1 + event4 ,
+ State1 == SubFsm2 + event1 ,
+ State2 == exit_pt_
+ (SubFsm2,PseudoExit1) + event6
+ // +------------------------------------------------------------------------------+
+ ),transition_table )
+
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const& e,FSM&,STATE& )
+ {
+ std::cout << "no transition in Fsm"
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << State1, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ Fsm_) //fsm name
+
+ //back-end
+ typedef msm::back::state_machine<Fsm_> Fsm;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "SubFsm2","State2" };
+ void pstate(Fsm const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ Fsm p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "Simply move in and out of the composite, activate init states" << std::endl;
+ p.process_event(event1); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "Direct entry into SubFsm2::SubState2, then transition to SubState1 and back to State1" << std::endl;
+ p.process_event(event2); pstate(p);
+ p.process_event(event6); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "processing fork to SubFsm2::SubState2, SubFsm2::SubState2b and SubFsm2::SubState2c" << std::endl;
+ p.process_event(event3); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "processing entry pseudo state" << std::endl;
+ p.process_event(event4); pstate(p);
+ p.process_event(event1); pstate(p);
+ std::cout << "processing entry + exit pseudo state" << std::endl;
+ p.process_event(event4); pstate(p);
+ std::cout << "using exit pseudo state" << std::endl;
+ p.process_event(event5); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/DirectEntryTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/DirectEntryTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,211 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct event1 {};
+ struct event2 {};
+ struct event3 {};
+ struct event4 {};
+ struct event5 {};
+ struct event6
+ {
+ event6(){}
+ template <class Event>
+ event6(Event const&){}
+ };
+ // front-end: define the FSM structure
+ struct Fsm_ : public msm::front::state_machine_def<Fsm_>
+ {
+ // The list of FSM states
+ struct State1 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State1" << std::endl;}
+ };
+ struct State2 : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: State2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: State2" << std::endl;}
+ };
+ struct SubFsm2_ : public msm::front::state_machine_def<SubFsm2_>
+ {
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2" << std::endl;}
+
+ struct SubState1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState1" << std::endl;}
+ };
+ struct SubState1b : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState1b" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState1b" << std::endl;}
+ };
+ struct SubState2 : public msm::front::state<> , public msm::front::explicit_entry<0>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState2" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState2" << std::endl;}
+ };
+ struct SubState2b : public msm::front::state<> , public msm::front::explicit_entry<1>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState2b" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState2b" << std::endl;}
+ };
+ // test with a pseudo entry
+ struct PseudoEntry1 : public msm::front::entry_pseudo_state<0>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::PseudoEntry1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::PseudoEntry1" << std::endl;}
+ };
+ struct SubState3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState3" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState3" << std::endl;}
+ };
+ struct SubState3b : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::SubState3b" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::SubState3b" << std::endl;}
+ };
+ struct PseudoExit1 : public msm::front::exit_pseudo_state<event6>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: SubFsm2::PseudoExit1" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: SubFsm2::PseudoExit1" << std::endl;}
+ };
+ // action methods
+ void entry_action(event4 const&)
+ {
+ std::cout << "calling entry_action" << std::endl;
+ }
+ // the initial state. Must be defined
+ typedef mpl::vector<SubState1,SubState1b> initial_state;
+
+ typedef mpl::vector<SubState2b> explicit_creation;
+
+ // Transition table for SubFsm2
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +--------------+-------------+------------+------------------------+----------------------+
+ a_row < PseudoEntry1 , event4 , SubState3 ,&SubFsm2_::entry_action >,
+ _row < SubState2 , event6 , SubState1 >,
+ _row < SubState3 , event5 , PseudoExit1 >
+ // +--------------+-------------+------------+------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<SubFsm2_> SubFsm2;
+
+ // the initial state of the player SM. Must be defined
+ typedef State1 initial_state;
+
+ // transition actions
+ // guard conditions
+
+ // Transition table for Fsm
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------------------+--------+------------------------------------+-------+--------+
+ _row < State1 , event1 , SubFsm2 >,
+ _row < State1 , event2 , SubFsm2::direct<SubFsm2_::SubState2> >,
+ _row < State1 , event3 , mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
+ SubFsm2::direct<SubFsm2_::SubState2b> > >,
+ _row < State1 , event4 , SubFsm2::entry_pt
+ <SubFsm2_::PseudoEntry1> >,
+ // +---------------------+--------+------------------------------------+-------+--------+
+ _row < SubFsm2 , event1 , State1 >,
+ _row < SubFsm2::exit_pt
+ <SubFsm2_::PseudoExit1>, event6 , State2 >
+ // +---------------------+--------+------------------------------------+-------+--------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Fsm_> Fsm;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "State1", "SubFsm2","State2" };
+ void pstate(Fsm const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ Fsm p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "Simply move in and out of the composite, activate init states" << std::endl;
+ p.process_event(event1()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "Direct entry into SubFsm2::SubState2, then transition to SubState1 and back to State1" << std::endl;
+ p.process_event(event2()); pstate(p);
+ p.process_event(event6()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "processing fork to SubFsm2::SubState2 and SubFsm2::SubState2b" << std::endl;
+ p.process_event(event3()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "processing entry pseudo state" << std::endl;
+ p.process_event(event4()); pstate(p);
+ p.process_event(event1()); pstate(p);
+ std::cout << "processing entry + exit pseudo state" << std::endl;
+ p.process_event(event4()); pstate(p);
+ std::cout << "using exit pseudo state" << std::endl;
+ p.process_event(event5()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/EumlInternal.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/EumlInternal.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,144 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+using namespace boost::msm::front;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(internal_event)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+ BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ Open + open_close [internal_guard1] / internal_action1,
+ Open + open_close [internal_guard2] / internal_action2,
+ Open + internal_event / internal_action ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ std::cout << "sending internal event (not rejected)" << std::endl;
+ p.process_event(internal_event);
+ std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/EumlInternalDistributed.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/EumlInternalDistributed.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,208 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+using namespace boost::msm::front;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ // note that unlike the SimpleTutorial, events must derive from euml_event.
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(internal_event)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+
+ // we just declare a state type but do not create any instance as we want to inherit from this type
+ BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
+ // derive to be able to add an internal transition table
+ struct Open_impl : public Open_def
+ {
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ open_close [internal_guard1] / internal_action1 ,
+ open_close [internal_guard2] / internal_action2 ,
+ internal_event / internal_action
+ ))
+ };
+ // declare an instance for the stt as we are manually declaring a state
+ Open_impl const Open;
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+
+ // Playing is a state machine itself.
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1 // Init State
+ ),Playing_def)
+
+ // some action for the internal transition
+ BOOST_MSM_EUML_ACTION(playing_internal_action)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Playing::internal action" << endl;
+ }
+ };
+ // derive to be able to add an internal transition table
+ struct Playing_ : public Playing_def
+ {
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ internal_event / playing_internal_action
+ ))
+ };
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Stopped + play / start_playback == Playing ,
+ Stopped + open_close / open_drawer == Open ,
+ Stopped + stop == Stopped ,
+ // +------------------------------------------------------------------------------+
+ Open + open_close / close_drawer == Empty ,
+ // +------------------------------------------------------------------------------+
+ Empty + open_close / open_drawer == Open ,
+ Empty + cd_detected
+ [good_disk_format&&(event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play))
+ == Stopped ,
+ // +------------------------------------------------------------------------------+
+ Playing + stop / stop_playback == Stopped ,
+ Playing + pause / pause_playback == Paused ,
+ Playing + open_close / stop_and_open == Open ,
+ // +------------------------------------------------------------------------------+
+ Paused + end_pause / resume_playback == Playing ,
+ Paused + stop / stop_playback == Stopped ,
+ Paused + open_close / stop_and_open == Open
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ std::cout << "sending internal event (not rejected)" << std::endl;
+ p.process_event(internal_event);
+ std::cout << "sending open_close event. Conflict with internal transitions (rejecting event)" << std::endl;
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+ // at this point, Play is active
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+ // event handled internally in Playing, without region checking
+ std::cout << "sending internal event (not rejected)" << std::endl;
+ p.process_event(internal_event);
+
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/EumlSimple.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/EumlSimple.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,215 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+
+#include "stdafx.h"
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+#include <boost/msm/front/euml/stl.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front::euml;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(cd_detected)
+
+ BOOST_MSM_EUML_ACTION(start_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(open_drawer)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(close_drawer)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(store_cd_info)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& fsm ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(stop_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(pause_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(resume_playback)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(stop_and_open)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ BOOST_MSM_EUML_ACTION(stopped_again)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE((),Empty)
+ BOOST_MSM_EUML_STATE((),Open)
+ BOOST_MSM_EUML_STATE((),Stopped)
+ BOOST_MSM_EUML_STATE((),Playing)
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer ,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer ,
+ Open == Paused + open_close / stop_and_open ,
+ Open == Stopped + open_close / open_drawer ,
+ Open == Playing + open_close / stop_and_open ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback ,
+ Stopped == Paused + stop / stop_playback ,
+ Stopped == Empty + cd_detected / store_cd_info ,
+ Stopped == Stopped + stop / stopped_again
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_exception << no_msg_queue, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(open_close);
+ p2.process_event(open_close);
+ p2.process_event(cd_detected);
+ p2.process_event(play);
+ p2.process_event(pause);
+ // go back to Playing
+ p2.process_event(end_pause);
+ p2.process_event(pause);
+ p2.process_event(stop);
+ // event leading to the same state
+ p2.process_event(stop);
+ p2.process_event(open_close);
+ p2.process_event(open_close);
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/Flags.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/Flags.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,244 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+ p.process_event(play());
+
+ // at this point, Play is active
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/History.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/History.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,230 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ };
+ // back-end
+ // demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+ p.process_event(play());
+
+ // at this point, Play is active
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // as you see, remembers the original state as end_pause is an history trigger
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+ // play does not trigger shallow history => start back from 1st song
+ p.process_event(play()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/HistoryEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/HistoryEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,170 @@
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+ // The list of FSM states
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+
+
+ // Playing is now a state machine itself.
+
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,Song1_Exit ),Song1)
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ // VC9 cannot compile the typedef with build_sm if one is also used for player
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1 // Init State
+ ),Playing_)
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_,
+ msm::back::ShallowHistory<mpl::vector<BOOST_MSM_EUML_EVENT_NAME(end_pause)> > > Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ // as you see, remembers the original state as end_pause is an history trigger
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(play); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/MsmComposite.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/MsmComposite.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,236 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct cd_detected{};
+ struct NextSong {};
+ struct PreviousSong {};
+
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<> {};
+ struct Song2 : public msm::front::state<> {};
+ struct Song3 : public msm::front::state<> {};
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { /*std::cout << "Playing::start_next_song\n";*/ }
+ void start_prev_song(PreviousSong const&) { /*std::cout << "Playing::start_prev_song\n"; */}
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ void start_playback(play const&) { }
+ void open_drawer(open_close const&) { }
+ void close_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const& cd) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&) {}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ test_fsm::player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::cd_detected());
+ p2.process_event(test_fsm::play());
+ for (int j=0;j<100;++j)
+ {
+ p2.process_event(test_fsm::NextSong());
+ p2.process_event(test_fsm::NextSong());
+ p2.process_event(test_fsm::PreviousSong());
+ p2.process_event(test_fsm::PreviousSong());
+ }
+
+ p2.process_event(test_fsm::pause());
+ // go back to Playing
+ p2.process_event(test_fsm::end_pause());
+ p2.process_event(test_fsm::pause());
+ p2.process_event(test_fsm::stop());
+ // event leading to the same state
+ p2.process_event(test_fsm::stop());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/MsmSimple.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/MsmSimple.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,192 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct cd_detected{};
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Playing" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Playing" << std::endl;*/}
+ };
+
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+ // transition actions
+ void start_playback(play const&) { }
+ void open_drawer(open_close const&) { }
+ void close_drawer(open_close const&) { }
+ void store_cd_info(cd_detected const& cd) { }
+ void stop_playback(stop const&) { }
+ void pause_playback(pause const&) { }
+ void resume_playback(end_pause const&) { }
+ void stop_and_open(open_close const&) { }
+ void stopped_again(stop const&) {}
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Stopped , play , Playing >,
+ _row < Stopped , open_close , Open >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Open , open_close , Empty >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Empty , open_close , Open >,
+ _row < Empty , cd_detected , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Playing , stop , Stopped >,
+ _row < Playing , pause , Paused >,
+ _row < Playing , open_close , Open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ _row < Paused , end_pause , Playing >,
+ _row < Paused , stop , Stopped >,
+ _row < Paused , open_close , Open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ test_fsm::player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::cd_detected());
+ p2.process_event(test_fsm::play());
+ p2.process_event(test_fsm::pause());
+ // go back to Playing
+ p2.process_event(test_fsm::end_pause());
+ p2.process_event(test_fsm::pause());
+ p2.process_event(test_fsm::stop());
+ // event leading to the same state
+ p2.process_event(test_fsm::stop());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/MsmSimpleFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/MsmSimpleFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,244 @@
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct cd_detected{};
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Playing" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Playing" << std::endl;*/}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+ // transition actions
+ struct start_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct open_drawer
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct close_drawer
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct store_cd_info
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& fsm ,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stop_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct pause_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct resume_playback
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stop_and_open
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ struct stopped_again
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ }
+ };
+ // guard conditions
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Stopped , play , Playing , start_playback >,
+ Row < Stopped , open_close , Open , open_drawer >,
+ Row < Stopped , stop , Stopped , stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer >,
+ Row < Empty , cd_detected , Stopped , store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback >,
+ Row < Playing , pause , Paused , pause_playback >,
+ Row < Playing , open_close , Open , stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback >,
+ Row < Paused , stop , Stopped , stop_playback >,
+ Row < Paused , open_close , Open , stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+ test_fsm::player p2;
+ p2.start();
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::cd_detected());
+ p2.process_event(test_fsm::play());
+ p2.process_event(test_fsm::pause());
+ // go back to Playing
+ p2.process_event(test_fsm::end_pause());
+ p2.process_event(test_fsm::pause());
+ p2.process_event(test_fsm::stop());
+ // event leading to the same state
+ p2.process_event(test_fsm::stop());
+ p2.process_event(test_fsm::open_close());
+ p2.process_event(test_fsm::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/Orthogonal-deferred.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/Orthogonal-deferred.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,292 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // if the play event arrives in this state, defer it until a state handles it or
+ // rejects it
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ // if the play event arrives in this state, defer it until a state handles it or
+ // rejects it
+ typedef mpl::vector<play> deferred_events;
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ };
+ struct AllOk : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ // this state is also made terminal so that all the events are blocked
+ struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
+ public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
+ // the event end_error is generated
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
+
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+
+ // at this point, Play is active (was deferred)
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found()); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play());pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play());pstate(p);
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/Orthogonal-deferred2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/Orthogonal-deferred2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,293 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace boost::msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // we want deferred events and no state requires deferred events (only the fsm in the
+ // transition table), so the fsm does.
+ typedef int activate_deferred_events;
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ // the player state machine contains a state which is himself a state machine
+ // as you see, no need to declare it anywhere so Playing can be developed separately
+ // by another team in another module. For simplicity I just declare it inside player
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ };
+ struct AllOk : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ // this state is also made terminal so that all the events are blocked
+ struct ErrorMode : //public msm::front::terminate_state<> // ErrorMode terminates the state machine
+ public msm::front::interrupt_state<end_error> // ErroMode just interrupts. Will resume if
+ // the event end_error is generated
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+
+ // 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& cd) {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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+
+ // guard conditions
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ Row < Open , play , none , Defer , none >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ Row < Empty , play , none , Defer , none >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode" };
+
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ p.process_event(cd_detected("louie, louie"));
+
+ // at this point, Play is active (was deferred)
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(NextSong());pstate(p); //2nd song active
+ p.process_event(NextSong());pstate(p);//3rd song active
+ p.process_event(PreviousSong());pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // go back to Playing
+ // as you see, it starts back from the original state
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ p.process_event(stop()); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found()); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play());pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play());pstate(p);
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/OrthogonalDeferredEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/OrthogonalDeferredEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,253 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(end_error)
+ BOOST_MSM_EUML_EVENT(error_found)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+
+ // Flags. Allow information about a property of the current state
+ BOOST_MSM_EUML_FLAG(PlayingPaused)
+ BOOST_MSM_EUML_FLAG(CDLoaded)
+ BOOST_MSM_EUML_FLAG(FirstSongPlaying)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+
+ BOOST_MSM_EUML_STATE(( Empty_Entry,
+ Empty_Exit,
+ attributes_ << no_attributes_,
+ configure_ << play // defer play
+ ),
+ Empty)
+
+ BOOST_MSM_EUML_STATE(( Open_Entry,
+ Open_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded << play // defer play, flag state with CDLoaded
+ ),
+ Open)
+
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,
+ Stopped_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded // flag state with CDLoaded
+ ),
+ Stopped)
+
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE(( no_action,
+ no_action,
+ attributes_ << no_attributes_,
+ configure_<< PlayingPaused << CDLoaded // flag state with CDLoaded and PlayingPaused
+ ),
+ Paused)
+
+ BOOST_MSM_EUML_STATE(( AllOk_Entry,AllOk_Exit ),AllOk)
+
+ // a terminate state
+ //BOOST_MSM_EUML_TERMINATE_STATE(( ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+ // or as an interrupt state
+ BOOST_MSM_EUML_INTERRUPT_STATE(( end_error,ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+
+ // Playing is now a state machine itself.
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,
+ Song1_Exit,
+ attributes_ << no_attributes_,
+ configure_<< FirstSongPlaying ),Song1)
+
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1, // Init State
+ no_action, // entry
+ no_action, // exit
+ attributes_ << no_attributes_, //attributes
+ configure_<< PlayingPaused << CDLoaded //flags
+ ),Playing_)
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop,
+ ErrorMode == AllOk + error_found / report_error,
+ AllOk == ErrorMode+ end_error / report_end_error
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty<< AllOk, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing","AllOk","ErrorMode" };
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+ std::cout << "FirstSong active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() << std::endl;//=> true
+
+ // make transition happen inside it. Player has no idea about this event but it's ok.
+ p.process_event(next_song);pstate(p); //2nd song active
+ p.process_event(next_song);pstate(p);//3rd song active
+ p.process_event(previous_song);pstate(p);//2nd song active
+ std::cout << "FirstSong active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(FirstSongPlaying)>() << std::endl;//=> false
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded),player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play);pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error);pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play);pstate(p);
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/OrthogonalDeferredEuml2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/OrthogonalDeferredEuml2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,241 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+ BOOST_MSM_EUML_EVENT(next_song)
+ BOOST_MSM_EUML_EVENT(previous_song)
+ BOOST_MSM_EUML_EVENT(end_error)
+ BOOST_MSM_EUML_EVENT(error_found)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Flags. Allow information about a property of the current state
+ BOOST_MSM_EUML_FLAG(PlayingPaused)
+ BOOST_MSM_EUML_FLAG(CDLoaded)
+ BOOST_MSM_EUML_FLAG(FirstSongPlaying)
+
+ // Concrete FSM implementation
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( Empty_Entry,
+ Empty_Exit,
+ attributes_ << no_attributes_,
+ configure_ << no_configure_
+ ),
+ Empty)
+
+ BOOST_MSM_EUML_STATE(( Open_Entry,
+ Open_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded // flag state with CDLoaded
+ ),
+ Open)
+
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,
+ Stopped_Exit,
+ attributes_ << no_attributes_,
+ configure_<< CDLoaded // flag state with CDLoaded
+ ),
+ Stopped)
+
+ // state not defining any entry or exit
+ BOOST_MSM_EUML_STATE(( no_action,
+ no_action,
+ attributes_ << no_attributes_,
+ configure_<< PlayingPaused << CDLoaded // flag state with CDLoaded and PlayingPaused
+ ),
+ Paused)
+
+ BOOST_MSM_EUML_STATE(( AllOk_Entry,AllOk_Exit ),AllOk)
+
+ // a terminate state
+ //BOOST_MSM_EUML_TERMINATE_STATE(( ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+ // or as an interrupt state
+ BOOST_MSM_EUML_INTERRUPT_STATE(( end_error,ErrorMode_Entry,ErrorMode_Exit ),ErrorMode)
+
+ // Playing is now a state machine itself.
+
+ // It has 3 substates
+ BOOST_MSM_EUML_STATE(( Song1_Entry,
+ Song1_Exit,
+ attributes_ << no_attributes_,
+ configure_<< FirstSongPlaying ),Song1)
+
+ BOOST_MSM_EUML_STATE(( Song2_Entry,Song2_Exit ),Song2)
+ BOOST_MSM_EUML_STATE(( Song3_Entry,Song3_Exit ),Song3)
+
+
+ // Playing has a transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Song2 == Song1 + next_song / start_next_song,
+ Song1 == Song2 + previous_song / start_prev_song,
+ Song3 == Song2 + next_song / start_next_song,
+ Song2 == Song3 + previous_song / start_prev_song
+ // +------------------------------------------------------------------------------+
+ ),playing_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playing_transition_table, //STT
+ init_ << Song1, // Init State
+ no_action, // entry
+ no_action, // exit
+ attributes_ << no_attributes_, //attributes
+ configure_<< PlayingPaused << CDLoaded //flags
+ ),Playing_)
+
+ // choice of back-end
+ typedef msm::back::state_machine<Playing_> Playing_type;
+ Playing_type const Playing;
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback ,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / close_drawer,
+ // we now defer using the defer_ function. This will need deferred_events as config (see below)
+ Empty + play / defer_ ,
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer ,
+ Open == Paused + open_close / stop_and_open ,
+ Open == Stopped + open_close / open_drawer ,
+ Open == Playing + open_close / stop_and_open ,
+ // we now defer using the defer_ function. This will need deferred_events as config (see below)
+ Open + play / defer_ ,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback ,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback ,
+ Stopped == Paused + stop / stop_playback ,
+ Stopped == Empty + cd_detected [good_disk_format&&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop ,
+ ErrorMode == AllOk + error_found / report_error ,
+ AllOk == ErrorMode+ end_error / report_end_error
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty << AllOk, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << deferred_events, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing","AllOk","ErrorMode" };
+ void pstate(player const& p)
+ {
+ // we have now several active states, which we show
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ // tests some flags
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl; //=> false (no CD yet)
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> true
+
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(PlayingPaused)>() << std::endl;//=> false
+ std::cout << "CDLoaded active:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>() << std::endl;//=> true
+ // by default, the flags are OR'ed but you can also use AND. Then the flag must be present in
+ // all of the active states
+ std::cout << "CDLoaded active with AND:" << std::boolalpha
+ << p.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded),player::Flag_AND>() << std::endl;//=> false
+
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+
+ // event leading to a terminal/interrupt state
+ p.process_event(error_found); pstate(p);
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(play);pstate(p);
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error);pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(play);pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/ParsingDigits.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/ParsingDigits.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,471 @@
+// MsmSimple.cpp : Defines the entry point for the console application.
+//
+#define FUSION_MAX_VECTOR_SIZE 20
+
+#include <boost/msm/back/state_machine.hpp>
+#include "char_event_dispatcher.hpp"
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/timer.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+// events
+struct end_sub {template <class Event> end_sub(Event const&){}};
+struct other_char {};
+struct default_char {};
+struct eos {};
+
+
+namespace test_fsm // Concrete FSM implementation
+{
+ // Concrete FSM implementation
+ struct parsing_ : public msm::front::state_machine_def<parsing_>
+ {
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+
+ struct Waiting : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Waiting" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Waiting" << std::endl;}
+ };
+ struct Digit1 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit1" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit1" << std::endl;}
+ };
+ struct Digit2 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit2" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit2" << std::endl;}
+ };
+ struct Digit3 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit3" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit3" << std::endl;}
+ };
+ struct Digit4 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit4" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit4" << std::endl;}
+ };
+ struct MinusChar1 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar1" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar1" << std::endl;}
+ };
+ struct Digit5 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit5" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit5" << std::endl;}
+ };
+ struct Digit6 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit6" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit6" << std::endl;}
+ };
+ struct Digit7 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit7" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit7" << std::endl;}
+ };
+ struct Digit8 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit8" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit8" << std::endl;}
+ };
+ struct MinusChar2 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar2" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar2" << std::endl;}
+ };
+ struct Digit9 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit9" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit9" << std::endl;}
+ };
+ struct Digit10 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit10" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit10" << std::endl;}
+ };
+ struct Digit11 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit11" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit11" << std::endl;}
+ };
+ struct Digit12 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit12" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit12" << std::endl;}
+ };
+ struct MinusChar3 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: MinusChar3" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: MinusChar3" << std::endl;}
+ };
+ struct Digit13 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit13" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit13" << std::endl;}
+ };
+ struct Digit14 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit14" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit14" << std::endl;}
+ };
+ struct Digit15 : public msm::front::state<>
+ {
+ // optional entry/exit methods
+ //template <class Event,class FSM>
+ //void on_entry(Event const&,FSM& ) {std::cout << "entering: Digit15" << std::endl;}
+ //template <class Event,class FSM>
+ //void on_exit(Event const&,FSM& ) {std::cout << "leaving: Digit15" << std::endl;}
+ };
+ //struct Start : public msm::front::state<> {};
+ struct Parsed : public msm::front::state<> {};
+ //struct Failed : public msm::front::state<> {};
+
+ // the initial state of the player SM. Must be defined
+ typedef Waiting initial_state;
+ // transition actions
+ struct test_fct
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Parsed!" << std::endl;
+ }
+ };
+
+ // guard conditions
+
+
+ // Transition table for parsing_
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +-------------+-------------------+---------+---------------------+----------------------+
+ Row < Waiting , digit , Digit1 >,
+ Row < Digit1 , digit , Digit2 >,
+ Row < Digit2 , digit , Digit3 >,
+ Row < Digit3 , digit , Digit4 >,
+ Row < Digit4 , event_char<'-'> , MinusChar1 >,
+ Row < MinusChar1 , digit , Digit5 >,
+ Row < Digit5 , digit , Digit6 >,
+ Row < Digit6 , digit , Digit7 >,
+ Row < Digit7 , digit , Digit8 >,
+ Row < Digit8 , event_char<'-'> , MinusChar2 >,
+ Row < MinusChar2 , digit , Digit9 >,
+ Row < Digit9 , digit , Digit10 >,
+ Row < Digit10 , digit , Digit11 >,
+ Row < Digit11 , digit , Digit12 >,
+ Row < Digit12 , event_char<'-'> , MinusChar3 >,
+ Row < MinusChar3 , digit , Digit13 >,
+ Row < Digit13 , digit , Digit14 >,
+ Row < Digit14 , digit , Digit15 >,
+ Row < Digit15 , eos , Parsed >,
+ Row < Parsed , eos , Waiting >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<parsing_> parsing;
+}
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+// This declares the statically-initialized char_event_dispatcher instance.
+template <class Fsm>
+const msm::back::char_event_dispatcher<Fsm>
+msm::back::char_event_dispatcher<Fsm>::instance;
+
+struct Parser
+{
+ Parser():p(){p.start();}
+ void new_char(char c)
+ {
+ typedef msm::back::char_event_dispatcher<test_fsm::parsing> table;
+ table::instance.process_event(p,c);
+ }
+ void finish_string(){p.process_event(eos());}
+ void reinit(){p.process_event(eos());}
+ test_fsm::parsing p;
+};
+
+void msm_match(const char* input)
+{
+ test_fsm::parsing p;
+ p.start();
+
+ int j=0;
+ while(input[j])
+ //for (size_t j=0;j<len;++j)
+ {
+ switch (input[j])
+ {
+ case '0':
+ p.process_event(char_0());
+ break;
+ case '1':
+ p.process_event(char_1());
+ break;
+ case '2':
+ p.process_event(char_2());
+ break;
+ case '3':
+ p.process_event(char_3());
+ break;
+ case '4':
+ p.process_event(char_4());
+ break;
+ case '5':
+ p.process_event(char_5());
+ break;
+ case '6':
+ p.process_event(char_6());
+ break;
+ case '7':
+ p.process_event(char_7());
+ break;
+ case '8':
+ p.process_event(char_8());
+ break;
+ case '9':
+ p.process_event(char_9());
+ break;
+ case '-':
+ p.process_event(event_char<'-'>());
+ break;
+ default:
+ p.process_event(default_char());
+ break;
+ }
+ ++j;
+ }
+ p.process_event(eos());
+ p.process_event(eos());
+}
+
+double time_match(const char* text)
+{
+ boost::timer tim;
+ int iter = 1;
+ int counter, repeats;
+ double result = 0;
+ double run;
+ do
+ {
+ tim.restart();
+ for(counter = 0; counter < iter; ++counter)
+ {
+ msm_match( text);
+ }
+ result = tim.elapsed();
+ iter *= 2;
+ } while(result < 0.5);
+ iter /= 2;
+
+ // repeat test and report least value for consistency:
+ for(repeats = 0; repeats < 10; ++repeats)
+ {
+ tim.restart();
+ for(counter = 0; counter < iter; ++counter)
+ {
+ msm_match( text);
+ }
+ run = tim.elapsed();
+ result = (std::min)(run, result);
+ }
+ return result / iter;
+}
+int main()
+{
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ test_fsm::parsing p;
+ p.start();
+ const char* input = "1234-5678-1234-456";
+ size_t len = strlen(input);
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<1000;++i)
+ {
+ int j=0;
+ while(input[j])
+ //for (size_t j=0;j<len;++j)
+ {
+ switch (input[j])
+ {
+ case '0':
+ p.process_event(char_0());
+ break;
+ case '1':
+ p.process_event(char_1());
+ break;
+ case '2':
+ p.process_event(char_2());
+ break;
+ case '3':
+ p.process_event(char_3());
+ break;
+ case '4':
+ p.process_event(char_4());
+ break;
+ case '5':
+ p.process_event(char_5());
+ break;
+ case '6':
+ p.process_event(char_6());
+ break;
+ case '7':
+ p.process_event(char_7());
+ break;
+ case '8':
+ p.process_event(char_8());
+ break;
+ case '9':
+ p.process_event(char_9());
+ break;
+ case '-':
+ p.process_event(event_char<'-'>());
+ break;
+ default:
+ p.process_event(default_char());
+ break;
+ }
+ ++j;
+ }
+ p.process_event(eos());
+ p.process_event(eos());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm(1) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm(1) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+
+ Parser parse;
+ // for timing
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li);
+#else
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<1000;++i)
+ {
+ for (size_t j=0;j<len;++j)
+ {
+ parse.new_char(input[j]);
+ }
+ parse.finish_string();
+ parse.reinit();
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "msm(2) took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "msm(2) took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ std::cout << "msm(3) took in s:" << time_match(input) <<"\n" <<std::endl;
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/SC Composite.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SC Composite.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,197 @@
+#include <boost/statechart/event.hpp>
+#include <boost/statechart/state_machine.hpp>
+#include <boost/statechart/simple_state.hpp>
+#include <boost/statechart/transition.hpp>
+#include "boost/mpl/list.hpp"
+
+#include <vector>
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace sc = boost::statechart;
+namespace mpl = boost::mpl;
+
+namespace test_sc
+{
+
+ //events
+ struct play : sc::event< play > {};
+ struct end_pause : sc::event< end_pause > {};
+ struct stop : sc::event< stop > {};
+ struct pause : sc::event< pause > {};
+ struct open_close : sc::event< open_close > {};
+ struct cd_detected : sc::event< cd_detected > {};
+ struct NextSong: sc::event< NextSong > {};
+ struct PreviousSong : sc::event< PreviousSong >{};
+
+ struct Empty;
+ struct Open;
+ struct Stopped;
+ struct Playing;
+ struct Paused;
+ // SM
+ struct player : sc::state_machine< player, Empty >
+ {
+ void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ }
+ void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ }
+ void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ }
+ void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ }
+ void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/}
+ void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ }
+ void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */}
+ void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ }
+ void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ }
+ };
+
+ struct Empty : sc::simple_state< Empty, player >
+ {
+ Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry
+ ~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< cd_detected, Stopped,
+ player, &player::store_cd_info > > reactions;
+
+ };
+ struct Open : sc::simple_state< Open, player >
+ {
+ Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry
+ ~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit
+ typedef sc::transition< open_close, Empty,
+ player, &player::close_drawer > reactions;
+
+ };
+ struct Stopped : sc::simple_state< Stopped, player >
+ {
+ Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry
+ ~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< play, Playing,
+ player, &player::start_playback >,
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< stop, Stopped,
+ player, &player::stopped_again > > reactions;
+
+ };
+ struct Song1;
+ struct Playing : sc::simple_state< Playing, player,Song1 >
+ {
+ Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry
+ ~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< pause, Paused,
+ player, &player::pause_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ void start_next_song(NextSong const&) { /*std::cout << "Playing::start_next_song\n";*/ }
+ void start_prev_song(PreviousSong const&) { /*std::cout << "Playing::start_prev_song\n";*/ }
+ };
+ struct Song2;
+ struct Song1 : sc::simple_state< Song1, Playing >
+ {
+ Song1() { /*std::cout << "entering Song1" << std::endl;*/ } // entry
+ ~Song1() { /*std::cout << "leaving Song1" << std::endl;*/ } // exit
+ typedef sc::transition< NextSong, Song2,
+ Playing, &Playing::start_next_song > reactions;
+ };
+ struct Song3;
+ struct Song2 : sc::simple_state< Song2, Playing >
+ {
+ Song2() { /*std::cout << "entering Song2" << std::endl;*/ } // entry
+ ~Song2() { /*std::cout << "leaving Song2" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< NextSong, Song3,
+ Playing, &Playing::start_next_song >,
+ sc::transition< PreviousSong, Song1,
+ Playing, &Playing::start_prev_song > > reactions;
+ };
+ struct Song3 : sc::simple_state< Song3, Playing >
+ {
+ Song3() { /*std::cout << "entering Song3" << std::endl;*/ } // entry
+ ~Song3() { /*std::cout << "leaving Song3" << std::endl;*/ } // exit
+ typedef sc::transition< PreviousSong, Song2,
+ Playing, &Playing::start_prev_song > reactions;
+ };
+ struct Paused : sc::simple_state< Paused, player >
+ {
+ Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry
+ ~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< end_pause, Playing,
+ player, &player::resume_playback >,
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ };
+}
+
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+int main()
+{
+ test_sc::player p;
+ p.initiate();
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+ ::QueryPerformanceCounter(&li);
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+
+ for (int i=0;i<100;++i)
+ {
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::cd_detected());
+ p.process_event(test_sc::play());
+ for (int j=0;j<100;++j)
+ {
+ p.process_event(test_sc::NextSong());
+ p.process_event(test_sc::NextSong());
+ p.process_event(test_sc::PreviousSong());
+ p.process_event(test_sc::PreviousSong());
+ }
+
+ p.process_event(test_sc::pause());
+ // go back to Playing
+ p.process_event(test_sc::end_pause());
+ p.process_event(test_sc::pause());
+ p.process_event(test_sc::stop());
+ // event leading to the same state
+ p.process_event(test_sc::stop());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/SC Simple.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SC Simple.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,159 @@
+#include <boost/statechart/event.hpp>
+#include <boost/statechart/state_machine.hpp>
+#include <boost/statechart/simple_state.hpp>
+#include <boost/statechart/transition.hpp>
+#include "boost/mpl/list.hpp"
+
+#include <vector>
+
+#include <iostream>
+#ifdef WIN32
+#include "windows.h"
+#else
+#include <sys/time.h>
+#endif
+
+namespace sc = boost::statechart;
+namespace mpl = boost::mpl;
+
+namespace test_sc
+{
+
+ //events
+ struct play : sc::event< play > {};
+ struct end_pause : sc::event< end_pause > {};
+ struct stop : sc::event< stop > {};
+ struct pause : sc::event< pause > {};
+ struct open_close : sc::event< open_close > {};
+ struct cd_detected : sc::event< cd_detected > {};
+
+
+ struct Empty;
+ struct Open;
+ struct Stopped;
+ struct Playing;
+ struct Paused;
+ // SM
+ struct player : sc::state_machine< player, Empty >
+ {
+ void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ }
+ void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ }
+ void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ }
+ void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ }
+ void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/}
+ void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ }
+ void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */}
+ void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ }
+ void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ }
+ };
+
+ struct Empty : sc::simple_state< Empty, player >
+ {
+ Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry
+ ~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< cd_detected, Stopped,
+ player, &player::store_cd_info > > reactions;
+
+ };
+ struct Open : sc::simple_state< Open, player >
+ {
+ Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry
+ ~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit
+ typedef sc::transition< open_close, Empty,
+ player, &player::close_drawer > reactions;
+
+ };
+ struct Stopped : sc::simple_state< Stopped, player >
+ {
+ Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry
+ ~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< play, Playing,
+ player, &player::start_playback >,
+ sc::transition< open_close, Open,
+ player, &player::open_drawer >,
+ sc::transition< stop, Stopped,
+ player, &player::stopped_again > > reactions;
+
+ };
+ struct Playing : sc::simple_state< Playing, player >
+ {
+ Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry
+ ~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< pause, Paused,
+ player, &player::pause_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ };
+ struct Paused : sc::simple_state< Paused, player >
+ {
+ Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry
+ ~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit
+ typedef mpl::list<
+ sc::transition< end_pause, Playing,
+ player, &player::resume_playback >,
+ sc::transition< stop, Stopped,
+ player, &player::stop_playback >,
+ sc::transition< open_close, Open,
+ player, &player::stop_and_open > > reactions;
+ };
+}
+
+
+#ifndef WIN32
+long mtime(struct timeval& tv1,struct timeval& tv2)
+{
+ return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec));
+}
+#endif
+
+
+int main()
+{
+ test_sc::player p;
+ p.initiate();
+ // for timing
+#ifdef WIN32
+ LARGE_INTEGER res;
+ ::QueryPerformanceFrequency(&res);
+ LARGE_INTEGER li,li2;
+ ::QueryPerformanceCounter(&li);
+#else
+ struct timeval tv1,tv2;
+ gettimeofday(&tv1,NULL);
+#endif
+ for (int i=0;i<100;++i)
+ {
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::cd_detected());
+ p.process_event(test_sc::play());
+ p.process_event(test_sc::pause());
+ // go back to Playing
+ p.process_event(test_sc::end_pause());
+ p.process_event(test_sc::pause());
+ p.process_event(test_sc::stop());
+ // event leading to the same state
+ p.process_event(test_sc::stop());
+ p.process_event(test_sc::open_close());
+ p.process_event(test_sc::open_close());
+ }
+#ifdef WIN32
+ ::QueryPerformanceCounter(&li2);
+#else
+ gettimeofday(&tv2,NULL);
+#endif
+#ifdef WIN32
+ std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl;
+#else
+ std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl;
+#endif
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/SM-2Arg.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SM-2Arg.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,459 @@
+#include <iostream>
+#include <string>
+#include "boost/mpl/vector/vector30.hpp"
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/back/tools.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct ThreeSec {};
+ struct TenSec {};
+ struct go_sleep {};
+ struct error_found {};
+ struct end_error {};
+
+ // Flags. Allow information about a property of the current state
+ struct PlayingPaused{};
+ struct CDLoaded {};
+ struct FirstSongPlaying {};
+
+ // A "complicated" event type that carries some data.
+ struct cd_detected
+ {
+ cd_detected(std::string name)
+ : name(name)
+ {}
+
+ std::string name;
+ };
+ // an easy visitor
+ struct SomeVisitor
+ {
+ template <class T>
+ void visit_state(T* astate,int i)
+ {
+ std::cout << "visiting state:" << typeid(*astate).name()
+ << " with data:" << i << std::endl;
+ }
+ };
+ // overwrite of the base state (not default)
+ struct my_visitable_state
+ {
+ // signature of the accept function
+ typedef msm::back::args<void,SomeVisitor&,int> accept_sig;
+
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept(SomeVisitor&,int) const {}
+ };
+
+ // Concrete FSM implementation
+ struct player_ : public msm::front::state_machine_def<player_,my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: player" << std::endl;}
+ // The list of FSM states
+ struct Empty : public msm::front::state<my_visitable_state>
+ {
+ typedef mpl::vector<play> deferred_events;
+ // every (optional) entry/exit methods get the event packed as boost::any. Not useful very often.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ vis.visit_state(this,i);
+ }
+ };
+ struct Open : public msm::front::state<my_visitable_state>
+ {
+ typedef mpl::vector1<CDLoaded> flag_list;
+ typedef mpl::vector<play> deferred_events;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ vis.visit_state(this,i);
+ }
+ };
+ // a state needing a pointer to the containing state machine
+ // and using for this the non-default policy
+ // if policy used, set_sm_ptr is needed
+ struct Stopped : public msm::front::state<my_visitable_state>
+ {
+ // when stopped, the CD is loaded
+ typedef mpl::vector1<CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+ // the player state machine contains a state which is himself a state machine
+ // it demonstrates Shallow History: if the state gets activated with end_pause
+ // then it will remember the last active state and reactivate it
+ // also possible: AlwaysHistory, the last active state will always be reactivated
+ // or NoHistory, always restart from the initial state
+ struct Playing_ : public msm::front::state_machine_def<Playing_,my_visitable_state >
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ // note that visiting will recursively visit sub-states
+ vis.visit_state(this,i);
+ }
+ // The list of FSM states
+ // the Playing state machine contains a state which is himself a state machine
+ // so we have a SM containing a SM containing a SM
+ struct Song1_ : public msm::front::state_machine_def<Song1_,my_visitable_state>
+ {
+ typedef mpl::vector1<FirstSongPlaying> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+ void accept(SomeVisitor& vis,int i) const
+ {
+ vis.visit_state(this,i);
+ }
+ struct LightOn : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOn" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOn" << std::endl;}
+ };
+ struct LightOff : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: LightOff" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: LightOff" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef LightOn initial_state;
+ // transition actions
+ void turn_light_off(ThreeSec const&) { std::cout << "3s off::turn light off\n"; }
+ // guard conditions
+
+ typedef Song1_ s; // makes transition table cleaner
+ // Transition table for Song1
+ struct transition_table : mpl::vector1<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < LightOn , ThreeSec , LightOff, &s::turn_light_off >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Song1_> Song1;
+
+ struct Song2 : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&) { std::cout << "Playing::start_next_song\n"; }
+ void start_prev_song(PreviousSong const&) { std::cout << "Playing::start_prev_song\n"; }
+ // guard conditions
+
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong, Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong, Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Playing_,msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;
+
+ // the player state machine contains a state which is himself a state machine (2 of them, Playing and Paused)
+ struct Paused_ : public msm::front::state_machine_def<Paused_,my_visitable_state>
+ {
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Paused" << std::endl;}
+
+ // The list of FSM states
+ struct StartBlinking : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: StartBlinking" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: StartBlinking" << std::endl;}
+ };
+ struct StopBlinking : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: StopBlinking" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: StopBlinking" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef StartBlinking initial_state;
+ // transition actions
+ void start_blinking(TenSec const&) { std::cout << "Paused::start_blinking\n"; }
+ void stop_blinking(TenSec const&) { std::cout << "Paused::stop_blinking\n"; }
+ // guard conditions
+
+ typedef Paused_ pa; // makes transition table cleaner
+ // Transition table
+ struct transition_table : mpl::vector2<
+ // Start Event Next Action Guard
+ // +---------------+-------------+--------------+---------------------+----------------------+
+ a_row < StartBlinking , TenSec , StopBlinking , &pa::stop_blinking >,
+ a_row < StopBlinking , TenSec , StartBlinking , &pa::start_blinking >
+ // +---------------+-------------+---------------+--------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ typedef msm::back::state_machine<Paused_> Paused;
+
+ struct SleepMode : public msm::front::state<my_visitable_state>
+ {
+ }; // dummy state just to test the automatic id generation
+
+ struct AllOk : public msm::front::state<my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: AllOk" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: AllOk" << std::endl;}
+ };
+ struct ErrorMode : //public terminate_state<>
+ public msm::front::interrupt_state<end_error,my_visitable_state>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: ErrorMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: ErrorMode" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector<Empty,AllOk> initial_state;
+ //typedef Empty initial_state; // this is to have only one active state
+
+ // 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";
+ // generate another event to test the queue
+ //process_event(play());
+ }
+ 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ void start_sleep(go_sleep const&) { }
+ void report_error(error_found const&) {std::cout << "player::report_error\n";}
+ void report_end_error(end_error const&) {std::cout << "player::report_end_error\n";}
+ // guard conditions
+
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ a_row < Stopped , stop , Stopped , &p::stopped_again >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ a_row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >,
+ a_row < Paused , go_sleep ,SleepMode, &p::start_sleep >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < AllOk , error_found ,ErrorMode, &p::report_error >,
+ a_row <ErrorMode,end_error ,AllOk , &p::report_end_error >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+
+ // back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+
+ void pstate(player const& p)
+ {
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused","AllOk","ErrorMode","SleepMode" };
+ for (unsigned int i=0;i<player::nr_regions::value;++i)
+ {
+ std::cout << " -> " << state_names[p.current_state()[i]] << std::endl;
+ }
+ }
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl; //=> false (no CD yet)
+
+ // test deferred event
+ // deferred in Empty and Open, will be handled only after event cd_detected
+ p.process_event(play());
+
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ // visiting Paused and AllOk, but only Paused cares
+ SomeVisitor vis;
+ p.visit_current_states(boost::ref(vis),1);
+ p.process_event(open_close()); pstate(p);
+ // visiting Empty and AllOk, but only Empty cares
+ p.visit_current_states(boost::ref(vis),2);
+
+
+ p.process_event(cd_detected("louie, louie"));
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+ // at this point, Play is active, along FirstSong and LightOn
+ pstate(p);
+ // visiting Playing+Song1 and AllOk, but only Playing+Song1 care
+ p.visit_current_states(boost::ref(vis),3);
+
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // call on_exit on LightOn,FirstSong,Play like stated in the UML spec.
+ // and of course on_entry on Paused and StartBlinking
+ p.process_event(pause()); pstate(p);
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> true
+ // forward events to Paused
+ p.process_event(TenSec());
+ p.process_event(TenSec());
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl; //=> true
+ p.process_event(ThreeSec()); pstate(p);
+ p.process_event(NextSong());pstate(p);
+ // We are now in second song, Flag inactive
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ // visiting Playing+Song2 and AllOk, but only Playing cares
+ p.visit_current_states(boost::ref(vis),4);
+
+ p.process_event(NextSong());pstate(p);
+ // 2nd song active
+ p.process_event(PreviousSong());pstate(p);
+ // Pause
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ // but end_pause is an event activating the History
+ // => keep the last active State (SecondSong)
+ p.process_event(end_pause()); pstate(p);
+ // test of an event from a state to itself. According to UML spec, call again exit/entry from Stopped
+ p.process_event(stop()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ std::cout << "CDLoaded active:" << std::boolalpha << p.is_flag_active<CDLoaded>() << std::endl;//=> true
+ std::cout << "PlayingPaused active:" << std::boolalpha << p.is_flag_active<PlayingPaused>() << std::endl;//=> false
+ std::cout << "FirstSong active:" << std::boolalpha << p.is_flag_active<FirstSongPlaying>() << std::endl;//=> false
+ std::cout << "CDLoaded active with AND:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_AND>() << std::endl;//=> false
+ std::cout << "CDLoaded active with OR:" << std::boolalpha << p.is_flag_active<CDLoaded,player::Flag_OR>() << std::endl;//=> true
+
+ // go back to Playing
+ // but play is not leading to Shallow History => do not remember the last active State (SecondSong)
+ // and activate again FirstSong and LightOn
+ p.process_event(play()); pstate(p);
+ p.process_event(error_found()); pstate(p);
+
+ // try generating more events
+ std::cout << "Trying to generate another event" << std::endl; // will not work, fsm is terminated or interrupted
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Trying to end the error" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(end_error());pstate(p);
+ std::cout << "Trying to generate another event" << std::endl; // will work only if ErrorMode is interrupt state
+ p.process_event(NextSong());pstate(p);
+
+ std::cout << "Simulate error. Event play is not valid" << std::endl;
+ p.process_event(play()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
+
Added: trunk/libs/msm/doc/PDF/examples/SimpleTimer.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTimer.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,149 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// how long the timer will ring when countdown elapsed.
+#define RINGING_TIME 5
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_timer)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_timer ), start_timer_attr)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(start_timer,start_timer_attr)
+
+ BOOST_MSM_EUML_EVENT(stop_timer)
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_tick)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_tick ), tick_attr)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(tick,tick_attr)
+
+ BOOST_MSM_EUML_EVENT(start_ringing)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_ACTION(Stopped_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Stopped" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_STATE(( Stopped_Entry ),Stopped)
+
+ BOOST_MSM_EUML_ACTION(Started_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Started" << std::endl;
+ }
+ };
+
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_counter)
+ BOOST_MSM_EUML_STATE(( Started_Entry,
+ no_action,
+ attributes_ << m_counter
+ ),
+ Started)
+
+ BOOST_MSM_EUML_ACTION(Ringing_Entry)
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Ringing" << std::endl;
+ }
+ };
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_ringing_cpt)
+ BOOST_MSM_EUML_STATE(( Ringing_Entry,
+ no_action,
+ attributes_ << m_ringing_cpt
+ ),
+ Ringing)
+
+ // external function
+ void do_ring(int ringing_time) {std::cout << "ringing " << ringing_time << " s" << std::endl;}
+ // create functor and eUML function
+ BOOST_MSM_EUML_FUNCTION(Ring_ , do_ring , ring_ , void , void )
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ // When we start the countdown, the countdown value is not hardcoded but contained in the start_timer event.
+ // We copy this value into Started
+ Started == Stopped + start_timer /(target_(m_counter)= event_(m_timer)) ,
+ Stopped == Started + stop_timer ,
+ // internal transition
+ Started + tick
+ // we here use the message queue to move to Started when the countdown is finished
+ // to do this we put start_ringing into the message queue
+ / if_then_( (source_(m_counter) -= event_(m_tick) ) <= Int_<0>(),
+ process_(start_ringing) ) ,
+ // when we start ringing, we give to the state its hard-coded ringing time.
+ Ringing == Started + start_ringing
+ / (target_(m_ringing_cpt) = Int_<RINGING_TIME>(),
+ // call the external do_ring function
+ ring_(Int_<RINGING_TIME>())) ,
+ // to change a bit, we now do not use the message queue but a transition conflict to solve the same problem.
+ // When tick is fired, we have an internal transition Ringing -> Ringing, as long as Counter > 0
+ Ringing + tick [ source_(m_ringing_cpt) - event_(m_tick) > Int_<0>() ]
+ /(target_(m_ringing_cpt) -= event_(m_tick) ) ,
+ // And we move to Stopped when the counter is 0
+ Stopped == Ringing + tick[source_(m_ringing_cpt)-event_(m_tick) <= Int_<0>()] ,
+ // we let the user manually stop the ringing by pressing any button
+ Stopped == Ringing + stop_timer ,
+ Stopped == Ringing + start_timer
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Stopped // Init State
+ ),
+ SimpleTimer_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<SimpleTimer_> SimpleTimer;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Started","Ringing" };
+ void pstate(SimpleTimer const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ SimpleTimer p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+
+ p.process_event(start_timer(5));pstate(p); //timer set to 5 ticks
+ p.process_event(tick(2));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ // we are now ringing, let it ring a bit
+ p.process_event(tick(2));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ p.process_event(tick(1));pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleTutorial.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTutorial.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,190 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // used to show a transition conflict. This guard will simply deactivate one transition and thus
+ // solve the conflict
+ bool auto_start(cd_detected const&)
+ {
+ return false;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ row < Empty , cd_detected , Playing , &p::store_cd_info ,&p::auto_start >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleTutorial2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTutorial2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,203 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/row2.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ void open_drawer(open_close const&) { std::cout << "Empty::open_drawer\n"; }
+ // actions for Empty's internal transitions
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ void close_drawer(open_close const&) { std::cout << "Open::close_drawer\n"; }
+ void stop_and_open(open_close const&) { std::cout << "Open::stop_and_open\n"; }
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ void start_playback(play const&) { std::cout << "Stopped::start_playback\n"; }
+ void stop_playback(stop const&) { std::cout << "Stopped::stop_playback\n"; }
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ // guard conditions
+ // used to show a transition conflict. This guard will simply deactivate one transition and thus
+ // solve the conflict
+ bool auto_start(cd_detected const&)
+ {
+ return false;
+ }
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ void pause_playback(pause const&) { std::cout << "Paused::pause_playback\n"; }
+ void resume_playback(end_pause const&) { std::cout << "Paused::resume_playback\n"; }
+ };
+
+ // action
+ void store_cd_info(cd_detected const&) { std::cout << "Player::store_cd_info\n"; }
+
+ // guard
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action/Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Stopped , play , Playing , Stopped , &Stopped::start_playback >,
+ a_row2 < Stopped , open_close , Open , Empty , &Empty::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Open , open_close , Empty , Open , &Open::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Empty , open_close , Open , Empty ,&Empty::open_drawer >,
+ row2 < Empty , cd_detected , Stopped , player_ ,&player_::store_cd_info
+ , player_ ,&player_::good_disk_format >,
+ row2 < Empty , cd_detected , Playing , player_ ,&player_::store_cd_info
+ , Playing ,&Playing::auto_start >,
+ // conflict with some internal rows
+ irow2 < Empty , cd_detected , Empty ,&Empty::internal_action
+ , Empty ,&Empty::internal_guard >,
+ g_irow2 < Empty , cd_detected , Empty ,&Empty::internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Playing , stop , Stopped , Stopped ,&Stopped::stop_playback >,
+ a_row2 < Playing , pause , Paused , Paused ,&Paused::pause_playback >,
+ a_row2 < Playing , open_close , Open , Open ,&Open::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row2 < Paused , end_pause , Playing , Paused ,&Paused::resume_playback >,
+ a_row2 < Paused , stop , Stopped , Stopped ,&Stopped::stop_playback >,
+ a_row2 < Paused , open_close , Open , Open ,&Open::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleTutorialEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTutorialEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,168 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+ // The list of FSM states
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+
+ // it is also possible to define a state which you can implement normally
+ // just make it a state, as usual, and also a grammar terminal, euml_state
+ struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
+ {
+ // this allows us to add some functions
+ void activate_empty() {std::cout << "switching to Empty " << std::endl;}
+ // standard entry behavior
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& fsm)
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const& evt,FSM& fsm)
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+ };
+ //instance for use in the transition table
+ Empty_impl const Empty;
+
+ // create a functor and a eUML function for the activate_empty method from Entry
+ BOOST_MSM_EUML_METHOD(ActivateEmpty_ , activate_empty , activate_empty_ , void , void )
+
+ // define more states
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+ BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
+
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Playing == Stopped + play / start_playback ,
+ Playing == Paused + end_pause / resume_playback,
+ // +------------------------------------------------------------------------------+
+ Empty == Open + open_close / (close_drawer,activate_empty_(target_)),
+ // +------------------------------------------------------------------------------+
+ Open == Empty + open_close / open_drawer,
+ Open == Paused + open_close / stop_and_open,
+ Open == Stopped + open_close / open_drawer,
+ Open == Playing + open_close / stop_and_open,
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + pause / pause_playback,
+ // +------------------------------------------------------------------------------+
+ Stopped == Playing + stop / stop_playback,
+ Stopped == Paused + stop / stop_playback,
+ Stopped == Empty + cd_detected [good_disk_format &&
+ (event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)),
+ Stopped == Stopped + stop
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // or simply, if no no_transition handler needed:
+ //BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ // Empty // Init State
+ // ),player_)
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Paused", "Open", "Empty", "Playing" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // note that we write open_close and not open_close(), like usual. Both are possible with eUML, but
+ // you now have less to type.
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleTutorialEuml2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTutorialEuml2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,139 @@
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// entry/exit/action/guard logging functors
+#include "logging_functors.h"
+
+namespace // Concrete FSM implementation
+{
+ // events
+ // note that unlike the SimpleTutorial, events must derive from euml_event.
+ BOOST_MSM_EUML_EVENT(play)
+ BOOST_MSM_EUML_EVENT(end_pause)
+ BOOST_MSM_EUML_EVENT(stop)
+ BOOST_MSM_EUML_EVENT(pause)
+ BOOST_MSM_EUML_EVENT(open_close)
+
+ // A "complicated" event type that carries some data.
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ), cd_detected_attributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+
+ // state not needing any entry or exit
+ BOOST_MSM_EUML_STATE((),Paused)
+ BOOST_MSM_EUML_STATE(( Empty_Entry,Empty_Exit ),Empty)
+ BOOST_MSM_EUML_STATE(( Open_Entry,Open_Exit ),Open)
+ BOOST_MSM_EUML_STATE(( Stopped_Entry,Stopped_Exit ),Stopped)
+ BOOST_MSM_EUML_STATE(( Playing_Entry,Playing_Exit ),Playing)
+
+ // guard conditions
+ BOOST_MSM_EUML_ACTION(good_disk_format)
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.get_attribute(cd_type)!=DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ // just for logging, does not block any transition
+ return true;
+ }
+ std::cout << "good disk" << std::endl;
+ return true;
+ }
+ };
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ Stopped + play / start_playback == Playing ,
+ Stopped + open_close / open_drawer == Open ,
+ Stopped + stop == Stopped,
+ // +------------------------------------------------------------------------------+
+ Open + open_close / close_drawer == Empty ,
+ // +------------------------------------------------------------------------------+
+ Empty + open_close / open_drawer == Open ,
+ Empty + cd_detected
+ [good_disk_format &&(event_(cd_type)==Int_<DISK_CD>())]
+ / (store_cd_info,process_(play)) == Stopped ,
+ // +------------------------------------------------------------------------------+
+ Playing + stop / stop_playback == Stopped ,
+ Playing + pause / pause_playback == Paused ,
+ Playing + open_close / stop_and_open == Open ,
+ // +------------------------------------------------------------------------------+
+ Paused + end_pause / resume_playback == Playing ,
+ Paused + stop / stop_playback == Stopped ,
+ Paused + open_close / stop_and_open == Open
+ // +------------------------------------------------------------------------------+
+ ),transition_table)
+
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Empty, // Init State
+ no_action, // Entry
+ no_action, // Exit
+ attributes_ << no_attributes_, // Attributes
+ configure_ << no_configure_, // configuration
+ Log_No_Transition // no_transition handler
+ ),
+ player_) //fsm name
+
+ // choice of back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close); pstate(p);
+ p.process_event(open_close); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play as the previous event does it in its action method
+ //p.process_event(play);
+
+ // at this point, Play is active
+ p.process_event(pause); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause); pstate(p);
+ p.process_event(pause); pstate(p);
+ p.process_event(stop); pstate(p);
+ // event leading to the same state
+ // no action method called as none is defined in the transition table
+ p.process_event(stop); pstate(p);
+ // test call to no_transition
+ p.process_event(pause); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternal.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternal.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,216 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+ struct to_ignore {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // transitions internal to Empty
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard functor\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal action functor" << std::endl;
+ }
+ };
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
+ _irow < Empty , to_ignore >,
+ g_irow < Empty , cd_detected ,&p::internal_guard >,
+ Row < Empty , cd_detected , none , internal_action_fct ,internal_guard_fct >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // this event will be ignored and not call no_transition
+ p.process_event(to_ignore());
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternal2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternal2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,221 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+
+namespace msm = boost::msm;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // actions for Empty's internal transitions
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard functor\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal action functor" << std::endl;
+ }
+ };
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Internal < cd_detected , internal_action_fct ,internal_guard_fct >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ // sm_ptr still supported but deprecated as functors are a much better way to do the same thing
+ struct Stopped : public msm::front::state<msm::front::default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ void set_sm_ptr(player_* pl)
+ {
+ m_player=pl;
+ }
+ player_* m_player;
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ // conflict between a normal and 2 internal transitions (irow/g_irow)
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
+ g_irow < Empty , cd_detected ,&p::internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ typedef int no_message_queue;
+
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternalFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleTutorialInternalFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,315 @@
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+using namespace msm::front;
+namespace mpl = boost::mpl;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal_transition_table guard\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal_transition_table action" << std::endl;
+ }
+ };
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Internal < cd_detected , internal_action_fct ,internal_guard_fct >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ struct internal_guard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ };
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // internal transition inside the stt: none as Target
+ Row < Empty , cd_detected , none , none , internal_guard >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous transition does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,294 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ // when stopped, the CD is loaded
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+ };
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ // we want to define one row with the classic look.
+ bool auto_start(cd_detected const& evt)
+ {
+ return false;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // we here also mix with some "classical row"
+ g_row < Empty , cd_detected , Playing , &p::auto_start >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors2.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,310 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+// for func_state and func_state_machine
+#include <boost/msm/front/euml/state_grammar.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // The list of FSM states
+ // entry and exit functors for Empty
+ struct Empty_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+ };
+ struct Empty_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+ };
+ // definition of Empty
+ struct Empty_tag {};
+ typedef msm::front::euml::func_state<Empty_tag,Empty_Entry,Empty_Exit> Empty;
+
+ struct Open_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Open" << std::endl;
+ }
+ };
+ struct Open_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Open" << std::endl;
+ }
+ };
+ struct Open_tag {};
+ typedef msm::front::euml::func_state<Open_tag,Open_Entry,Open_Exit> Open;
+
+ // states without entry/exit actions (can be declared as functor state, just without functors ;-) )
+ struct Stopped_tag {};
+ typedef msm::front::euml::func_state<Stopped_tag> Stopped;
+
+ struct Playing_tag {};
+ typedef msm::front::euml::func_state<Playing_tag> Playing;
+
+ // state not defining any entry or exit (declared as simple state. Equivalent)
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+ // we want to define one row with the classic look.
+ bool auto_start(cd_detected const& evt)
+ {
+ return false;
+ }
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // we here also mix with some "classical row"
+ g_row < Empty , cd_detected , Playing , &p::auto_start >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors3.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/SimpleWithFunctors3.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,297 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+// for And_ operator
+#include <boost/msm/front/euml/operator.hpp>
+// for func_state and func_state_machine
+#include <boost/msm/front/euml/state_grammar.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+// for And_ operator
+using namespace msm::front::euml;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct open_close {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+
+ // The list of FSM states
+ // entry and exit functors for Empty
+ struct Empty_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+ };
+ struct Empty_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+ };
+ // definition of Empty
+ struct Empty_tag {};
+ typedef msm::front::euml::func_state<Empty_tag,Empty_Entry,Empty_Exit> Empty;
+
+ struct Open_Entry
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Open" << std::endl;
+ }
+ };
+ struct Open_Exit
+ {
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Open" << std::endl;
+ }
+ };
+ struct Open_tag {};
+ typedef msm::front::euml::func_state<Open_tag,Open_Entry,Open_Exit> Open;
+
+ // states without entry/exit actions (can be declared as functor state, just without functors ;-) )
+ struct Stopped_tag {};
+ typedef msm::front::euml::func_state<Stopped_tag> Stopped;
+
+ struct Playing_tag {};
+ typedef msm::front::euml::func_state<Playing_tag> Playing;
+
+ // state not defining any entry or exit (declared as simple state. Equivalent)
+ struct Paused_tag {};
+ typedef msm::front::euml::func_state<Paused_tag> Paused;
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ // transition actions
+ // as the functors are generic on events, fsm and source/target state,
+ // you can reuse them in another machine if you wish
+ struct TestFct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM&,SourceState& ,TargetState& )
+ {
+ cout << "transition with event:" << typeid(EVT).name() << endl;
+ }
+ };
+ struct start_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+ };
+ struct open_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+ };
+ struct close_drawer
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+ };
+ struct store_cd_info
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const&,FSM& fsm ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+ };
+ struct stop_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+ };
+ struct pause_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+ };
+ struct resume_playback
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+ };
+ struct stop_and_open
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+ };
+ struct stopped_again
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+ };
+ // guard conditions
+ struct DummyGuard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt,FSM& fsm,SourceState& src,TargetState& tgt)
+ {
+ return true;
+ }
+ };
+ struct good_disk_format
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ };
+ struct always_true
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ return true;
+ }
+ };
+
+ // Transition table for player
+ struct player_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Stopped , play , Playing , ActionSequence_
+ <mpl::vector<
+ TestFct,start_playback> >
+ , DummyGuard >,
+ Row < Stopped , open_close , Open , open_drawer , none >,
+ Row < Stopped , stop , Stopped , none , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Open , open_close , Empty , close_drawer , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Empty , open_close , Open , open_drawer , none >,
+ Row < Empty , cd_detected , Stopped , store_cd_info , And_<good_disk_format,
+ always_true> >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Playing , stop , Stopped , stop_playback , none >,
+ Row < Playing , pause , Paused , pause_playback , none >,
+ Row < Playing , open_close , Open , stop_and_open , none >,
+ // +---------+-------------+---------+---------------------------+----------------------+
+ Row < Paused , end_pause , Playing , resume_playback , none >,
+ Row < Paused , stop , Stopped , stop_playback , none >,
+ Row < Paused , open_close , Open , stop_and_open , none >
+ // +---------+-------------+---------+---------------------------+----------------------+
+ > {};
+ // fsm definition
+ struct player_tag {};
+ typedef msm::front::euml::func_state_machine<Playing_tag,
+ // transition table
+ player_transition_table,
+ //Initial state
+ Empty> player_;
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ // no need to call play() as the previous event does it in its action method
+ //p.process_event(play());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/TestInternal.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/TestInternal.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,327 @@
+#include <iostream>
+#include "boost/mpl/vector/vector30.hpp"
+
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/internal_row.hpp>
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+namespace
+{
+ // events
+ struct play {};
+ struct end_pause {};
+ struct stop {};
+ struct pause {};
+ struct internal_event {};
+ struct open_close {};
+ struct NextSong {};
+ struct PreviousSong {};
+ struct to_ignore {};
+
+ // A "complicated" event type that carries some data.
+ enum DiskTypeEnum
+ {
+ DISK_CD=0,
+ DISK_DVD=1
+ };
+ struct cd_detected
+ {
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+ };
+
+ // front-end: define the FSM structure
+ struct player_ : public msm::front::state_machine_def<player_>
+ {
+ // 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(end_pause const&) { std::cout << "player::resume_playback\n"; }
+ void stop_and_open(open_close const&) { std::cout << "player::stop_and_open\n"; }
+ void stopped_again(stop const&) {std::cout << "player::stopped_again\n";}
+ // guard conditions
+ bool good_disk_format(cd_detected const& evt)
+ {
+ // to test a guard condition, let's say we understand only CDs, not DVD
+ if (evt.disc_type != DISK_CD)
+ {
+ std::cout << "wrong disk, sorry" << std::endl;
+ return false;
+ }
+ return true;
+ }
+ // transitions internal to Empty
+ void internal_action(cd_detected const&){ std::cout << "Empty::internal action\n"; }
+ bool internal_guard(cd_detected const&)
+ {
+ std::cout << "Empty::internal guard\n";
+ return false;
+ }
+ void internal_action(internal_event const&){ std::cout << "Playing::internal action\n"; }
+ bool internal_guard(internal_event const&)
+ {
+ std::cout << "Playing::internal guard\n";
+ return false;
+ }
+
+ // The list of FSM states
+ struct Empty : public msm::front::state<>
+ {
+ // every (optional) entry/exit methods get the event passed.
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+
+ struct internal_guard_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal guard functor\n";
+ return false;
+ }
+ };
+ struct internal_action_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& ,SourceState& ,TargetState& )
+ {
+ std::cout << "Empty::internal action functor" << std::endl;
+ }
+ };
+ void internal_action(to_ignore const&) { std::cout << "Empty::(almost)ignoring event\n"; }
+ // Transition table for Empty
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ Row < Empty , cd_detected , none , internal_action_fct ,internal_guard_fct >,
+ Internal < cd_detected , internal_action_fct ,internal_guard_fct >,
+ a_internal< to_ignore , Empty,&Empty::internal_action >
+ // +---------+-------------+----------+------------------------+----------------------+
+ > {};
+ };
+ struct Open : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ };
+
+ struct Stopped : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Stopped" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Stopped" << std::endl;}
+ };
+
+ struct Playing_ : public msm::front::state_machine_def<Playing_>
+ {
+ // when playing, the CD is loaded and we are in either pause or playing (duh)
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Playing" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Playing" << std::endl;}
+
+ // The list of FSM states
+ struct Song1 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: First song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: First Song" << std::endl;}
+
+ };
+ struct Song2 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Second song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Second Song" << std::endl;}
+ };
+ struct Song3 : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Third song" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Third Song" << std::endl;}
+ };
+ // the initial state. Must be defined
+ typedef Song1 initial_state;
+ // transition actions
+ void start_next_song(NextSong const&){std::cout << "Playing: start_next_song" << std::endl;}
+ void start_prev_song(PreviousSong const&){std::cout << "Playing: start_prev_song" << std::endl;}
+ // guard conditions
+ struct playing_internal_guard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::internal guard fct\n";
+ return true;
+ }
+ };
+ struct playing_false_guard
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ bool operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::false guard\n";
+ return false;
+ }
+ };
+ struct playing_internal_fct
+ {
+ template <class EVT,class FSM,class SourceState,class TargetState>
+ void operator()(EVT const& evt ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::internal fct\n";
+ }
+ };
+ typedef Playing_ pl; // makes transition table cleaner
+ // Transition table for Playing
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +---------+---------------+---------+---------------------+----------------------+
+ a_row < Song1 , NextSong , Song2 , &pl::start_next_song >,
+ a_row < Song2 , PreviousSong , Song1 , &pl::start_prev_song >,
+ a_row < Song2 , NextSong , Song3 , &pl::start_next_song >,
+ a_row < Song3 , PreviousSong , Song2 , &pl::start_prev_song >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Internal transition table for Playing
+ // +---------+----------------+---------+---------------------+-----------------------+
+ struct internal_transition_table : mpl::vector<
+ // normal internal transition
+ // Start Event Next Action Guard
+ Internal < internal_event , playing_internal_fct,playing_internal_guard >,
+ // conflict between internal and the external defined above
+ Internal < PreviousSong , playing_internal_fct,playing_false_guard >,
+ internal < internal_event , player_,&player_::internal_action,
+ player_,&player_::internal_guard >
+ // +---------+----------------+---------+---------------------+-----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // back-end
+ typedef msm::back::state_machine<Playing_> Playing;
+
+ // state not defining any entry or exit
+ struct Paused : public msm::front::state<>
+ {
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Stopped , play , Playing , &p::start_playback >,
+ a_row < Stopped , open_close , Open , &p::open_drawer >,
+ _row < Stopped , stop , Stopped >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Open , open_close , Empty , &p::close_drawer >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Empty , open_close , Open , &p::open_drawer >,
+ // conflict between a normal and 2 internal transitions (irow/g_irow)
+ // + a state-defined internals defined 2 ways (see Empty)
+ row < Empty , cd_detected , Stopped , &p::store_cd_info ,&p::good_disk_format >,
+ irow < Empty , cd_detected , &p::internal_action ,&p::internal_guard >,
+ g_irow < Empty , cd_detected ,&p::internal_guard >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Playing , stop , Stopped , &p::stop_playback >,
+ a_row < Playing , pause , Paused , &p::pause_playback >,
+ a_row < Playing , open_close , Open , &p::stop_and_open >,
+ // +---------+-------------+---------+---------------------+----------------------+
+ a_row < Paused , end_pause , Playing , &p::resume_playback >,
+ a_row < Paused , stop , Stopped , &p::stop_playback >,
+ a_row < Paused , open_close , Open , &p::stop_and_open >
+ // +---------+-------------+---------+---------------------+----------------------+
+ > {};
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // Pick a back-end
+ typedef msm::back::state_machine<player_> player;
+
+ //
+ // Testing utilities.
+ //
+ static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" };
+ void pstate(player const& p)
+ {
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+ }
+
+ void test()
+ {
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // this event will be ignored and not call no_transition
+ p.process_event(to_ignore());
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+ // will be rejected, wrong disk type
+ p.process_event(
+ cd_detected("louie, louie",DISK_DVD)); pstate(p);
+ p.process_event(
+ cd_detected("louie, louie",DISK_CD)); pstate(p);
+ p.process_event(play());
+ p.process_event(NextSong());
+ std::cout << "sending an internal event" << std::endl;
+ p.process_event(internal_event());
+ std::cout << "conflict between the internal and normal transition. Internal is tried last" << std::endl;
+ p.process_event(PreviousSong());
+
+ // at this point, Play is active
+ p.process_event(pause()); pstate(p);
+ // go back to Playing
+ p.process_event(end_pause()); pstate(p);
+ p.process_event(pause()); pstate(p);
+ p.process_event(stop()); pstate(p);
+ // event leading to the same state
+ // no action method called as it is not present in the transition table
+ p.process_event(stop()); pstate(p);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/char_event_dispatcher.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/char_event_dispatcher.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,82 @@
+#ifndef BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
+#define BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
+
+#include <boost/msm/back/common_types.hpp>
+
+struct digit {};
+struct char_0 : public digit {};
+struct char_1 : public digit {};
+struct char_2 : public digit {};
+struct char_3 : public digit {};
+struct char_4 : public digit {};
+struct char_5 : public digit {};
+struct char_6 : public digit {};
+struct char_7 : public digit {};
+struct char_8 : public digit {};
+struct char_9 : public digit {};
+struct minus_char {};
+template <char c>
+struct event_char{};
+template <>
+struct event_char<'0'> : public digit{};
+template <>
+struct event_char<'1'> : public digit{};
+template <>
+struct event_char<'2'> : public digit{};
+template <>
+struct event_char<'3'> : public digit{};
+template <>
+struct event_char<'4'> : public digit{};
+template <>
+struct event_char<'5'> : public digit{};
+template <>
+struct event_char<'6'> : public digit{};
+template <>
+struct event_char<'7'> : public digit{};
+template <>
+struct event_char<'8'> : public digit{};
+template <>
+struct event_char<'9'> : public digit{};
+
+namespace boost { namespace msm { namespace back {
+
+
+template <class Fsm>
+struct char_event_dispatcher
+{
+ template <char c>
+ struct dispatch_event_helper
+ {
+ static execute_return apply(Fsm& fsm)
+ {
+ return fsm.process_event(event_char<c>());
+ }
+ };
+ char_event_dispatcher()
+ {
+ entries[0x30]=&dispatch_event_helper<'0'>::apply;
+ entries[0x31]=&dispatch_event_helper<'1'>::apply;
+ entries[0x32]=&dispatch_event_helper<'2'>::apply;
+ entries[0x33]=&dispatch_event_helper<'3'>::apply;
+ entries[0x34]=&dispatch_event_helper<'4'>::apply;
+ entries[0x35]=&dispatch_event_helper<'5'>::apply;
+ entries[0x36]=&dispatch_event_helper<'6'>::apply;
+ entries[0x37]=&dispatch_event_helper<'7'>::apply;
+ entries[0x38]=&dispatch_event_helper<'8'>::apply;
+ entries[0x39]=&dispatch_event_helper<'9'>::apply;
+ entries[0x2D]=&dispatch_event_helper<'-'>::apply;
+ entries[0x2B]=&dispatch_event_helper<'+'>::apply;
+ }
+ execute_return process_event(Fsm& fsm,char c) const
+ {
+ return entries[c](fsm);
+ }
+
+ // The singleton instance.
+ static const char_event_dispatcher instance;
+ typedef execute_return (*cell)(Fsm&);
+ cell entries[255];
+};
+
+}}} // boost::msm::back
+#endif //BOOST_MSM_CHAR_EVENT_DISPATCHER_HPP
\ No newline at end of file
Added: trunk/libs/msm/doc/PDF/examples/distributed_table/DistributedTable.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/distributed_table/DistributedTable.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,64 @@
+#include <vector>
+#include <iostream>
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+// functors
+#include <boost/msm/front/functor_row.hpp>
+#include <boost/msm/front/euml/common.hpp>
+
+#include "Empty.hpp"
+#include "Open.hpp"
+
+using namespace std;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+
+// front-end: define the FSM structure
+struct player_ : public msm::front::state_machine_def<player_>
+{
+ // the initial state of the player SM. Must be defined
+ typedef Empty initial_state;
+ typedef mpl::vector<Empty,Open> explicit_creation;
+
+ typedef player_ p; // makes transition table cleaner
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+};
+// Pick a back-end
+typedef msm::back::state_machine<player_> player;
+
+//
+// Testing utilities.
+//
+static char const* const state_names[] = { "Empty", "Open" };
+void pstate(player const& p)
+{
+ std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
+}
+
+void test()
+{
+ player p;
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ p.start();
+ // go to Open, call on_exit on Empty, then action, then on_entry on Open
+ p.process_event(open_close()); pstate(p);
+ p.process_event(open_close()); pstate(p);
+}
+
+int main()
+{
+ test();
+ return 0;
+}
+
Added: trunk/libs/msm/doc/PDF/examples/distributed_table/Empty.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/distributed_table/Empty.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,7 @@
+#include <iostream>
+#include "Empty.hpp"
+
+void Empty::open_drawer(open_close const&)
+{
+ std::cout << "Empty::open_drawer\n";
+}
Added: trunk/libs/msm/doc/PDF/examples/distributed_table/Empty.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/distributed_table/Empty.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,33 @@
+#ifndef EMPTY_HPP
+#define EMPTY_HPP
+
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/row2.hpp>
+
+#include "Events.hpp"
+
+struct Open;
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+struct Empty : public msm::front::state<>
+{
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "entering: Empty" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Empty" << std::endl;}
+ void open_drawer(open_close const&);
+
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ msm::front::a_row2 < Empty , open_close , Open , Empty,&Empty::open_drawer >
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ > {};
+};
+
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/PDF/examples/distributed_table/Events.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/distributed_table/Events.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,29 @@
+#ifndef EVENTS_HPP
+#define EVENTS_HPP
+
+// events
+struct play {};
+struct end_pause {};
+struct stop {};
+struct pause {};
+struct open_close {};
+
+// A "complicated" event type that carries some data.
+enum DiskTypeEnum
+{
+ DISK_CD=0,
+ DISK_DVD=1
+};
+struct cd_detected
+{
+ cd_detected(std::string name, DiskTypeEnum diskType)
+ : name(name),
+ disc_type(diskType)
+ {}
+
+ std::string name;
+ DiskTypeEnum disc_type;
+};
+
+
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/PDF/examples/distributed_table/Open.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/distributed_table/Open.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,7 @@
+#include <iostream>
+#include "Open.hpp"
+
+void Open::close_drawer(open_close const&)
+{
+ std::cout << "Open::close_drawer\n";
+}
Added: trunk/libs/msm/doc/PDF/examples/distributed_table/Open.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/distributed_table/Open.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,34 @@
+#ifndef OPEN_HPP
+#define OPEN_HPP
+
+// back-end
+#include <boost/msm/back/state_machine.hpp>
+//front-end
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/row2.hpp>
+
+#include "Events.hpp"
+
+struct Empty;
+
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+using namespace msm::front;
+
+struct Open : public msm::front::state<>
+{
+ template <class Event,class FSM>
+ void on_entry(Event const& ,FSM&) {std::cout << "entering: Open" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "leaving: Open" << std::endl;}
+ void close_drawer(open_close const&);
+
+ struct internal_transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ msm::front::a_row2 < Open , open_close , Empty , Open,&Open::close_drawer >
+ //+-------------+---------+-------------+---------+---------------------------+----------------------+
+ > {};
+};
+
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/PDF/examples/iPodEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPodEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,261 @@
+#include <vector>
+#include <set>
+#include <string>
+#include <iostream>
+// we need more than the default 20 states
+#define FUSION_MAX_VECTOR_SIZE 20
+// we need more than the default 20 transitions
+#include "boost/mpl/vector/vector50.hpp"
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+
+// attribute names and types
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_Selected)
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_SongIndex)
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(int,m_NumberOfSongs)
+#include "ipod_functors.hpp"
+
+
+namespace // Concrete FSM implementation
+{
+ //flags
+ BOOST_MSM_EUML_FLAG(MenuActive)
+ BOOST_MSM_EUML_FLAG(NoFastFwd)
+ // hardware-generated events
+ BOOST_MSM_EUML_EVENT(Hold)
+ BOOST_MSM_EUML_EVENT(NoHold)
+ BOOST_MSM_EUML_EVENT(SouthPressed)
+ BOOST_MSM_EUML_EVENT(SouthReleased)
+ BOOST_MSM_EUML_EVENT(MiddleButton)
+ BOOST_MSM_EUML_EVENT(EastPressed)
+ BOOST_MSM_EUML_EVENT(EastReleased)
+ BOOST_MSM_EUML_EVENT(Off)
+ BOOST_MSM_EUML_EVENT(MenuButton)
+ // internally defined events
+ BOOST_MSM_EUML_EVENT(PlayPause)
+ BOOST_MSM_EUML_EVENT(EndPlay)
+ struct CloseMenu_impl : euml_event<CloseMenu_impl>
+ {
+ CloseMenu_impl(){}//defined only for stt
+ template<class EVENT>
+ CloseMenu_impl(EVENT const &) {}
+ };
+ CloseMenu_impl const CloseMenu;
+ BOOST_MSM_EUML_EVENT(OnOffTimer)
+ BOOST_MSM_EUML_EVENT(MenuMiddleButton)
+ BOOST_MSM_EUML_EVENT(SelectSong)
+ BOOST_MSM_EUML_EVENT(SongFinished)
+
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_Selected ), StartSongAttributes)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(StartSong,StartSongAttributes)
+ BOOST_MSM_EUML_EVENT(PreviousSong)
+ BOOST_MSM_EUML_EVENT(NextSong)
+ BOOST_MSM_EUML_EVENT(ForwardTimer)
+ BOOST_MSM_EUML_EVENT(PlayingMiddleButton)
+
+ // Concrete iPod implementation
+ // The list of iPod states
+ BOOST_MSM_EUML_STATE(( NotHolding_Entry ),NotHolding)
+ BOOST_MSM_EUML_INTERRUPT_STATE(( NoHold,Holding_Entry ),Holding)
+ BOOST_MSM_EUML_STATE(( NotPlaying_Entry ),NotPlaying)
+ BOOST_MSM_EUML_STATE(( NoMenuMode_Entry ),NoMenuMode)
+ BOOST_MSM_EUML_STATE(( NoOnOffButton_Entry ),NoOnOffButton)
+ BOOST_MSM_EUML_STATE(( OffDown_Entry ),OffDown)
+ BOOST_MSM_EUML_STATE(( PlayerOff_Entry ),PlayerOff)
+ BOOST_MSM_EUML_STATE(( CheckMiddleButton_Entry ),CheckMiddleButton)
+
+ // Concrete PlayingMode_ implementation
+ // The list of PlayingMode_ states
+ BOOST_MSM_EUML_STATE(( Playing_Entry ),Playing)
+ BOOST_MSM_EUML_STATE(( WaitingForNextPrev_Entry ),WaitingForNextPrev)
+ BOOST_MSM_EUML_STATE(( Paused_Entry ),Paused)
+ BOOST_MSM_EUML_STATE(( WaitingForEnd_Entry ),WaitingForEnd)
+ BOOST_MSM_EUML_STATE(( NoForward_Entry ),NoForward)
+ BOOST_MSM_EUML_STATE(( ForwardPressed_Entry,ForwardPressed_Exit ),ForwardPressed)
+ BOOST_MSM_EUML_STATE(( FastForward_Entry,FastForward_Exit ),FastForward)
+ BOOST_MSM_EUML_STATE(( StdDisplay_Entry ),StdDisplay)
+ BOOST_MSM_EUML_STATE(( SetPosition_Entry ),SetPosition)
+ BOOST_MSM_EUML_STATE(( SetMark_Entry ),SetMark)
+ BOOST_MSM_EUML_EXIT_STATE(( EndPlay,PlayingExit_Entry ),PlayingExit)
+
+ //stt
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Paused == Playing + PlayPause ,
+ Paused == Playing + Off ,
+ Playing == Playing + StartSong
+ / (if_then_(event_(m_Selected) > Int_<0>() &&
+ event_(m_Selected) < fsm_(m_NumberOfSongs),
+ fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) ,
+ Playing == Playing + SongFinished
+ / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/
+ show_playing_song, /*then*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else*/ ) ) ,
+ Playing == Paused + PlayPause ,
+ Playing == Paused + StartSong
+ / (if_then_(event_(m_Selected) > Int_<0>() &&
+ event_(m_Selected) < fsm_(m_NumberOfSongs),
+ fsm_(m_SongIndex) = event_(m_Selected) ),show_selected_song) ,
+ WaitingForNextPrev == WaitingForNextPrev+ PreviousSong
+ /( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(), /*if*/
+ show_playing_song, /*then*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ) ,
+ WaitingForNextPrev == WaitingForNextPrev+ NextSong
+ / (if_then_else_(++fsm_(m_SongIndex) <= fsm_(m_NumberOfSongs), /*if*/
+ show_playing_song, /*then*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay)) /*else*/ ) ),
+
+ PlayingExit == WaitingForEnd + EndPlay ,
+ ForwardPressed == NoForward + EastPressed [!is_flag_(NoFastFwd)] ,
+ NoForward == ForwardPressed + EastReleased / process_(NextSong) ,
+ FastForward == ForwardPressed + ForwardTimer / do_fast_forward ,
+ FastForward == FastForward + ForwardTimer / do_fast_forward ,
+ FastForward == NoForward + EastReleased ,
+ SetPosition == StdDisplay + PlayingMiddleButton ,
+ StdDisplay == SetPosition + StartSong ,
+ SetMark == SetPosition + PlayingMiddleButton ,
+ StdDisplay == SetMark + PlayingMiddleButton ,
+ StdDisplay == SetMark + StartSong
+ // +------------------------------------------------------------------------------+
+ ),playingmode_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (playingmode_transition_table, //STT
+ init_ << Playing << WaitingForNextPrev << WaitingForEnd
+ << NoForward << StdDisplay, // Init States
+ fsm_(m_NumberOfSongs)=Int_<5>(), // entry
+ no_action, // exit
+ attributes_ << m_SongIndex << m_NumberOfSongs, //attributes
+ configure_<< NoFastFwd // Flags, Deferred events, configuration
+ ),PlayingMode_)
+
+ // choice of back-end
+ typedef msm::back::state_machine<PlayingMode_> PlayingMode_type;
+ PlayingMode_type const PlayingMode;
+
+ // Concrete MenuMode_ implementation
+ // The list of MenuMode_ states
+ BOOST_MSM_EUML_STATE(( WaitingForSongChoice_Entry ),WaitingForSongChoice)
+ BOOST_MSM_EUML_STATE(( StartCurrentSong_Entry ),StartCurrentSong)
+ BOOST_MSM_EUML_EXIT_STATE(( CloseMenu,MenuExit_Entry ),MenuExit)
+
+ //stt
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ StartCurrentSong == WaitingForSongChoice + MenuMiddleButton ,
+ MenuExit == StartCurrentSong + SelectSong
+ // +------------------------------------------------------------------------------+
+ ),menumode_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE( (menumode_transition_table, //STT
+ init_ << WaitingForSongChoice, // Init States
+ no_action, // entry
+ no_action, // exit
+ attributes_ << no_attributes_, //attributes
+ configure_<< MenuActive // Flags, Deferred events, configuration
+ ),MenuMode_)
+
+ typedef msm::back::state_machine<MenuMode_> MenuMode_type;
+ MenuMode_type const MenuMode;
+
+ // iPod stt
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ // +------------------------------------------------------------------------------+
+ Holding == NotHolding + Hold ,
+ NotHolding == Holding + NoHold ,
+ PlayingMode == NotPlaying + PlayPause ,
+ NotPlaying == exit_pt_(PlayingMode,PlayingExit) + EndPlay
+ / process_(MenuButton) ,
+ MenuMode == NoMenuMode + MenuButton ,
+ NoMenuMode == exit_pt_(MenuMode,MenuExit)+ CloseMenu
+ / process2_(StartSong,Int_<5>()) ,
+ OffDown == NoOnOffButton + SouthPressed ,
+ NoOnOffButton == OffDown + SouthReleased
+ / process_(PlayPause) ,
+ PlayerOff == OffDown + OnOffTimer
+ / (show_player_off,process_(Off)) ,
+ NoOnOffButton == PlayerOff + SouthPressed / show_player_on ,
+ NoOnOffButton == PlayerOff + NoHold / show_player_on ,
+ CheckMiddleButton == CheckMiddleButton + MiddleButton
+ [is_flag_(MenuActive)] / process_(PlayingMiddleButton) ,
+ CheckMiddleButton == CheckMiddleButton + MiddleButton
+ [!is_flag_(MenuActive)] / process_(PlayingMiddleButton)
+ // +------------------------------------------------------------------------------+
+ ),ipod_transition_table )
+
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( ipod_transition_table, //STT
+ init_ << NotHolding << NotPlaying << NoMenuMode
+ << NoOnOffButton << CheckMiddleButton
+ ),
+ iPod_) //fsm name
+ typedef msm::back::state_machine<iPod_> iPod;
+
+ void test()
+ {
+ iPod sm;
+ sm.start();
+ // we first press Hold
+ std::cout << "pressing hold" << std::endl;
+ sm.process_event(Hold);
+ // pressing a button is now ignored
+ std::cout << "pressing a button" << std::endl;
+ sm.process_event(SouthPressed);
+ // or even one contained in a submachine
+ sm.process_event(EastPressed);
+ // no more holding
+ std::cout << "no more holding, end interrupt event sent" << std::endl;
+ sm.process_event(NoHold);
+ std::cout << "pressing South button a short time" << std::endl;
+ sm.process_event(SouthPressed);
+ // we suppose a short pressing leading to playing a song
+ sm.process_event(SouthReleased);
+ // we move to the next song
+ std::cout << "we move to the next song" << std::endl;
+ sm.process_event(NextSong);
+ // then back to no song => exit from playing, menu active
+ std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
+ sm.process_event(PreviousSong);
+ sm.process_event(PreviousSong);
+ // even in menu mode, pressing play will start playing the first song
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(SouthReleased);
+ // of course pausing must be possible
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(SouthReleased);
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(SouthReleased);
+ // while playing, you can fast forward
+ std::cout << "pressing East button a long time" << std::endl;
+ sm.process_event(EastPressed);
+ // let's suppose the timer just fired
+ sm.process_event(ForwardTimer);
+ sm.process_event(ForwardTimer);
+ // end of fast forwarding
+ std::cout << "releasing East button" << std::endl;
+ sm.process_event(EastReleased);
+ // we now press the middle button to set playing at a given position
+ std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
+ sm.process_event(MiddleButton);
+ std::cout <<"pressing East button to fast forward" << std::endl;
+ sm.process_event(EastPressed);
+ // we switch off and on
+ std::cout <<"switch off player" << std::endl;
+ sm.process_event(SouthPressed);
+ sm.process_event(OnOffTimer);
+ std::cout <<"switch on player" << std::endl;
+ sm.process_event(SouthPressed);
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/iPodSearch.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPodSearch.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,198 @@
+#include <set>
+#include <string>
+#include <iostream>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+
+namespace // Concrete FSM implementation
+{
+ // events
+ struct OneSong
+ {
+ OneSong(string const& asong):m_Song(asong){}
+ const string& get_data() const {return m_Song;}
+ private:
+ string m_Song;
+ };
+ template <class DATA>
+ struct NotFound
+ {
+ DATA get_data() const {return m_Data;}
+ DATA m_Data;
+ };
+ template <class DATA>
+ struct Found
+ {
+ DATA get_data() const {return m_Data;}
+ DATA m_Data;
+ };
+ struct Done {};
+
+ template <class Container,class BASE_TYPE,class FSMType>
+ struct Insert : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& )
+ {
+ //TODO other containers
+ if (m_Cont)
+ {
+ m_Cont->insert(evt.get_data());
+ }
+ m_fsm->process_event(Done());
+ }
+ void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
+ void set_container(Container* cont){m_Cont=cont;}
+ Container* m_Cont;
+
+ private:
+ FSMType* m_fsm;
+ };
+ template <class BASE_TYPE,class FSMType>
+ struct StringFind : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& )
+ {
+ //TODO other containers
+ // if the element in the event is found
+ if (evt.get_data().find(m_Cont) != std::string::npos )
+ {
+ Found<std::string> res;
+ res.m_Data = evt.get_data();
+ m_fsm->process_event(res);
+ }
+ // data not found
+ else
+ {
+ NotFound<std::string> res;
+ res.m_Data = evt.get_data();
+ m_fsm->process_event(res);
+ }
+ }
+ void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
+ void set_container(const char* cont){m_Cont=cont;}
+ private:
+ std::string m_Cont;
+ FSMType* m_fsm;
+ };
+ template <class EventType,class Container,class BASE_TYPE,class FSMType>
+ struct Foreach : public boost::msm::front::state<BASE_TYPE,boost::msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const& evt,FSM& )
+ {
+ //TODO other containers
+ if (!m_Cont.empty())
+ {
+ typename Container::value_type next_event = *m_Cont.begin();
+ m_Cont.erase(m_Cont.begin());
+ m_fsm->process_event(EventType(next_event));
+ }
+ }
+ void set_sm_ptr(FSMType* fsm){m_fsm=fsm;}
+ void set_container(Container* cont){m_Cont=*cont;}
+
+ private:
+ Container m_Cont;
+ FSMType* m_fsm;
+ };
+
+
+ // Concrete FSM implementation
+ struct iPodSearch_ : public msm::front::state_machine_def<iPodSearch_>
+ {
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+ // The list of FSM states
+ typedef std::set<std::string> Songset;
+ typedef Insert<Songset,boost::msm::front::default_base_state,iPodSearch> MyInsert;
+ typedef StringFind<boost::msm::front::default_base_state,iPodSearch> MyFind;
+ typedef Foreach<OneSong,Songset,boost::msm::front::default_base_state,iPodSearch> MyForeach;
+
+ // the initial state of the player SM. Must be defined
+ typedef MyForeach initial_state;
+
+ // transition actions
+
+ // guard conditions
+
+ typedef iPodSearch_ fsm; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector4<
+ // Start Event Next Action Guard
+ // +-----------+------------------+------------+---------------------+----------------------+
+ _row < MyForeach , OneSong , MyFind >,
+ _row < MyFind , NotFound<string> , MyForeach >,
+ _row < MyFind , Found<string> , MyInsert >,
+ _row < MyInsert , Done , MyForeach >
+ // +-----------+------------------+------------+---------------------+----------------------+
+ > {};
+ iPodSearch_():m_AllSongs(),m_ResultSearch()
+ {
+ // add a few songs for testing
+ m_AllSongs.insert("Let it be");
+ m_AllSongs.insert("Yellow submarine");
+ m_AllSongs.insert("Twist and Shout");
+ m_AllSongs.insert("She Loves You");
+ }
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& fsm)
+ {
+ fsm.template get_state<MyForeach&>().set_container(&m_AllSongs);
+ fsm.template get_state<MyInsert&>().set_container(&m_ResultSearch);
+ }
+ const Songset& get_result(){return m_ResultSearch;}
+ void reset_search(){m_ResultSearch.clear();}
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+
+ private:
+ Songset m_AllSongs;
+ Songset m_ResultSearch;
+ };
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+
+
+ void test()
+ {
+ iPodSearch search;
+ // look for "She Loves You" using the first letters
+ search.get_state<iPodSearch::MyFind*>()->set_container("Sh");// will find 2 songs
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ search.start();
+ // display all the songs
+ const iPodSearch::Songset& res = search.get_result();
+ for (iPodSearch::Songset::const_iterator it = res.begin();it != res.end();++it)
+ {
+ cout << "candidate song:" << *it << endl;
+ }
+ cout << "search using more letters" << endl;
+ // look for "She Loves You" using more letters
+ search.reset_search();
+ search.get_state<iPodSearch::MyFind*>()->set_container("She");// will find 1 song
+ search.start();
+ const iPodSearch::Songset& res2 = search.get_result();
+ for (iPodSearch::Songset::const_iterator it = res2.begin();it != res2.end();++it)
+ {
+ cout << "candidate song:" << *it << endl;
+ }
+
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/iPodSearchEuml.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPodSearchEuml.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,156 @@
+// same as iPodSearch.cpp but using eUML
+// requires boost >= v1.40 because using mpl::string
+
+#include <vector>
+#include <iostream>
+
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+#include <boost/msm/front/euml/stl.hpp>
+
+using namespace std;
+using namespace boost::msm::front::euml;
+namespace msm = boost::msm;
+namespace mpl = boost::mpl;
+
+// how long the timer will ring when countdown elapsed.
+#define RINGING_TIME 5
+
+namespace // Concrete FSM implementation
+{
+ // events
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), OneSongDef)
+ struct OneSong_impl : euml_event<OneSong_impl>,OneSongDef
+ {
+ OneSong_impl(){}
+ OneSong_impl(const string& asong)
+ {
+ get_attribute(m_song)=asong;
+ }
+ OneSong_impl(const char* asong)
+ {
+ get_attribute(m_song)=asong;
+ }
+ OneSong_impl(const OneSong_impl& asong)
+ {
+ get_attribute(m_song)=asong.get_attribute(m_song);
+ }
+ const string& get_data() const {return get_attribute(m_song);}
+ };
+ OneSong_impl const OneSong;
+
+ // attribute definitions
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_src_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>,m_tgt_container)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_letters)
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(vector<OneSong_impl>::iterator,m_src_it)
+
+ // the same attribute name can be reused
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), NotFoundDef)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(NotFound,NotFoundDef)
+
+ BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(Found,FoundDef)
+
+ BOOST_MSM_EUML_EVENT(Done)
+
+ // Concrete FSM implementation
+
+ // The list of FSM states
+ BOOST_MSM_EUML_STATE(( (push_back_(fsm_(m_tgt_container),event_(m_song))
+ ,process_(Done)),
+ no_action ),Insert)
+
+ BOOST_MSM_EUML_STATE(( if_then_else_( string_find_(event_(m_song),state_(m_letters)) != Npos_<string>() ,
+ process2_(Found,event_(m_song)),
+ process2_(NotFound,event_(m_song)) ) ,
+ no_action,
+ attributes_ << m_letters ),StringFind)
+
+ BOOST_MSM_EUML_STATE(( if_then_( state_(m_src_it) != end_(fsm_(m_src_container)),
+ process2_(OneSong,*(state_(m_src_it)++)) ),
+ no_action,
+ attributes_ << m_src_it ),Foreach)
+
+ // replaces the old transition table
+ BOOST_MSM_EUML_TRANSITION_TABLE((
+ StringFind == Foreach + OneSong ,
+ Insert == StringFind + Found ,
+ Foreach == StringFind + NotFound ,
+ Foreach == Insert + Done
+ // +------------------------------------------------------------------------------+
+ ),transition_table )
+
+ BOOST_MSM_EUML_ACTION(Log_No_Transition)
+ {
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+ // create a state machine "on the fly"
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE(( transition_table, //STT
+ init_ << Foreach, // Init
+ (
+ clear_(fsm_(m_src_container)), //clear source
+ clear_(fsm_(m_tgt_container)), //clear results
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'Let ','it ','be'> >()),//add a song
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'Yell','ow s','ubma','rine'> >()),//add a song
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'Twis','t an','d Sh','out'> >()),//add a song
+ push_back_(fsm_(m_src_container),
+ String_<mpl::string<'She ','love','s yo','u'> >()),//add a song
+ attribute_(substate_(Foreach()),m_src_it)
+ = begin_(fsm_(m_src_container)) //set the search begin
+ ), // Entry
+ no_action, // Exit
+ attributes_ << m_src_container // song list
+ << m_tgt_container, // result
+ configure_<< no_configure_,
+ Log_No_Transition
+ ),
+ iPodSearch_) //fsm name
+
+
+ // choice of back-end
+ typedef msm::back::state_machine<iPodSearch_> iPodSearch;
+
+ void test()
+ {
+ iPodSearch search;
+
+ // look for "She Loves You" using the first letters
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="Sh";// will find 2 songs
+
+ // needed to start the highest-level SM. This will call on_entry and mark the start of the SM
+ search.start();
+ // display all the songs
+ for (vector<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_attribute(m_song) << endl;
+ }
+
+ cout << "search using more letters" << endl;
+ // look for "She Loves You" using more letters
+ search.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().get_attribute(m_letters)="She";// will find 1 song
+ search.start();
+ // display all the songs
+ for (vector<OneSong_impl>::const_iterator it = search.get_attribute(m_tgt_container).begin();
+ it != search.get_attribute(m_tgt_container).end();++it)
+ {
+ cout << "candidate song:" << (*it).get_attribute(m_song) << endl;
+ }
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/iPod_distributed/Events.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPod_distributed/Events.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,40 @@
+#ifndef EVENTS_HPP
+#define EVENTS_HPP
+
+//flags
+struct MenuActive{};
+// hardware-generated events
+struct Hold {};
+struct NoHold {};
+struct SouthPressed {};
+struct SouthReleased {};
+struct MiddleButton {};
+struct EastPressed{};
+struct EastReleased{};
+struct Off {};
+struct MenuButton {};
+
+// internally used events
+struct PlayPause {};
+struct EndPlay {};
+struct CloseMenu
+{
+ template<class EVENT>
+ CloseMenu(EVENT const &) {}
+};
+struct OnOffTimer {};
+struct MenuMiddleButton {};
+struct SelectSong {};
+struct SongFinished {};
+struct StartSong
+{
+ StartSong (int song_index):m_Selected(song_index){}
+ int m_Selected;
+};
+struct PreviousSong{};
+struct NextSong{};
+struct NextSongDerived : public NextSong{};
+struct ForwardTimer{};
+struct PlayingMiddleButton{};
+
+#endif // EVENTS_HPP
Added: trunk/libs/msm/doc/PDF/examples/iPod_distributed/MenuMode.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPod_distributed/MenuMode.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,2 @@
+#include "MenuMode.hpp"
+BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(MenuMode)
Added: trunk/libs/msm/doc/PDF/examples/iPod_distributed/MenuMode.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPod_distributed/MenuMode.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,52 @@
+#ifndef MENU_MODE_HPP
+#define MENU_MODE_HPP
+
+#include <iostream>
+#include <boost/any.hpp>
+
+#include "Events.hpp"
+#include <boost/msm/back/favor_compile_time.hpp>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+
+struct MenuMode_ : public msm::front::state_machine_def<MenuMode_>
+{
+ typedef mpl::vector1<MenuActive> flag_list;
+ struct WaitingForSongChoice : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::WaitingForSongChoice" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::WaitingForSongChoice" << std::endl;}
+ };
+ struct StartCurrentSong : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::StartCurrentSong" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::StartCurrentSong" << std::endl;}
+ };
+ struct MenuExit : public msm::front::exit_pseudo_state<CloseMenu>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: MenuMode::WaitingForSongChoice" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: MenuMode::WaitingForSongChoice" << std::endl;}
+ };
+ typedef WaitingForSongChoice initial_state;
+ typedef MenuMode_ fsm; // makes transition table cleaner
+ // Transition table for player
+ struct transition_table : mpl::vector2<
+ // Start Event Next Action Guard
+ // +---------------------+------------------+-------------------+---------------------+----------------------+
+ _row < WaitingForSongChoice , MenuMiddleButton , StartCurrentSong >,
+ _row < StartCurrentSong , SelectSong , MenuExit >
+ // +---------------------+------------------+-------------------+---------------------+----------------------+
+ > {};
+};
+typedef msm::back::state_machine<MenuMode_> MenuMode;
+
+#endif
Added: trunk/libs/msm/doc/PDF/examples/iPod_distributed/PlayingMode.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPod_distributed/PlayingMode.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,2 @@
+#include "PlayingMode.hpp"
+BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(PlayingMode)
Added: trunk/libs/msm/doc/PDF/examples/iPod_distributed/PlayingMode.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPod_distributed/PlayingMode.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,241 @@
+#ifndef PLAYING_MODE_HPP
+#define PLAYING_MODE_HPP
+
+#include <iostream>
+#include <boost/any.hpp>
+#define FUSION_MAX_VECTOR_SIZE 20
+
+#include "Events.hpp"
+#include <boost/msm/back/favor_compile_time.hpp>
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+#include <boost/msm/front/euml/euml.hpp>
+
+using namespace std;
+namespace msm = boost::msm;
+namespace euml = boost::msm::front::euml;
+
+struct PlayingMode_ : public msm::front::state_machine_def<PlayingMode_>
+{
+ //flags
+ struct NoFastFwd{};
+
+ struct Playing : public msm::front::state<default_base_state,msm::front::sm_ptr>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& )
+ {
+ std::cout << "starting: PlayingMode::Playing" << std::endl;
+ std::cout << "playing song:" << m_fsm->get_current_song() << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Playing" << std::endl;}
+ void set_sm_ptr(PlayingMode_* pl)
+ {
+ m_fsm = pl;
+ }
+ private:
+ PlayingMode_* m_fsm;
+ };
+ struct Paused : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::Paused" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::Paused" << std::endl;}
+ };
+ struct WaitingForNextPrev : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForNextPrev" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForNextPrev" << std::endl;}
+ };
+ struct WaitingForEnd : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::WaitingForEnd" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::WaitingForEnd" << std::endl;}
+ };
+ struct NoForward : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::NoForward" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::NoForward" << std::endl;}
+ };
+ struct ForwardPressed : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& )
+ {
+ std::cout << "starting: PlayingMode::ForwardPressed," << "start timer" << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& )
+ {
+ std::cout << "finishing: PlayingMode::ForwardPressed," << "stop timer" << std::endl;
+ }
+ };
+ struct FastForward : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& )
+ {
+ std::cout << "starting: PlayingMode::FastForward," << "start timer" << std::endl;
+ }
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& )
+ {
+ std::cout << "finishing: PlayingMode::FastForward," << "stop timer" << std::endl;
+ }
+ };
+ struct StdDisplay : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::StdDisplay" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::StdDisplay" << std::endl;}
+ };
+ struct SetPosition : public msm::front::state<>
+ {
+ typedef mpl::vector1<NoFastFwd> flag_list;
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetPosition" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetPosition" << std::endl;}
+ };
+ struct SetMark : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::SetMark" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::SetMark" << std::endl;}
+ };
+ struct PlayingExit : public msm::front::exit_pseudo_state<EndPlay>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayingMode::PlayingExit" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayingMode::PlayingExit" << std::endl;}
+ };
+ // transition action methods
+ struct inc_song_counter : euml::euml_action<inc_song_counter>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ if (++fsm.m_SongIndex <= fsm.m_NumberOfSongs )
+ {
+ std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
+ }
+ else
+ {
+ // last song => end playing, next play will start at the beginning
+ fsm.m_SongIndex = 1;
+ fsm.process_event(EndPlay());
+ }
+ }
+ };
+
+ void select_song(StartSong const& evt)
+ {
+ if ((evt.m_Selected>0) && (evt.m_Selected<=m_NumberOfSongs))
+ {
+ m_SongIndex = evt.m_Selected;
+ std::cout << "selecting song:" << m_SongIndex << std::endl;
+ }
+ else
+ {
+ // play current song
+ std::cout << "selecting song:" << m_SongIndex << std::endl;
+ }
+ }
+ struct dec_song_counter : euml::euml_action<dec_song_counter>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ if (--fsm.m_SongIndex >0 )
+ {
+ std::cout << "playing song:" << fsm.m_SongIndex << std::endl;
+ }
+ else
+ {
+ // before first song => end playing
+ fsm.m_SongIndex = 1;
+ fsm.process_event(EndPlay());
+ }
+ }
+ };
+ struct send_NextSong : euml::euml_action<send_NextSong>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ fsm.process_event(NextSong());
+ }
+ };
+
+ void do_fast_forward(ForwardTimer const&)
+ {
+ std::cout << "moving song forward..." << std::endl;
+ }
+
+ // transition guard methods
+ struct fast_fwd_ok : euml::euml_action<fast_fwd_ok>
+ {
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ // guard accepts only if fast forward is possible (No SetPosition mode)
+ return !fsm.is_flag_active<NoFastFwd>();
+ }
+ };
+ // initial states / orthogonal zones
+ typedef mpl::vector5<Playing,WaitingForNextPrev,WaitingForEnd,NoForward,StdDisplay>
+ initial_state;
+ typedef PlayingMode_ fsm; // makes transition table cleaner
+ // Transition table for player
+ struct transition_table : mpl::vector19<
+ // Start Event Next Action Guard
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ _row < Playing , PlayPause , Paused >,
+ _row < Playing , Off , Paused >,
+ a_row < Playing , StartSong , Playing , &fsm::select_song >,
+ _row < Paused , PlayPause , Playing >,
+ msm::front::Row < Playing , SongFinished , Playing , inc_song_counter , msm::front::none >,
+ a_row < Paused , StartSong , Playing , &fsm::select_song >,
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ msm::front::Row < WaitingForNextPrev , PreviousSong , WaitingForNextPrev , dec_song_counter , msm::front::none >,
+ msm::front::Row < WaitingForNextPrev , NextSong , WaitingForNextPrev , inc_song_counter , msm::front::none >,
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ _row < WaitingForEnd , EndPlay , PlayingExit >,
+ // +--------------------+---------------------+--------------------+--------------------------+----------------------+
+ msm::front::Row < NoForward , EastPressed , ForwardPressed , msm::front::none , fast_fwd_ok >,
+ msm::front::Row < ForwardPressed , EastReleased , NoForward , send_NextSong , msm::front::none >,
+ a_row < ForwardPressed , ForwardTimer , FastForward , &fsm::do_fast_forward >,
+ a_row < FastForward , ForwardTimer , FastForward , &fsm::do_fast_forward >,
+ _row < FastForward , EastReleased , NoForward >,
+ // +--------------------+---------------------+---------------------+--------------------------+----------------------+
+ _row < StdDisplay , PlayingMiddleButton , SetPosition >,
+ _row < SetPosition , StartSong , StdDisplay >,
+ _row < SetPosition , PlayingMiddleButton , SetMark >,
+ _row < SetMark , PlayingMiddleButton , StdDisplay >,
+ _row < SetMark , StartSong , StdDisplay >
+ // +--------------------+---------------------+---------------------+--------------------------+----------------------+
+ > {};
+ PlayingMode_():
+ m_SongIndex(1),
+ // for simplicity we decide there are 5 songs
+ m_NumberOfSongs(5){}
+
+ int get_current_song(){return m_SongIndex;}
+ int m_SongIndex;
+ int m_NumberOfSongs;
+
+};
+typedef msm::back::state_machine<PlayingMode_> PlayingMode;
+
+#endif // PLAYING_MODE_HPP
Added: trunk/libs/msm/doc/PDF/examples/iPod_distributed/iPod.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/iPod_distributed/iPod.cpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,234 @@
+#include <vector>
+#include <set>
+#include <string>
+#include <iostream>
+#define FUSION_MAX_VECTOR_SIZE 20
+
+#include "boost/mpl/vector/vector50.hpp"
+#include <boost/msm/back/state_machine.hpp>
+#include <boost/msm/front/state_machine_def.hpp>
+
+#include "Events.hpp"
+#include "PlayingMode.hpp"
+#include "MenuMode.hpp"
+
+using namespace std;
+namespace msm = boost::msm;
+
+namespace // Concrete FSM implementation
+{
+ struct iPod_;
+ typedef msm::back::state_machine<iPod_,
+ ::boost::msm::back::NoHistory,
+ ::boost::msm::back::favor_compile_time> iPod;
+
+ // Concrete FSM implementation
+ struct iPod_ : public msm::front::state_machine_def<iPod_>
+ {
+ // The list of FSM states
+ struct NotHolding : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NotHolding" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotHolding" << std::endl;}
+ };
+ struct Holding : public msm::front::interrupt_state<NoHold>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: Holding" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: Holding" << std::endl;}
+ };
+ struct NotPlaying : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NotPlaying" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NotPlaying" << std::endl;}
+ };
+ struct NoMenuMode : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NoMenuMode" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoMenuMode" << std::endl;}
+ };
+ struct NoOnOffButton : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: NoOnOffButton" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: NoOnOffButton" << std::endl;}
+ };
+ struct OffDown : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: OffDown, start timer" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: OffDown, end timer" << std::endl;}
+ };
+ struct PlayerOff : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: PlayerOff" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: PlayerOff" << std::endl;}
+ };
+ struct CheckMiddleButton : public msm::front::state<>
+ {
+ template <class Event,class FSM>
+ void on_entry(Event const&,FSM& ) {std::cout << "starting: CheckMiddleButton" << std::endl;}
+ template <class Event,class FSM>
+ void on_exit(Event const&,FSM& ) {std::cout << "finishing: CheckMiddleButton" << std::endl;}
+ };
+
+ // the initial state of the player SM. Must be defined
+ typedef mpl::vector5<NotHolding,NotPlaying,NoMenuMode,NoOnOffButton,CheckMiddleButton>
+ initial_state;
+ // transition actions
+ void send_ActivateMenu(EndPlay const&)
+ {
+ std::cout << "leaving Playing" << std::endl;
+ // we need to activate the menu and simulate its button
+ (static_cast<iPod*>(this))->process_event(MenuButton());
+ }
+ void send_StartSong(CloseMenu const&)
+ {
+ // we suppose the 5th song was selected
+ (static_cast<iPod*>(this))->process_event(StartSong(5));
+ }
+ void send_PlayPause(SouthReleased const&)
+ {
+ // action using the message queue to generate another event
+ (static_cast<iPod*>(this))->process_event(PlayPause());
+ }
+ void send_Off(OnOffTimer const&)
+ {
+ std::cout << "turning player off" << std::endl;
+ (static_cast<iPod*>(this))->process_event(Off());
+ }
+ void send_PlayingMiddleButton(MiddleButton const&)
+ {
+ (static_cast<iPod*>(this))->process_event(PlayingMiddleButton());
+ }
+ void send_MenuMiddleButton(MiddleButton const&)
+ {
+ (static_cast<iPod*>(this))->process_event(MenuMiddleButton());
+ }
+ // guard conditions
+ bool is_menu(MiddleButton const&)
+ {
+ return (static_cast<iPod*>(this))->is_flag_active<MenuActive>();
+ }
+ bool is_no_menu(MiddleButton const& evt)
+ {
+ return !is_menu(evt);
+ }
+ template <class EVENT>
+ void switch_on(EVENT const&)
+ {
+ std::cout << "turning player on" << std::endl;
+ }
+ typedef iPod_ fsm; // makes transition table cleaner
+
+ // Transition table for player
+ struct transition_table : mpl::vector<
+ // Start Event Next Action Guard
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NotHolding , Hold , Holding >,
+ _row < Holding , NoHold , NotHolding >,
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NotPlaying , PlayPause , PlayingMode >,
+ a_row < PlayingMode::exit_pt<PlayingMode_::
+ PlayingExit> , EndPlay , NotPlaying , &fsm::send_ActivateMenu >,
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NoMenuMode , MenuButton , MenuMode >,
+ a_row < MenuMode::exit_pt<MenuMode_::
+ MenuExit> , CloseMenu , NoMenuMode , &fsm::send_StartSong >,
+ // +-------------------+---------------+-------------------+--------------------------------+----------------------+
+ _row < NoOnOffButton , SouthPressed , OffDown >,
+ a_row < OffDown , SouthReleased , NoOnOffButton , &fsm::send_PlayPause >,
+ a_row < OffDown , OnOffTimer , PlayerOff , &fsm::send_Off >,
+ a_row < PlayerOff , SouthPressed , NoOnOffButton , &fsm::switch_on >,
+ a_row < PlayerOff , NoHold , NoOnOffButton , &fsm::switch_on >,
+ // +-------------------+---------------+--------------------+--------------------------------+----------------------+
+ row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_PlayingMiddleButton , &fsm::is_menu >,
+ row < CheckMiddleButton , MiddleButton , CheckMiddleButton , &fsm::send_MenuMiddleButton , &fsm::is_no_menu >
+ // +-------------------+---------------+--------------------+--------------------------------+----------------------+
+ > {};
+
+ // Replaces the default no-transition response.
+ template <class FSM,class Event>
+ void no_transition(Event const& e, FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+ };
+
+ void test()
+ {
+ iPod sm;
+ sm.start();
+ // we first press Hold
+ std::cout << "pressing hold" << std::endl;
+ sm.process_event(Hold());
+ // pressing a button is now ignored
+ std::cout << "pressing a button" << std::endl;
+ sm.process_event(SouthPressed());
+ // or even one contained in a submachine
+ sm.process_event(EastPressed());
+ // no more holding
+ std::cout << "no more holding, end interrupt event sent" << std::endl;
+ sm.process_event(NoHold());
+ std::cout << "pressing South button a short time" << std::endl;
+ sm.process_event(SouthPressed());
+ // we suppose a short pressing leading to playing a song
+ sm.process_event(SouthReleased());
+ // we move to the next song
+ std::cout << "we move to the next song" << std::endl;
+ sm.process_event(NextSong());
+ // then back to no song => exit from playing, menu active
+ std::cout << "we press twice the West button (simulated)=> end of playing" << std::endl;
+ sm.process_event(PreviousSong());
+ sm.process_event(PreviousSong());
+ // even in menu mode, pressing play will start playing the first song
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(SouthReleased());
+ // of course pausing must be possible
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(SouthReleased());
+ std::cout << "pressing play/pause" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(SouthReleased());
+ // while playing, you can fast forward
+ std::cout << "pressing East button a long time" << std::endl;
+ sm.process_event(EastPressed());
+ // let's suppose the timer just fired
+ sm.process_event(ForwardTimer());
+ sm.process_event(ForwardTimer());
+ // end of fast forwarding
+ std::cout << "releasing East button" << std::endl;
+ sm.process_event(EastReleased());
+ // we now press the middle button to set playing at a given position
+ std::cout << "pressing Middle button, fast forwarding disabled" << std::endl;
+ sm.process_event(MiddleButton());
+ std::cout <<"pressing East button to fast forward" << std::endl;
+ sm.process_event(EastPressed());
+ // we switch off and on
+ std::cout <<"switch off player" << std::endl;
+ sm.process_event(SouthPressed());
+ sm.process_event(OnOffTimer());
+ std::cout <<"switch on player" << std::endl;
+ sm.process_event(SouthPressed());
+ }
+}
+
+int main()
+{
+ test();
+ return 0;
+}
Added: trunk/libs/msm/doc/PDF/examples/ipod_functors.hpp
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/ipod_functors.hpp 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,238 @@
+#ifndef IPOD_FUNCTORS_HPP
+#define IPOD_FUNCTORS_HPP
+#include <boost/msm/front/euml/euml.hpp>
+
+BOOST_MSM_EUML_ACTION(NotHolding_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NotHolding" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Holding_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Holding" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NotPlaying_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NotPlaying" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NoMenuMode_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NoMenuMode" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NoOnOffButton_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NoOnOffButton" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(OffDown_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: OffDown" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(PlayerOff_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: PlayerOff" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(CheckMiddleButton_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: CheckMiddleButton" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Playing_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM& fsm,STATE& )
+ {
+ std::cout << "entering: Playing" << std::endl;
+ std::cout << "playing song:" << fsm.get_attribute(m_SongIndex) << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(WaitingForNextPrev_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: WaitingForNextPrev" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Paused_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Paused" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(WaitingForEnd_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: OffDown" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(NoForward_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: NoForward" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(ForwardPressed_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: ForwardPressed" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(ForwardPressed_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: ForwardPressed" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(FastForward_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: FastForward" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(FastForward_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: FastForward" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(StdDisplay_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: StdDisplay" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(SetPosition_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SetPosition" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(SetMark_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: SetMark" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(PlayingExit_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: PlayingExit" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(WaitingForSongChoice_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: WaitingForSongChoice" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(StartCurrentSong_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: StartCurrentSong" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(MenuExit_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: MenuExit" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_selected_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "selecting song:" << fsm.get_attribute(m_SongIndex) << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(do_fast_forward)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "moving song forward..." << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_playing_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "playing song:" << fsm.get_attribute(m_SongIndex) << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_player_off)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "turning player off" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(show_player_on)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM& fsm,SourceState& ,TargetState& )
+ {
+ std::cout << "turning player on" << std::endl;
+ }
+};
+#endif
\ No newline at end of file
Added: trunk/libs/msm/doc/PDF/examples/logging_functors.h
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/PDF/examples/logging_functors.h 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,360 @@
+#ifndef LOGGING_FUNCTORS
+#define LOGGING_FUNCTORS
+
+BOOST_MSM_EUML_ACTION(Empty_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Empty" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Empty_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Empty" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Open_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Open" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Open_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Open" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Stopped_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Stopped" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Stopped_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Stopped" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(AllOk_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: AllOk" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(AllOk_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: AllOk" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(ErrorMode_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: ErrorMode" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(ErrorMode_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: ErrorMode" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Playing_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "entering: Playing" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Playing_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "leaving: Playing" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Song1_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: First song" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Song1_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: First Song" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Song2_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Second song" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Song2_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Second Song" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Song3_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Third song" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Song3_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Third Song" << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(Region2State1_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Region2State1" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Region2State1_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Region2State1" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Region2State2_Entry)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "starting: Region2State2" << std::endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(Region2State2_Exit)
+{
+ template <class Event,class FSM,class STATE>
+ void operator()(Event const&,FSM&,STATE& )
+ {
+ std::cout << "finishing: Region2State2" << std::endl;
+ }
+};
+// transition actions for Playing
+BOOST_MSM_EUML_ACTION(start_next_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::start_next_song" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(start_prev_song)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ std::cout << "Playing::start_prev_song" << endl;
+ }
+};
+
+// transition actions
+BOOST_MSM_EUML_ACTION(start_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::start_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(open_drawer)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::open_drawer" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(close_drawer)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::close_drawer" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(store_cd_info)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ // it is now easy to use the message queue.
+ // alternatively to the proces_ in the transition table, we could write:
+ // fsm.process_event(play());
+ }
+};
+BOOST_MSM_EUML_ACTION(stop_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(pause_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::pause_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(resume_playback)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::resume_playback" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(stop_and_open)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::stop_and_open" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(stopped_again)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::stopped_again" << endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(report_error)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::report_error" << endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(report_end_error)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
+ {
+ cout << "player::report_end_error" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_action1)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal action1" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_action2)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal action2" << endl;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_action)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ void operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal action" << endl;
+ }
+};
+enum DiskTypeEnum
+{
+ DISK_CD=0,
+ DISK_DVD=1
+};
+
+// Handler called when no_transition detected
+BOOST_MSM_EUML_ACTION(Log_No_Transition)
+{
+ template <class FSM,class Event>
+ void operator()(Event const& e,FSM&,int state)
+ {
+ std::cout << "no transition from state " << state
+ << " on event " << typeid(e).name() << std::endl;
+ }
+};
+
+BOOST_MSM_EUML_ACTION(internal_guard1)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal guard1" << endl;
+ return false;
+ }
+};
+BOOST_MSM_EUML_ACTION(internal_guard2)
+{
+ template <class FSM,class EVT,class SourceState,class TargetState>
+ bool operator()(EVT const&, FSM& ,SourceState& ,TargetState& )
+ {
+ cout << "Open::internal guard2" << endl;
+ return false;
+ }
+};
+#endif // LOGGING_FUNCTORS
Added: trunk/libs/msm/doc/PDF/msm.pdf
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/AnnexA.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/Anonymous.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/CompositeTutorial.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/FlagsTutorial.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/HistoryTutorial.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/Orthogonal-deferred.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/ParsingDigits.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/SimpleTutorial.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/completion.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/conflict1.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/conflict2.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/entry tutorial.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/entry_point.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/error_no_regions.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/exit.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/explicit.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/fork.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/history.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/init_state.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/regions.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/sm.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/state.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/terminate.gif
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/images/transition.jpg
==============================================================================
Binary file. No diff available.
Added: trunk/libs/msm/doc/src/msm.xml
==============================================================================
--- (empty file)
+++ trunk/libs/msm/doc/src/msm.xml 2010-05-21 17:15:38 EDT (Fri, 21 May 2010)
@@ -0,0 +1,8207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?oxygen RNGSchema="http://www.oasis-open.org/docbook/xml/5.0/rng/docbook.rng" type="xml"?>
+<book xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" version="5.0">
+ <info>
+ <title>Meta State Machine (MSM) V2.10</title>
+ <author>
+ <personname>Christophe Henry</personname>
+ <email>christophe.j.henry_at_[hidden]</email>
+ </author>
+ <copyright>
+ <year>2008-2010</year>
+ <holder>
+ <phrase> Distributed under the Boost Software License, Version 1.0. (See
+ accompanying file LICENSE_1_0.txt or copy at <link
+ xlink:href="http://www.boost.org/LICENSE_1_0.txt"
+ >http://www.boost.org/LICENSE_1_0.txt> ) </phrase>
+ </holder>
+ </copyright>
+ </info>
+ <preface>
+ <title>Preface</title>
+ <para>MSM is a library allowing you to easily and quickly define state machines of very high
+ performance. From this point, two main questions usually quickly arise, so please allow
+ me to try answering them upfront.</para>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>When do I need a state machine?</para>
+ <para>More often that you think. Very often, one defined a state machine
+ informally without even noticing it. For example, one declares inside a
+ class some boolean attribute, say to remember that a task has been
+ completed. Later the boolean actually needs a third value, so it becomes an
+ int. A few weeks, a second attribute is needed. Then a third. Soon, you find
+ yourself writing:</para>
+ <para><code>void incoming_data(data)</code></para>
+ <para><code>{</code></para>
+ <para><code> if (data == packet_3 && flag1 == work_done && flag2
+ > step3)...</code></para>
+ <para><code>}</code></para>
+ <para>This starts to look like event processing (contained inside data) if some
+ stage of the object life has been achieved (but is ugly).</para>
+ <para>This could be a protocol definition and it is a common use case for state
+ machines. Another common one is a user interface. The stage of the user's
+ interaction defines if some button is active, a functionality is available,
+ etc.</para>
+ <para>But there are many more use cases if you start looking. Actually, a whole
+ model-driven development method, Executable UML
+ (http://en.wikipedia.org/wiki/Executable_UML) specifies its complete dynamic
+ behavior using state machines. Class diagram, state machine diagrams, and an
+ action language are all you absolutely need in the Executable UML
+ world.</para>
+ </listitem>
+ <listitem>
+ <para>Another state machine library? What for?</para>
+ <para>True, there are many state machine libraries. This should already be an
+ indication that if you're not using any of them, you might be missing
+ something. Why should you use this one? Unfortunately, when looking for a
+ good state machine library, you usually pretty fast hit one or several of
+ the following snags:<itemizedlist>
+ <listitem>
+ <para>speed: "state machines are slow" is usually the first
+ criticism you might hear. While it is often an excuse not to use
+ any and instead resort to dirty, hand-written implementations (I
+ mean, no, yours are not dirty of course, I'm talking about other
+ developers). MSM removes this often feeble excuse because it is
+ blazingly fast. Most hand-written implementations will be beaten
+ by MSM.</para>
+ </listitem>
+ <listitem>
+ <para>ease of use: good argument. If you used another library, you
+ are probably right. Many state machine definitions will look
+ similar to:</para>
+ <para><code>state s1 = new State; // a state</code></para>
+ <para><code>state s2 = new State; // another state</code></para>
+ <para><code>event e = new Event; // event</code></para>
+ <para><code>s1->addTransition(e,s2); // transition s1 ->
+ s2</code></para>
+ <para>The more transitions you have, the less readable it is. A long
+ time ago, there was not so much Java yet, and many electronic
+ systems were built with a state machine defined by a simple
+ transition table. You could easily see the whole structure and
+ immediately see if you forgot some transitions. Thanks to our
+ new OO techniques, this ease of use was gone. MSM gives you back
+ the transition table and reduces the noise to the
+ minimum.</para>
+ </listitem>
+ <listitem>
+ <para>expressiveness: MSM offers several front-ends and constantly
+ tries to improve state machine definition techniques. For
+ example, you can define a transition with eUML (one of MSM's
+ front-ends) as:</para>
+ <para><code>state1 == state2 + event [condition] /
+ action</code></para>
+ <para>This is not simply syntactic sugar. Such a formalized,
+ readable structure allows easy communication with domain experts
+ of a software to be constructed. Having domain experts
+ understand your code will greatly reduce the number of
+ bugs.</para>
+ </listitem>
+ <listitem>
+ <para>model-driven-development: a common difficulty of a
+ model-driven development is the complexity of making a
+ round-trip (generating code from model and then model from
+ code). This is due to the fact that if a state machine structure
+ is hard for you to read, chances are that your parsing tool will
+ also have a hard time. MSM's syntax will hopefully help tool
+ writers.</para>
+ </listitem>
+ <listitem>
+ <para>features: most developers use only 20% of the richly defined
+ UML standard. Unfortunately, these are never the same 20% for
+ all. And so, very likely, one will need something from the
+ standard which is not implemented. MSM offers a very large part
+ of the standard, with more on the way.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>Let us not wait any longer, I hope you will enjoy MSM and have fun with
+ it!</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </preface>
+ <part>
+ <title>User' guide</title>
+ <chapter>
+ <title>Founding idea</title>
+ <para>Let's start with an example taken from the C++ Template Metaprogramming
+ book:</para>
+ <para>
+ <code>class player : public state_machine<player></code></para>
+ <para><code>{ </code></para>
+ <para><code>// The list of FSM states enum states { Empty, Open, Stopped, Playing,
+ Paused , initial_state = Empty }; </code></para>
+ <para><code>// transition actions void start_playback(play const&) { std::cout
+ << "player::start_playback\n"; } </code></para>
+ <para><code>void open_drawer(open_close const&) { std::cout <<
+ "player::open_drawer\n"; } </code></para>
+ <para><code>void close_drawer(open_close const&) { std::cout <<
+ "player::close_drawer\n"; } </code></para>
+ <para><code>void store_cd_info(cd_detected const&) { std::cout <<
+ "player::store_cd_info\n"; } </code></para>
+ <para><code>void stop_playback(stop const&) { std::cout <<
+ "player::stop_playback\n"; } </code></para>
+ <para><code>void pause_playback(pause const&) { std::cout <<
+ "player::pause_playback\n"; } </code></para>
+ <para><code>void resume_playback(play const&) { std::cout <<
+ "player::resume_playback\n"; } </code></para>
+ <para><code>void stop_and_open(open_close const&) { std::cout <<
+ "player::stop_and_open\n"; } </code></para>
+ <para><code>friend class state_machine<player>; </code></para>
+ <para><code>typedef player p; // makes transition table cleaner </code></para>
+ <para><code>// Transition table </code></para>
+ <para><code>struct transition_table : mpl::vector11< </code></para>
+ <para><code>row < Stopped , play , Playing , &p::start_playback >, </code></para>
+ <para><code>row < Stopped , open_close , Open , &p::open_drawer >, </code></para>
+ <para><code>row < Open , open_close , Empty , &p::close_drawer >, </code></para>
+ <para><code>row < Empty , open_close , Open , &p::open_drawer >, </code></para>
+ <para><code>row < Empty , cd_detected , Stopped , &p::store_cd_info >,
+ </code></para>
+ <para><code>row < Playing , stop , Stopped , &p::stop_playback >, </code></para>
+ <para><code>row < Playing , pause , Paused , &p::pause_playback >, </code></para>
+ <para><code>row < Playing , open_close , Open , &p::stop_and_open >,
+ </code></para>
+ <para><code>row < Paused , play , Playing , &p::resume_playback >, </code></para>
+ <para><code>row < Paused , stop , Stopped , &p::stop_playback >, </code></para>
+ <para><code>row < Paused , open_close , Open , &p::stop_and_open > </code></para>
+ <para><code>> {}; </code></para>
+ <para><code>// Replaces the default no-transition response. </code></para>
+ <para><code>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; } };</code>
+ </para>
+ <para><code>void test() { player p; p.process_event(open_close());...}</code></para>
+ <para>This example is the foundation for the idea driving MSM: a descriptive and
+ expressive language based on a transition table with as little syntactic noise as
+ possible, all this while offering as many features from the UML 2.0 standard as
+ possible. MSM also offers several expressive state machine definition syntaxes with
+ different trade-offs.</para>
+ </chapter>
+ <chapter>
+ <title>UML Short Guide</title>
+ <sect1>
+ <title>What are state machines?</title>
+ <para>State machines are the description of a thing's lifeline. They describe the
+ different stages of the lifeline, the events influencing it, and what it does
+ when a particular event is detected at a particular stage. They offer the
+ complete specification of the dynamic behavior of the thing.</para>
+ </sect1>
+ <sect1>
+ <title>Concepts</title>
+ <para>Thinking in terms of state machines is a bit surprising at first, so let us
+ have a quick glance at the concepts.</para>
+ <sect2>
+ <title>State machine, state, transition, event </title>
+ <para>A state machine is a concrete model describing the behavior of a system.
+ It is composed of a finite number of states and transitions.</para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/sm.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>A simple state has no sub states. It can have data, entry and exit
+ behaviors and deferred events. One can provide entry and exit behaviors
+ (also called actions) to states (or state machines), which are executed
+ whenever a state is entered or left, no matter how. A state can also have
+ internal transitions which cause no entry or exit behavior to be called. A
+ state can mark events as deferred. This means the event cannot be processed
+ if this state is active, but it must be retained. Next time a state not
+ deferring this event is active, the event will be processed, as if it had
+ just been fired. </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/state.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>A transition is the switching between active states, triggered by an
+ event. Actions and guard conditions can be attached to the transition. The
+ action executes when the transition fires, the guard is a Boolean operation
+ executed first and which can prevent the transition from firing by returning
+ false.</para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/transition.jpg"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>An initial state marks the first active state of a state machine. It has
+ no real existence and neither has the transition originating from it.</para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/init_state.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ </sect2>
+ <sect2>
+ <title>Submachines, orthogonal regions, pseudostates </title>
+ <para>A composite state is a state containing a region or decomposed in two or
+ more regions. A composite state contains its own set of states and regions. </para>
+ <para>A submachine is a state machine inserted as a state in another state
+ machine. The same submachine can be inserted more than once. </para>
+ <para>Orthogonal regions are parts of a composite state or submachine, each
+ having its own set of mutually exclusive set of states and transitions. </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/regions.gif" width="60%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>UML also defines a number of pseudo states, which are considered important
+ concepts to model, but not enough to make them first-class citizens. The
+ terminate pseudo state terminates the execution of a state machine (MSM
+ handles this slightly differently. The state machine is not destroyed but no
+ further event processing occurs.). </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/terminate.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>An exit point pseudo state exits a composite state or a submachine and
+ forces termination of execution in all contained regions.</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/exit.gif" width="60%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>An entry point pseudo state allows a kind of controlled entry inside a
+ composite. Precisely, it connects a transition outside the composite to a
+ transition inside the composite. An important point is that this mechanism
+ only allows a single region to be entered. In the above diagram, in region1,
+ the initial state would become active. </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/entry_point.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>There are also two more ways to enter a submachine (apart the obvious and
+ more common case of a transition terminating on the submachine as shown in
+ the region case). An explicit entry means that an inside state is the target
+ of a transition. Unlike with direct entry, no tentative encapsulation is
+ made, and only one transition is executed. An explicit exit is a transition
+ from an inner state to a state outside the submachine (not supported by
+ MSM). I would not recommend using explicit entry or exit. </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/explicit.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>The last entry possibility is using fork. A fork is an explicit entry into
+ one or more regions. Other regions are again activated using their initial
+ state. </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/fork.gif" width="70%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ </sect2>
+ <sect2>
+ <title>
+ <command xml:id="uml-history"/>History </title>
+ <para>UML defines two kinds of history, shallow history and deep history.
+ Shallow history is a pseudo state representing the most recent substate of a
+ submachine. A submachine can have at most one shallow history. A transition
+ with a history pseudo state as target is equivalent to a transition with the
+ most recent substate as target. And very importantly, only one transition
+ may originate from the history. Deep history is a shallow history
+ recursively reactivating the substates of the most recent substate. It is
+ represented like the shallow history with a star (H* inside a
+ circle).</para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/history.gif" width="60%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>History is not a completely satisfying concept. First of all, there can be
+ just one history pseudo state and only one transition may originate from it.
+ So they do not mix well with orthogonal regions as only one region can be
+ ârememberedâ. Deep history is even worse and looks like a last-minute
+ addition. History has to be activated by a transition and only one
+ transition originates from it, so how to model the transition originating
+ from the deep history pseudo state and pointing to the most recent substate
+ of the substate? As a bonus, it is also inflexible and does not accept new
+ types of histories. Let's face it, history sounds great and is useful in
+ theory, but the UML version is not quite making the cut. And therefore, MSM
+ provides a different version of this useful concept. </para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="uml-anonymous"/>Completion transitions / anonymous
+ transitions</title>
+ <para>Completion events (or transitions), also called anonymous transitions, are
+ defined as transitions having no defined event triggering them. This means
+ that such transitions will immediately fire when a state being the source of
+ an anonymous transition becomes active, provided that a guard allows it.
+ They are useful in modeling algorithms as an activity diagram would normally
+ do. In the real-time world, they have the advantage of making it easier to
+ estimate how long a periodically executed action will last. For example,
+ consider the following diagram. </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/completion.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>The designer now knows at any time that he will need a maximum of 4
+ transitions. Being able to estimate how long a transition takes, he can
+ estimate how much of a time frame he will need to require (real-time tasks
+ are often executed at regular intervals). If he can also estimate the
+ duration of actions, he can even use graph algorithms to better estimate his
+ timing requirements. </para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="UML-internal-transition"/> Internal transitions </title>
+ <para>Internal transitions are transitions executing in the scope of the active
+ state, being a simple state or a submachine. One can see them as a
+ self-transition of this state, without an entry or exit action
+ called.</para>
+ </sect2>
+ <sect2>
+ <title>
+ <command xml:id="transition-conflict"/>Conflicting transitions </title>
+ <para>If, for a given event, several transitions are enabled, they are said to
+ be in conflict. There are two kinds of conflicts: <itemizedlist>
+ <listitem>
+ <para>For a given source state, several transitions are defined,
+ triggered by the same event. Normally, the guard condition in
+ each transition defines which one is fired.</para>
+ </listitem>
+ <listitem>
+ <para>The source state is a submachine or simple state and the
+ conflict is between a transition internal to this state and a
+ transition triggered by the same event and having as target
+ another state.</para>
+ </listitem>
+ </itemizedlist>The first one is simple; one only needs to define two or more
+ rows in the transition table, with the same source and trigger, with a
+ different guard condition. Beware, however, that the UML standard wants
+ these conditions to be not overlapping. If they do, the standard says
+ nothing except that this is incorrect, so the implementer is free to
+ implement it the way he sees fit. In the case of MSM, the transition
+ appearing last in the transition table gets selected first, if it returns
+ false (meaning disabled), the library tries with the previous one, and so
+ on.</para>
+ <para>
+ <inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/conflict1.gif"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>In the second case, UML defines that the most inner transition gets
+ selected first, which makes sense, otherwise no exit point pseudo state
+ would be possible (the inner transition brings us to the exit point, from
+ where the containing state machine can take over). </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/conflict2.gif" width="60%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>MSM handles both cases itself, so the designer needs only concentrate on
+ its state machine and the UML subtleties (not overlapping conditions), not
+ on implementing this behavior himself. </para>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title>State machine glossary</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>state machine: the life cycle of a thing. It is made of states,
+ regions, transitions and processes incoming events.</para>
+ </listitem>
+ <listitem>
+ <para>state: a stage in the life cycle of a state machine. A state (like
+ a submachine) can have an entry and exit behaviors.</para>
+ </listitem>
+ <listitem>
+ <para>event: an incident provoking (or not) a reaction of the state
+ machine</para>
+ </listitem>
+ <listitem>
+ <para>transition: a specification of how a state machine reacts to an
+ event. It specifies a source state, the event triggering the
+ transition, the target state (which will become the newly active
+ state if the transition is triggered), guard and actions.</para>
+ </listitem>
+ <listitem>
+ <para>action: an operation executed during the triggering of the
+ transition.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a boolean operation being able to prevent the triggering of
+ a transition which would otherwise fire.</para>
+ </listitem>
+ <listitem>
+ <para>transition table: representation of a state machine. A state
+ machine diagram is a graphical, but incomplete representation of the
+ same model. A transition table, on the other hand, is a complete
+ representation.</para>
+ </listitem>
+ <listitem>
+ <para>initial state: The state in which the state machine starts. Having
+ several orthogonal regions means having as many initial
+ states.</para>
+ </listitem>
+ <listitem>
+ <para>submachine: A submachine is a state machine inserted as a state in
+ another state machine and can be found several times in a same state
+ machine.</para>
+ </listitem>
+ <listitem>
+ <para>orthogonal regions: (logical) parallel flow of execution of a
+ state machine. Every region of a state machine gets a chance to
+ process an incoming event.</para>
+ </listitem>
+ <listitem>
+ <para>terminate pseudo-state: when this state becomes active, it
+ terminates the execution of the whole state machine. MSM does not
+ destroy the state machine as required by the UML standard, however,
+ which lets you keep all the state machine's data.</para>
+ </listitem>
+ <listitem>
+ <para>entry/exit pseudo state: defined for submachines and are defined
+ as a connection between a transition outside of the submachine and a
+ transition inside the submachine. It is a way to enter or leave a
+ submachine through a predefined point.</para>
+ </listitem>
+ <listitem>
+ <para>fork: a fork allows explicit entry into several orthogonal regions
+ of a submachine.</para>
+ </listitem>
+ <listitem>
+ <para>history: a history is a way to remember the active state of a
+ submachine so that the submachine can proceed in its last active
+ state next time it becomes active.</para>
+ </listitem>
+ <listitem>
+ <para>completion events (also called completion/anonymous transitions):
+ when a transition has no named event triggering it, it automatically
+ fires when the source state is active, unless a guard forbids
+ it.</para>
+ </listitem>
+ <listitem>
+ <para>transition conflict: a conflict is present if for a given source
+ state and incoming event, several transitions are possible. UML
+ specifies that guard conditions have to solve the conflict.</para>
+ </listitem>
+ <listitem>
+ <para>internal transitions: transition from a state to itself without
+ having exit and entry actions being called.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+ </chapter>
+ <chapter>
+ <title>Tutorial</title>
+ <sect1>
+ <title>Design</title>
+ <para>MSM is divided between frontâends and back-ends. At the moment, there is just
+ one back-end. On the front-end side, you will find three of them which are as
+ many state machine description languages, with many more possible. For potential
+ language writers, this document contains a <link
+ xlink:href="#internals-front-back-interface">description of the interface
+ between front-end and back-end</link>.</para>
+ <para>The first front-end is an adaptation of the example provided in the <link
+ xlink:href="http://boostpro.com/mplbook">MPL book</link> with actions
+ defined as pointers to state or state machine methods. The second one is based
+ on functors. The third, eUML (embedded UML) is an experimental language based on
+ Boost.Proto and Boost.Typeof and hiding most of the metaprogramming to increase
+ readability. Both eUML and the functor front-end also offer a functional library
+ (a bit like Boost.Phoenix) for use as action language (UML defining
+ none).</para>
+ </sect1>
+ <sect1>
+ <title><command xml:id="basic-front-end"/>Basic front-end</title>
+ <para>This is the historical front-end, inherited from the MPL book. It provides a
+ transition table made of rows of different names and functionality. Actions and
+ guards are defined as methods and referenced through a pointer in the
+ transition. This front-end provides a simple interface making easy state
+ machines easy to define, but more complex state machines a bit harder.</para>
+ <sect2>
+ <title>A simple example</title>
+ <para>Let us have a look at a state machine diagram of the founding
+ example:</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/SimpleTutorial.jpg" width="60%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>We are now going to build it with MSM's basic front-end. An <link
+ xlink:href="examples/SimpleTutorial.cpp">implementation</link> is also
+ provided.</para>
+ </sect2>
+ <sect2>
+ <title>Transition table</title>
+ <para>As previously stated, MSM is based on the transition table, so let us
+ define one:</para>
+ <para>struct transition_table : mpl::vector<</para>
+ <para>
+ <informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Stopped ,</td>
+ <td>play,</td>
+ <td>Playing,</td>
+ <td>&player_::start_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Stopped ,</td>
+ <td>open_close,</td>
+ <td>Open,</td>
+ <td>&player_::open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>_row <</td>
+ <td>Stopped ,</td>
+ <td>stop,</td>
+ <td>Stopped</td>
+ <td> </td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Open ,</td>
+ <td>open_close ,</td>
+ <td>Empty ,</td>
+ <td>&player_::close_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Empty ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::store_cd_info ,</td>
+ <td>&player_::good_disk_format</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Playing ,</td>
+ <td>&player_::store_cd_info ,</td>
+ <td>&player_::auto_start</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::stop_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>pause ,</td>
+ <td>Paused ,</td>
+ <td>&player_::pause_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Playing ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::stop_and_open</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>end_pause ,</td>
+ <td>Playing ,</td>
+ <td>&player_::resume_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>&player_::stop_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td> Paused ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>&player_::stop_and_open</td>
+ <td> </td>
+ <td>></td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </para>
+ <para>You will notice that this is almost exactly our founding example. The only
+ change in the transition table is the different types of transitions (rows).
+ The founding example forces one to define an action method and offers no
+ guards. You have 4 basic row types:<itemizedlist>
+ <listitem>
+ <para><code>row</code> takes 5 arguments: start state, event, target
+ state, action and guard.</para>
+ </listitem>
+ <listitem>
+ <para><code>a_row</code> (âaâ for action) allows defining only the
+ action and omit the guard condition.</para>
+ </listitem>
+ <listitem>
+ <para><code>g_row</code> (âgâ for guard) allows omitting the action
+ behavior and defining only the guard.</para>
+ </listitem>
+ <listitem>
+ <para><code>_row</code> allows omitting action and guard.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>The signature for an action methods is void method_name (event
+ const&), for example:</para>
+ <programlisting>void stop_playback(stop const&)</programlisting>
+ <para>Action methods return nothing and take the argument as const reference. Of
+ course nothing forbids you from using the same action for several
+ events:</para>
+ <programlisting>template <class Event> void stop_playback(Eventconst&)</programlisting>
+ <para>Guards have as only difference the return value, which is a
+ boolean:</para>
+ <programlisting>bool good_disk_format(cd_detected const& evt)</programlisting>
+ <para>The transition table is actually a MPL vector (or list), which brings the
+ limitation that the default maximum size of the table is 20. If you need
+ more transitions, overriding this default behavior is necessary, so you need
+ to add before any header:</para>
+ <programlisting>#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 //or whatever you need
+#define BOOST_MPL_LIMIT_MAP_SIZE 30 //or whatever you need </programlisting>
+ <para>The other limitation is that the MPL types are defined only up to 50
+ entries. For the moment, the only solution to achieve more is to add headers
+ to the MPL (luckily, this is not very complicated).</para>
+ </sect2>
+ <sect2>
+ <title>Defining states with entry/exit actions</title>
+ <para>While states were enums in the MPL book, they now are classes, which
+ allows them to hold data, provide entry, exit behaviors and be reusable (as
+ they do not know anything about the containing state machine). To define a
+ state, inherit from the desired state type. You will mainly use simple
+ states:</para>
+ <para>struct Empty : public msm::front::state<> {};</para>
+ <para>They can optionally provide entry and exit behaviors:</para>
+ <programlisting language="C++">
+struct Empty : public msm::front::state<>
+{
+ template <class Event, class Fsm>
+ void on_entry(Event const&, Fsm& )
+ {std::cout <<"entering: Empty" << std::endl;}
+ template <class Event, class Fsm>
+ void on_exit(Event const&, Fsm& )
+ {std::cout <<"leaving: Empty" << std::endl;}
+};
+ </programlisting>
+ <para>Notice how the entry and exit behaviors are templatized on the event and
+ state machine. Being generic facilitates reuse. There are more state types
+ (terminate, interrupt, pseudo states, etc.) corresponding to the UML
+ standard state types. These will be described in details in the next
+ sections.</para>
+ </sect2>
+ <sect2>
+ <title>Defining a simple state machine</title>
+ <para>Declaring a state machine is straightforward and is done with a high
+ signal / noise ratio. In our player example, we declare the state machine
+ as:</para>
+ <programlisting>struct player_ : public msm::front::state_machine_def<player_>{
+ /* see below */}</programlisting>
+ <para>This declares a state machine using the basic front-end. We now declare
+ inside the state machine structure the initial state:</para>
+ <para>
+ <programlisting>typedef Empty initial_state;</programlisting>
+ </para>
+ <para>And that is about all of what is absolutely needed. In the example, the
+ states are declared inside the state machine for readability but this is not
+ a requirements, states can be declared wherever you like.</para>
+ <para>All what is left to do is to pick a back-end (which is quite simple as
+ there is only one at the moment):</para>
+ <para>
+ <programlisting>typedef msm::back::state_machine<player_> player;</programlisting>
+ </para>
+ <para>You now have a ready-to-use state machine with entry/exit actions, guards,
+ transition actions, a message queue so that processing an event can generate
+ another event. The state machine also adapted itself to your need and
+ removed almost all features we didn't use in this simple example. Note that
+ this is not per default the fastest possible state machine. See the section
+ "getting more speed" to know how to get the maximum speed. In a nutshell,
+ MSM cannot know about your usage of some features so you will have to
+ explicitly tell it.</para>
+ <para>State objects are built automatically with the state machine. They will
+ exist until state machine destruction. MSM is using Boost.Fusion behind the
+ hood. This unfortunately means that if you define more than 10 states, you
+ will need to extend the default:</para>
+ <para>
+ <programlisting>#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need
+ </programlisting>
+ </para>
+ <para>When an unexpected event is fired, the <code>no_transition(event, state
+ machine, state id)</code> method of the state machine is called . By
+ default, this method simply asserts when called. It is possible to overwrite
+ the <code>no_transition</code> method to define a different handling:</para>
+ <para>
+ <programlisting>template <class Fsm,class Event>
+void no_transition(Event const& e, Fsm& ,int state){...}</programlisting>
+ </para>
+ <para><emphasis role="underline">Note</emphasis>: you might have noticed that
+ the tutorial calls <code>start()</code> on the state machine just after
+ creation. The start method will initiate the state machine, meaning it will
+ activate the initial state, which means in turn that the initial state's
+ entry behavior will be called. The reason why we need this will be explained
+ in the <link xlink:href="#backend-start">back-end part</link>. After a call
+ to start, the state machine is ready to process events.</para>
+ </sect2>
+ <sect2>
+ <title>Defining a submachine</title>
+ <para>We now want to extend our last state machine by making the Playing state a
+ state machine itself (a submachine).</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/CompositeTutorial.jpg" width="60%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>Again, an <link xlink:href="examples/CompositeTutorial.cpp">example</link>
+ is also provided.</para>
+ <para>A submachine really is a state machine itself, so we declare Playing as
+ such, choosing a front-end and a back-end:</para>
+ <para>
+ <programlisting>struct Playing_ : public msm::front::state_machine_def<Playing_>{...}
+typedef msm::back::state_machine<Playing_> Playing;</programlisting>
+ </para>
+ <para>Like for any state machine, one also needs a transition table and an
+ initial state:</para>
+ <para> struct transition_table : mpl::vector<<informaltable>
+ <tbody>
+ <tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>------------------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Song1 ,</td>
+ <td>NextSong,</td>
+ <td>Song2,</td>
+ <td>&Playing_::start_next_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Song2 ,</td>
+ <td>PreviousSong,</td>
+ <td>Song1,</td>
+ <td>&Playing_::start_prev_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Song2 ,</td>
+ <td>NextSong,</td>
+ <td>Song3,</td>
+ <td>&Playing_::start_next_song </td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>a_row <</td>
+ <td>Song3 ,</td>
+ <td>PreviousSong ,</td>
+ <td>Song2 ,</td>
+ <td>&Playing_::start_prev_song </td>
+ <td> </td>
+ <td>></td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>------------------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ </tbody>
+ </informaltable></para>
+ <para>
+ <programlisting>typedef Song1 initial_state; </programlisting>
+ </para>
+ <para>This is about all you need to do. MSM will now automatically recognize
+ Playing as a submachine and all events handled by Playing (NextSong and
+ PreviousSong) will now be automatically forwarded to Playing whenever this
+ state is active. All other state machine features described later are also
+ available. You can even decide to use a state machine sometimes as
+ submachine or sometimes as an independent state machine.</para>
+ </sect2>
+ <sect2>
+ <title>Orthogonal regions, terminate state, event deferring</title>
+ <para>It is a very common problem in many state machines to have to handle
+ errors. It usually involves defining a transition from all the states to a
+ special error state. Translation: not fun. It is also not practical to find
+ from which state the error originated. The following diagram shows an
+ example of what clearly becomes not very readable:</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/error_no_regions.jpg" width="60%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>This is neither very readable nor beautiful. And we do not even have any
+ action on the transitions yet to make it even less readable.</para>
+ <para>Luckily, UML provides a helpful concept, orthogonal regions. See them as
+ lightweight state machines running at the same time inside a common state
+ machine and having the capability to influence one another. The effect is
+ that you have several active states at any time. We can therefore keep our
+ state machine from the previous example and just define a new region made of
+ two states, AllOk and ErrorMode. AllOk is most of the time active. But the
+ error_found error event makes the second region move to the new active state
+ ErrorMode. This event does not interest the main region so it will simply be
+ ignored. "<code>no_transition</code>" will be called only if no region at
+ all handles the event. Also, as UML mandates, every region gets a chance of
+ handling the event, in the order as declared by the
+ <code>initial_state</code> type.</para>
+ <para>Adding an orthogonal region is easy, one only needs to declare more states
+ in the <code>initial_state</code> typedef. So, adding a new region with
+ AllOk as the region's initial state is:</para>
+ <para>
+ <programlisting>typedef mpl::vector<Empty,AllOk> initial_state;</programlisting>
+ </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/Orthogonal-deferred.jpg" width="60%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>Furthermore, when you detect an error, you usually do not want events to
+ be further processed. To achieve this, we use another UML feature, terminate
+ states. When any region moves to a terminate state, the state machine
+ âterminatesâ (the state machine and all its states stay alive) and all
+ events are ignored. This is of course not mandatory, one can use orthogonal
+ regions without terminate states. MSM also provides a small extension to
+ UML, interrupt states. If you declare ErrorMode as interrupt state instead
+ of terminate state, the state machine will not handle any event other than
+ the one which ends the interrupt. So it's like a terminate state, with the
+ difference that you are allowed to resume the state machine when a condition
+ (like handling of the original error) is met. </para>
+ <para><command xml:id="basic-defer"/>Last but not least, this example also shows
+ here the handling of event deferring. Let's say someone puts a disc and
+ immediately presses play. The event cannot be handled, yet you'd want it to
+ be handled at a later point and not force the user to press play again. The
+ solution is to define it as deferred in the Empty and Open states and get it
+ handled in the first state where the event is not to be deferred. It can
+ then be handled or rejected. In this example, when Stopped becomes active,
+ the event will be handled because only Empty and Open defer the
+ event.</para>
+ <para>UML defines event deferring as a state property. To accommodate this, MSM
+ lets you specify this in states by providing a <code>deferred_events</code>
+ type:</para>
+ <programlisting>struct Empty : public msm::front::state<>
+{
+ // if the play event is fired while in this state, defer it until a state
+ // handles or rejects it
+ typedef mpl::vector<play> deferred_events;
+...
+}; </programlisting>
+ <para>Please have a look at the <link
+ xlink:href="examples/Orthogonal-deferred.cpp">complete
+ example</link>.</para>
+ <para>While this is wanted by UML and is simple, it is not always practical
+ because one could wish to defer only in certain conditions. One could also
+ want to make this be part of a transition action with the added bonus of a
+ guard for more sophisticated behaviors. It would also be conform to the MSM
+ philosophy to get as much as possible in the transition table, where you
+ have the whole state machine structure. This is also possible but not
+ practical with this front-end so we will need to pick a different row from
+ the functor front-end. For a complete description of the <code>Row</code>
+ type, please have a look at the <command xlink:href="#functor-front-end"
+ >functor front-end.</command></para>
+ <para>First, as there is no state where MSM can automatically find out the usage
+ of this feature, we need to require deferred events capability explicitly,
+ by adding a type in the state machine definition:</para>
+ <programlisting>struct player_ : public msm::front::state_machine_def<player_>
+{
+ typedef int activate_deferred_events;
+...
+}; </programlisting>
+ <para>We can now defer an event in any transition of the transition table by
+ using as action the predefined <code>msm::front::Defer</code> functor, for
+ example:</para>
+ <para>
+ <programlisting>Row < Empty , play , none , Defer , none ></programlisting>
+ </para>
+ <para>This is an internal transition row(see <command
+ xlink:href="#internal-transitions">internal transitions</command>) but
+ you can ignore this for the moment. It just means that we are not leaving
+ the Empty state. What matters is that we use Defer as action. This is
+ roughly equivalent to the previous syntax but has the advantage of giving
+ you all the information in the transition table with the added power of
+ transition behavior.</para>
+ <para>The second difference is that as we now have a transition defined, this
+ transition can play in the resolution of <command
+ xlink:href="#transition-conflict">transition conflicts</command>. For
+ example, we could model an "if (condition2) move to Playing else if
+ (condition1) defer play event":</para>
+ <para>
+ <programlisting>Row < Empty , play , none , Defer , condition1 >,
+g_row < Empty , play , Playing , &player_::condition2 ></programlisting>
+ </para>
+ <para>Please have a look at <link xlink:href="examples/Orthogonal-deferred2.cpp"
+ >this possible implementation</link>.</para>
+ </sect2>
+ <sect2>
+ <title>History</title>
+ <para>UML defines two types of history, Shallow History and Deep History. In the
+ previous examples, if the player was playing the second song and the user
+ pressed pause, leaving Playing, at the next press on the play button, the
+ Playing state would become active and the first song would play again. Soon
+ would the first client complaints follow. They'd of course demand, that if
+ the player was paused, then it should remember which song was playing. But
+ it the player was stopped, then it should restart from the first song. How
+ can it be done? Of course, you could add a bit of programming logic and
+ generate extra events to make the second song start if coming from Pause.
+ Something like: </para>
+ <para>
+ <programlisting>if (Event == end_pause)
+{
+ for (int i=0;i< song number;++i) {player.process_event(NextSong()); }
+} </programlisting>
+ </para>
+ <para>Not much to like in this example, isn't it? To solve this problem, you
+ define what is called a shallow or a deep history. A shallow history
+ reactivates the last active substate of a submachine when this submachine
+ becomes active again. The deep history does the same recursively, so if this
+ last active substate of the submachine was itself a submachine, its last
+ active substate would become active and this will continue recursively until
+ an active state is a normal state. For example, let us have a look at the
+ following UML diagram: </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/HistoryTutorial.jpg" width="60%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>Notice that the main difference compared to previous diagrams is that the
+ initial state is gone and replaced by a History symbol (the H inside a
+ circle).</para>
+ <para>As explained in the <command xlink:href="#uml-history">small UML
+ tutorial</command>, History is a good concept with a not completely
+ satisfying specification. MSM kept the concept but not the specification and
+ goes another way by making this a policy and you can add your own history
+ types (the <link xlink:href="#history-interface">reference</link> explains
+ what needs to be done). Furthermore, History is a backend policy. This
+ allows you to reuse the same state machine definition with different history
+ policies in different contexts.</para>
+ <para>Concretely, your frontend stays unchanged:</para>
+ <para>
+ <programlisting>struct Playing_ : public msm::front::state_machine_def<Playing_></programlisting>
+ </para>
+ <para>You then add the policy to the backend as second parameter:</para>
+ <para>
+ <programlisting>typedef msm::back::state_machine<Playing_,
+ msm::back::ShallowHistory<mpl::vector<end_pause> > > Playing;</programlisting>
+ </para>
+ <para>This states that a shallow history must be activated if the Playing state
+ machine gets activated by the end_pause event and only this one (or any
+ other event added to the mpl::vector). If the state machine was in the
+ Stopped state and the event play was generated, the history would not be
+ activated and the normal initial state would become active. By default,
+ history is disabled. For your convenience the library provides in addition
+ to ShallowHistory a non-UML standard AlwaysHistory policy (likely to be your
+ main choice) which always activates history, whatever event triggers the
+ submachine activation. Deep history is not available as a policy (but could
+ be added). The reason is that it would conflict with policies which
+ submachines could define. Of course, if for example, Song1 were a state
+ machine itself, it could use the ShallowHistory policy itself thus creating
+ Deep History for itself. An <link xlink:href="examples/History.cpp"
+ >example</link> is also provided.</para>
+ </sect2>
+ <sect2>
+ <title>Completion (anonymous) transitions</title>
+ <para><command xml:id="anonymous-transitions"/>The following diagram shows an
+ example making use of this feature:</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/Anonymous.jpg" width="60%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>Anonymous transitions are transitions without a named event. This means
+ that the transition automatically fires when the predecessor state is
+ entered (to be exact, after the entry action). Otherwise it is a normal
+ transition with actions and guards. Why would you need something like that?
+ A possible case would be if a part of your state machine implements some
+ algorithm, where states are steps of the algorithm implementation. Then,
+ using several anonymous transitions with different guard conditions, you are
+ actually implementing some if/else statement. Another possible use would be
+ a real-time system called at regular intervals and always doing the same
+ thing, meaning implementing the same algorithm. The advantage is that once
+ you know how long a transition takes to execute on the system, by
+ calculating the longest path (the number of transitions from start to end),
+ you can pretty much know how long your algorithm will take in the worst
+ case, which in turns tells you how much of a time frame you are to request
+ from a scheduler. </para>
+ <para>If you are using Executable UML (a good book describing it is "Executable
+ UML, a foundation for Model-Driven Architecture"), you will notice that it
+ is common for a state machine to generate an event to itself only to force
+ leaving a state. Anonymous transitions free you from this constraint.</para>
+ <para>If you do not use this feature in a concrete state machine, MSM will
+ deactivate it and you will not pay for it. If you use it, there is however a
+ small performance penalty as MSM will try to fire a compound event (the
+ other UML name for anonymous transitions) after every taken transition. This
+ will therefore double the event processing cost, which is not as bad as it
+ sounds as MSMâs execution speed is very high anyway.</para>
+ <para>To define such a transition, use ânoneâ as event in the transition table,
+ for example:</para>
+ <para>
+ <programlisting>row < State3 , none , State4 , &p::State3ToState4 , &p::always_true ></programlisting>
+ </para>
+ <para><link xlink:href="examples/AnonymousTutorial.cpp">An implementation</link>
+ of the state machine diagram is also provided.</para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="internal-transitions"/>Internal transitions</title>
+ <para>Internal transitions are transitions executing in the scope of the active
+ state, a simple state or a submachine. One can see them as a self-transition
+ of this state, without an entry or exit action called. This is useful when
+ all you want is to execute some code for a given event in a given
+ state.</para>
+ <para>Internal transitions are specified as having a higher priority than normal
+ transitions. While it makes sense for a submachine with exit points, it is
+ surprising for a simple state. MSM lets you define the transition priority
+ by setting the transitionâs position inside the transition table (see
+ <command xlink:href="#run-to-completion">internals</command> ). The
+ difference between "normal" and internal transitions is that internal
+ transitions have no target state, therefore we need new row types. We had
+ a_row, g_row, _row and row, we now add a_irow, g_irow, _irow and irow which
+ are like normal transitions but define no target state. For, example an
+ internal transition with a guard condition could be:</para>
+ <para>
+ <programlisting>g_irow < Empty /*state*/,cd_detected/*event*/,&p::internal_guard/* guard */></programlisting>
+ </para>
+ <para>These new row types can be placed anywhere in the transition table so that
+ you can still have your state machine structure grouped together. The only
+ difference of behavior with the UML standard is the missing notion of higher
+ priority for internal transitions. Please have a look at <link
+ xlink:href="examples/SimpleTutorialInternal.cpp">the
+ example</link>.</para>
+ <para>It is also possible to do it the UML-conform way by declaring a transition
+ table called <code>internal transition_table</code> inside the state itself
+ and using internal row types. For example:</para>
+ <programlisting>struct Empty : public msm::front::state<>
+{
+ struct internal_transition_table : mpl::vector<
+ a_internal < cd_detected , Empty, &Empty::internal_action >
+ > {};
+};</programlisting>
+ <para>This declares an internal transition table called
+ internal_transition_table and reacting on the event cd_detected by calling
+ internal_action on Empty. Let us note a few points:<itemizedlist>
+ <listitem>
+ <para>internal tables are NOT called transition_table but
+ internal_transition_table</para>
+ </listitem>
+ <listitem>
+ <para>they use different but similar row types: a_internal,
+ g_internal, _internal and internal.</para>
+ </listitem>
+ <listitem>
+ <para>These types take as first template argument the triggering
+ event and then the action and guard method. Note that the only
+ real difference to classical rows is the extra argument before
+ the function pointer. This is the type on which the function
+ will be called.</para>
+ </listitem>
+ <listitem>
+ <para>This also allows you, if you wish, to use actions and guards
+ from another state of the state machine or in the state machine
+ itself.</para>
+ </listitem>
+ <listitem>
+ <para>submachines can have an internal transition table and a
+ classical transition table.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>The <link xlink:href="examples/TestInternal.cpp">following example</link>
+ makes use of an a_internal. It also uses functor-based internal transitions
+ which will be explained in <command
+ xlink:href="#functor-internal-transitions">the functor
+ front-end</command>, please ignore them for the moment. Also note that
+ the state-defined internal transitions, having the highest priority (as
+ mandated by the UML standard), are tried before those defined inside the
+ state machine transition table.</para>
+ <para>Which method should you use? It depends on what you need:<itemizedlist>
+ <listitem>
+ <para>the first version (using irow) is simpler and likely to
+ compile faster. It also lets you choose the priority of your
+ internal transition.</para>
+ </listitem>
+ <listitem>
+ <para>the second version is more logical from a UML perspective and
+ lets you make states more useful and reusable. It also allows
+ you to call actions and guards on any state of the state
+ machine.</para>
+ </listitem>
+ </itemizedlist>
+ <command xml:id="internal-transitions-note"/><emphasis role="underline"
+ ><emphasis role="bold">Note</emphasis></emphasis>: There is an added
+ possibility coming from this feature. The
+ <code>internal_transition_table</code> transitions being added directly
+ inside the main state machine's transition table, it is possible, if it is
+ more to your state, to distribute your state machine definition a bit like
+ Boost.Statechart, leaving to the state machine itself the only task of
+ declaring the states it wants to use using the
+ <code>explicit_creation</code> type definition. While this is not the
+ author's favorite way, it is still possible. A simplified example using only
+ two states will show this possibility:<itemizedlist>
+ <listitem>
+ <para><link
+ xlink:href="examples/distributed_table/DistributedTable.cpp"
+ >state machine definition</link></para>
+ </listitem>
+ <listitem>
+ <para>Empty <link xlink:href="examples/distributed_table/Empty.hpp"
+ >header</link> and <link
+ xlink:href="examples/distributed_table/Empty.cpp"
+ >cpp</link></para>
+ </listitem>
+ <listitem>
+ <para>Open <link xlink:href="examples/distributed_table/Open.hpp"
+ >header</link> and <link
+ xlink:href="examples/distributed_table/Open.cpp"
+ >cpp</link></para>
+ </listitem>
+ <listitem>
+ <para><link xlink:href="examples/distributed_table/Events.hpp"
+ >events definition</link></para>
+ </listitem>
+ </itemizedlist></para>
+ <para>There is an added bonus offered for submachines, which can have both the
+ standard transition_table and an internal_transition_table (which has a
+ higher priority). This makes it easier if you decide to make a full
+ submachine from a state. It is also slightly faster than the standard
+ alternative, adding orthogonal regions, because event dispatching will, if
+ accepted by the internal table, not continue to the subregions. This gives
+ you a O(1) dispatch instead of O(number of regions). While the example is
+ with eUML, the same is also possible with any front-end.</para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="basic-row2"/>more row types</title>
+ <para>It is also possible to write transitions using actions and guards not just
+ from the state machine but also from its contained states. In this case, one
+ must specify not just a method pointer but also the object on which to call
+ it. This transition row is called, not very originally, <code>row2</code>.
+ They come, like normal transitions in four flavors: <code>a_row2, g_row2,
+ _row2 and row2</code>. For example, a transition calling an action from
+ the state Empty could be:</para>
+ <para>
+ <programlisting>a_row2<Stopped,open_close,Open,Empty
+ /*action source*/,&Empty::open_drawer/*action*/></programlisting>
+ </para>
+ <para>The same capabilities are also available for internal transitions so that
+ we have: <code>a_irow2, g_irow2, _irow2 and row2</code>. For transitions
+ defined as part of the <code>internal_transition_table</code>, you can use
+ the <command xlink:href="#internal-transitions">a_internal, g_internal,
+ _internal, internal</command> row types from the previous
+ sections.</para>
+ <para>These row types allow us to distribute the state machine code among
+ states, making them reusable and more useful. Using transition tables inside
+ states also contributes to this possibility. An <link
+ xlink:href="examples/SimpleTutorial2.cpp">example</link> of these new
+ rows is also provided.</para>
+ </sect2>
+ <sect2>
+ <title>Explicit entry / entry and exit pseudo-state / fork</title>
+ <para>MSM (almost) fully supports these features, described in the <command
+ xlink:href="#uml-history">small UML tutorial</command>. Almost because
+ there are currently two limitations: <itemizedlist>
+ <listitem>
+ <para>it is only possible to explicitly enter a sub- state of the
+ target but not a sub-sub state.</para>
+ </listitem>
+ <listitem>
+ <para>it is not possible to explicitly exit. Exit points must be
+ used.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>Let us see a concrete example:</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/entry%20tutorial.jpg" width="60%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>We find in this diagram:<itemizedlist>
+ <listitem>
+ <para>A ânormalâ activation of SubFsm2, triggered by event1. In each
+ region, the initial state is activated, i.e. SubState1 and
+ SubState1b.</para>
+ </listitem>
+ <listitem>
+ <para>An explicit entry into SubFsm2::SubState2 for region â1â with
+ event2 as trigger, meaning that in region â2â the initial state,
+ SubState1b, activated.</para>
+ </listitem>
+ <listitem>
+ <para>A fork into regions â1â and â2â to the explicit entries
+ SubState2 and SubState2b, triggered by event3. Both states
+ become active so no region is default activated (if we had a
+ third one, it would be).</para>
+ </listitem>
+ <listitem>
+ <para>A connection of two transitions through an entry pseudo state,
+ SubFsm2::PseudoEntry1, triggered by event4 and triggering also
+ the second transition on the same event (both transitions must
+ be triggered by the same event). Region â2â is default-activated
+ and SubState1b becomes active.</para>
+ </listitem>
+ <listitem>
+ <para>An exit from SubFsm2 using an exit pseudo-state, PseudoExit1,
+ triggered by event5 and connecting two transitions using the
+ same event. Again, the event is forwarded to the second
+ transition and both regions are exited, as SubFsm2 becomes
+ inactive. Note that if no transition is defined from
+ PseudoExit1, an error (as defined in the UML standard) will be
+ detected and no_transition called.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>The example is also <link xlink:href="examples/DirectEntryTutorial.cpp"
+ >fully implemented</link>.</para>
+ <para>This sounds complicated but the syntax is simple.</para>
+ <sect3>
+ <title>Explicit entry</title>
+ <para>First, to define that a state is an explicit entry, you have to make
+ it a state and mark it as explicit, giving as template parameters the
+ region id (the region id starts with 0 and corresponds to the first
+ initial state of the initial_state type sequence).</para>
+ <para>
+ <programlisting>struct SubState2 : public msm::front::state<> ,
+ public msm::front::explicit_entry<0></programlisting>
+ </para>
+ <para>And define the submachine as:</para>
+ <para>
+ <programlisting>typedef msm::back::state_machine<SubFsm2_> SubFsm2;</programlisting>
+ </para>
+ <para>You can then use it as target in a transition with State1 as
+ source:</para>
+ <para>
+ <programlisting>_row < State1, Event2, SubFsm2::direct< SubFsm2_::SubState2> ></programlisting>
+ </para>
+ <para>The syntax deserves some explanation. SubFsm2_ is a front end.
+ SubState2 is a nested state, therefore the SubFsm2_::SubState2 syntax.
+ The containing machine (containing State1 and SubFsm2) refers to the
+ backend instance (SubFsm2). SubFsm2::direct states that an explicit
+ entry is desired.</para>
+ <para><emphasis role="underline">Note (also valid for forks)</emphasis>: in
+ order to make compile time more bearable for the more standard cases,
+ and unlike initial states, explicit entry states which are also not
+ found in the transition table of the entered submachine (a rare case) do
+ NOT get automatically created. To explicitly create such states, you
+ need to add in the state machine containing the explicit states a simple
+ typedef giving a sequence of states to be explicitly created
+ like:</para>
+ <para>
+ <programlisting>typedef mpl::vector<SubState2,SubState2b> explicit_creation;</programlisting>
+ </para>
+ </sect3>
+ <sect3>
+ <title>Fork</title>
+ <para>Need a fork instead of an explicit entry? As a fork is an explicit
+ entry into states of different regions, we do not change the state
+ definition compared to the explicit entry and specify as target a list
+ of explicit entry states:</para>
+ <para>
+ <programlisting>_row < State1, Event3,
+ mpl::vector<SubFsm2::direct<SubFsm2_::SubState2>,
+ SubFsm2::direct <SubFsm2_::SubState2b>
+ ></programlisting>
+ </para>
+ <para>With SubState2 defined as before and SubState2b defined as being in
+ the second region (Caution: MSM does not check that the region is
+ correct):</para>
+ <para>
+ <programlisting>struct SubState2b : public msm::front::state<> ,
+ public msm::front::explicit_entry<1></programlisting>
+ </para>
+ </sect3>
+ <sect3>
+ <title>Entry pseudo states</title>
+ <para> To define an entry pseudo state, you need derive from the
+ corresponding class and give the region id:</para>
+ <para>
+ <programlisting>struct PseudoEntry1 : public msm::front::entry_pseudo_state<0></programlisting>
+ </para>
+ <para>And add the corresponding transition in the top-level state machine's
+ transition table:</para>
+ <para>
+ <programlisting>_row < State1, Event4, SubFsm2::entry_pt<SubFsm2_::PseudoEntry1> ></programlisting>
+ </para>
+ <para>And another in the SubFsm2_ submachine definition (remember that UML
+ defines an entry point as a connection between two transitions), for
+ example this time with an action method:</para>
+ <para>
+ <programlisting>_row < PseudoEntry1, Event4, SubState3,&SubFsm2_::entry_action ></programlisting>
+ </para>
+ </sect3>
+ <sect3>
+ <title> Exit pseudo states </title>
+ <para>And finally, exit pseudo states are to be used almost the same way,
+ but defined differently: it takes as template argument the event to be
+ forwarded (no region id is necessary):</para>
+ <para>
+ <programlisting>struct PseudoExit1 : public exit_pseudo_state<event6></programlisting>
+ </para>
+ <para>And you need, like for entry pseudo states, two transitions, one in
+ the submachine:</para>
+ <para>
+ <programlisting>_row < SubState3, Event5, PseudoExit1 ></programlisting>
+ </para>
+ <para>And one in the containing state machine:</para>
+ <para>
+ <programlisting>_row < SubFsm2::exit_pt<SubFsm2_::PseudoExit1>, Event6,State2 ></programlisting>
+ </para>
+ <para><emphasis role="underline">Important note 1:</emphasis> UML defines
+ transiting to an entry pseudo state and having either no second
+ transition or one with a guard as an error but defines no error
+ handling. MSM will tolerate this behavior; the entry pseudo state will
+ simply be the newly active state.</para>
+ <para><emphasis role="underline">Important note 2</emphasis>: UML defines
+ transiting to an exit pseudo state and having no second transition as an
+ error, and also defines no error handling. Therefore, it was decided to
+ implement exit pseudo state as terminate states and the containing
+ composite not properly exited will stay terminated as it was technically
+ âexitedâ.</para>
+ <para><emphasis role="underline">Important note 3:</emphasis> UML states
+ that for the exit point, the same event must be used in both
+ transitions. MSM relaxes this rule and only wants the event on the
+ inside transition to be convertible to the one of the outside
+ transition. In our case, event6 is convertible from event5. Notice that
+ the forwarded event must be named in the exit point definition. For
+ example, we could define event6 as simply as:</para>
+ <para>
+ <programlisting>struct event6
+{
+ event6(){}
+ template <class Event>
+ event6(Event const&){}
+}; //convertible from any event</programlisting>
+ </para>
+ </sect3>
+ </sect2>
+ <sect2>
+ <title>Flags</title>
+ <para>This <link xlink:href="examples/Flags.cpp">tutorial</link> is devoted to a
+ concept not defined in UML: flags. It has been added into MSM after proving
+ itself useful on many occasions. Please, do not be frightened as we are not
+ talking about ugly shortcuts made of an improbable collusion of
+ Booleans.</para>
+ <para>If you look into the Boost.Statechart documentation you'll find this
+ code:</para>
+ <programlisting>if ( ( state_downcast< const NumLockOff * >() != 0 ) &&
+ ( state_downcast< const CapsLockOff * >() != 0 ) &&
+ ( state_downcast< const ScrollLockOff * >() != 0 ) )
+ </programlisting>
+ <para>While correct and found in many UML books, this can be error-prone and a
+ potential time-bomb when your state machine grows and you add new states or
+ orthogonal regions.</para>
+ <para>And most of all, it hides the real question, which would be âdoes my state
+ machine's current state define a special propertyâ? In this special case
+ âare my keys in a lock stateâ? So let's apply the Fundamental Theorem of
+ Software Engineering and move one level of abstraction higher.</para>
+ <para>In our player example, let's say we need to know if the player has a
+ loaded CD. We could do the same:</para>
+ <programlisting>if ( ( state_downcast< const Stopped * >() != 0 ) &&
+ ( state_downcast< const Open * >() != 0 ) &&
+ ( state_downcast< const Paused * >() != 0 ) &&
+ ( state_downcast< const Playing * >() != 0 )) </programlisting>
+ <para>Or flag these 4 states as CDLoaded-able. You add a flag_list type into
+ each flagged state:</para>
+ <para>
+ <programlisting>typedef mpl::vector1<CDLoaded> flag_list;</programlisting>
+ </para>
+ <para>You can even define a list of flags, for example in Playing:</para>
+ <para>
+ <programlisting>typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;</programlisting>
+ </para>
+ <para>This means that Playing supports both properties. To check if your player
+ has a loaded CD, check if your flag is active in the current state:</para>
+ <para>
+ <programlisting>player p; if (p.is_flag_active<CDLoaded>()) ... </programlisting>
+ </para>
+ <para>And what if you have orthogonal regions? How to decide if a state machine
+ is in a flagged state? By default, you keep the same code and the current
+ states will be OR'ed, meaning if one of the active states has the flag, then
+ is_flag_active returns true. Of course, in some cases, you might want that
+ all of the active states are flagged for the state to be active. You can
+ also AND the active states:</para>
+ <para>
+ <programlisting>if (p.is_flag_active<CDLoaded,player::Flag_AND>()) ...</programlisting>
+ </para>
+ <para>The following diagram displays the flag situation in the tutorial.</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/FlagsTutorial.jpg" width="60%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="event-hierarchy"/>Event Hierarchy</title>
+ <para>There are cases where one needs transitions based on categories of events.
+ An example is text parsing. Let's say you want to parse a string and use a
+ state machine to manage your parsing state. You want to parse 4 digits and
+ decide to use a state for every matched digit. Your state machine could look
+ like:</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/ParsingDigits.jpg" width="30%"
+ scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>But how to detect the digit event? We would like to avoid defining 10
+ transitions on char_0, char_1... between two states as it would force us to
+ write 4 x 10 transitions and the compile-time would suffer. To solve this
+ problem, MSM supports the triggering of a transition on a subclass event.
+ For example, if we define digits as: </para>
+ <programlisting>struct digit {};
+struct char_0 : public digit {}; </programlisting>
+ <para>And to the same for other digits, we can now fire char_0, char_1 events
+ and this will cause a transition with "digit" as trigger to be taken.</para>
+ <para>An <link xlink:href="examples/ParsingDigits.cpp">example</link> with
+ performance measurement, taken from the documentation of Boost.Xpressive
+ illustrates this example. You might notice that the performance is actually
+ very good (in this case even better).</para>
+ </sect2>
+ <sect2>
+ <title>Customizing a state machine / Getting more speed</title>
+ <para>MSM is offering many UML features at a high-speed, but sometimes, you just
+ need more speed and are ready to give up some features in exchange. A
+ process_event is handling several tasks: <itemizedlist>
+ <listitem>
+ <para>checking for terminate/interrupt states</para>
+ </listitem>
+ <listitem>
+ <para>handling the message queue (for entry/exit/transition actions
+ generating themselves events)</para>
+ </listitem>
+ <listitem>
+ <para>handling deferred events</para>
+ </listitem>
+ <listitem>
+ <para>catching exceptions (or not)</para>
+ </listitem>
+ <listitem>
+ <para>handling the state switching and action calls</para>
+ </listitem>
+ </itemizedlist>Of these tasks, only the last one is absolutely necessary to
+ a state machine (its core job), the other ones are nice-to-haves which cost
+ CPU time. In many cases, it is not so important, but in embedded systems,
+ this can lead to ad-hoc state machine implementations. MSM detects by itself
+ if a concrete state machine makes use of terminate/interrupt states and
+ deferred events and deactivates them if not used. For the other two, if you
+ do not need them, you need to help by indicating it in your implementation.
+ This is done with two simple typedefs:<itemizedlist>
+ <listitem>
+ <para><code>no_exception_thrown</code> indicates that behaviors will
+ never throw and MSM does not need to catch anything</para>
+ </listitem>
+ <listitem>
+ <para><code>no_message_queue</code> indicates that no action will
+ itself generate a new event and MSM can save us the message
+ queue.</para>
+ </listitem>
+ </itemizedlist>The third configuration possibility, explained <link
+ xlink:href="#basic-defer">here</link>, is to manually activate deferred
+ events, using <code>activate_deferred_events</code>. For example, the
+ following state machine sets all three configuration types:</para>
+ <programlisting>struct player_ : public msm::front::state_machine_def<player_>
+{
+ // no need for exception handling or message queue
+ typedef int no_exception_thrown;
+ typedef int no_message_queue;
+ // also manually enable deferred events
+ typedef int activate_deferred_events
+ ...// rest of implementation
+};</programlisting>
+ </sect2>
+ <sect2>
+ <title>Choosing the initial event</title>
+ <para>A state machine is started using the <code>start</code> method. This
+ causes the initial state's entry behavior to be executed. Like every entry
+ behavior, it becomes as parameter the event causing the state to be entered.
+ But when the machine starts, there was no event triggered. In this case, MSM
+ sends <code>msm::back::state_machine<...>::InitEvent</code>, which might
+ not be the default you'd want. For this special case, MSM provides a
+ configuration mechanism in the form of a typedef. If the state machine's
+ front-end definition provides an initial_event typedef set to another event,
+ this event will be used. For example:</para>
+ <programlisting>struct my_initial_event{};
+struct player_ : public msm::front::state_machine_def<player_>{
+...
+typedef my_initial_event initial_event;
+};</programlisting>
+ </sect2>
+ <sect2>
+ <title> Containing state machine (deprecated)</title>
+ <para>This feature is still supported in MSM for backward compatibility but made
+ obsolete by the fact that every guard/action/entry action/exit action get
+ the state machine passed as argument and might be removed at a later
+ time.</para>
+ <para>All of the states defined in the state machine are created upon state
+ machine construction. This has the huge advantage of a reduced syntactic
+ noise. The cost is a small loss of control for the user on the state
+ creation and access. But sometimes you needed a way for a state to get
+ access to its containing state machine. Basically, a state needs to change
+ its declaration to:</para>
+ <programlisting>struct Stopped : public msm::front::state<sm_ptr></programlisting>
+ <para>And to provide a set_sm_ptr function: <code>void set_sm_ptr(player*
+ pl)</code></para>
+ <para>to get a pointer to the containing state machine. The same applies to
+ terminate_state / interrupt_state and entry_pseudo_state /
+ exit_pseudo_state. </para>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title><command xml:id="functor-front-end"/>Functor front-end</title>
+ <para>The functor front-end is the preferred front-end at the moment. It is more
+ powerful than the standard front-end and has a more readable transition table.
+ It also makes it easier to reuse parts of state machines. Like <command
+ xlink:href="#eUML-front-end">eUML</command>, it also comes with a good deal
+ of predefined actions. Actually, eUML generates a functor front-end through
+ Boost.Typeof and Boost.Proto so both offer the same functionality.</para>
+ <para>The rows which MSM offered in the previous front-end come in different
+ flavors. We saw the a_row, g_row, _row, row, not counting internal rows. This is
+ already much to know, so why define new rows? These types have some
+ disadvantages: <itemizedlist>
+ <listitem>
+ <para>They are more typing and information than we would wish. This
+ means syntactic noise and more to learn.</para>
+ </listitem>
+ <listitem>
+ <para>Function pointers are weird in C++.</para>
+ </listitem>
+ <listitem>
+ <para>The action/guard signature is limited and does not allow for more
+ variations of parameters (source state, target state, current state
+ machine, etc.)</para>
+ </listitem>
+ <listitem>
+ <para>It is not easy to reuse action code from a state machine to
+ another.</para>
+ </listitem>
+ </itemizedlist></para>
+ <sect2>
+ <title> Transition table </title>
+ <para>We can change the definition of the simple tutorial's transition table
+ to:</para>
+ <para>
+ <informaltable>
+ <tbody>
+ <tr>
+ <td>//</td>
+ <td>Start</td>
+ <td>Event</td>
+ <td>Next</td>
+ <td>Action</td>
+ <td>Guard</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>play,</td>
+ <td>Playing,</td>
+ <td>start_playback</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>open_close,</td>
+ <td>Open,</td>
+ <td>open_drawer,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Stopped ,</td>
+ <td>stop,</td>
+ <td>Stopped,</td>
+ <td> </td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Open ,</td>
+ <td>open_close ,</td>
+ <td>Empty ,</td>
+ <td>close_drawer,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Empty ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>open_drawer</td>
+ <td> </td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Stopped ,</td>
+ <td>store_cd_info ,</td>
+ <td>good_disk_format</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>g_row <</td>
+ <td>Empty ,</td>
+ <td>cd_detected ,</td>
+ <td>Playing ,</td>
+ <td>store_cd_info ,</td>
+ <td>&player_::auto_start</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>stop_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>pause ,</td>
+ <td>Paused ,</td>
+ <td>pause_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td>Playing ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>stop_and_open,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>end_pause ,</td>
+ <td>Playing ,</td>
+ <td>resume_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>stop ,</td>
+ <td>Stopped ,</td>
+ <td>stop_playback,</td>
+ <td> none</td>
+ <td>>,</td>
+ </tr>
+ <tr>
+ <td>Row <</td>
+ <td> Paused ,</td>
+ <td>open_close ,</td>
+ <td>Open ,</td>
+ <td>stop_and_open,</td>
+ <td> none</td>
+ <td>></td>
+ </tr>
+ <tr>
+ <td>//</td>
+ <td>+---------+</td>
+ <td>-------------+</td>
+ <td>---------+</td>
+ <td>---------------------+</td>
+ <td>----------------------+</td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>> {};</td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </para>
+ <para>Transitions are now of type "Row" with exactly 5 template arguments:
+ source state, event, target state, action and guard. Wherever there is
+ nothing (for example actions and guards), write "none". Actions and guards
+ are no more methods but functors getting as arguments the detected event,
+ the state machine, source and target state:</para>
+ <programlisting>struct store_cd_info
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ void operator()(Evt const&, Fsm& fsm, SourceState&,TargetState& )
+ {
+ cout << "player::store_cd_info" << endl;
+ fsm.process_event(play());
+ }
+}; </programlisting>
+ <para>The advantage of functors compared to functions are that functors are
+ generic and reusable. They also allow passing more parameters than just
+ events. The guard functors are the same but have an operator() returning a
+ bool.</para>
+ <para>It is also possible to mix rows from different front-ends. To show this, a
+ g_row has been left in the transition table. <emphasis role="underline"
+ >Note:</emphasis> in case the action functor is used in the transition
+ table of a state machine contained inside a top-level state machine, the
+ âfsmâ parameter refers to the lowest-level state machine (referencing this
+ action), not the top-level one.</para>
+ <para>To illustrate the reusable point, MSM comes with a whole set of predefined
+ functors. Please refer to eUML for the <link xlink:href="#Reference-begin"
+ >full list</link>. For example, we are now going to replace the first
+ action by an action sequence and the guard by a more complex functor.</para>
+ <para>We decide we now want to execute two actions in the first transition
+ (Stopped -> Playing). We only need to change the action start_playback to
+ <programlisting>ActionSequence_< mpl::vector<some_action, start_playback> ></programlisting>and
+ now will execute some_action and start_playback every time the transition is
+ taken. ActionSequence_ is a functor calling each action of the mpl::vector
+ in sequence.</para>
+ <para>We also want to replace good_disk_format by a condition of the type:
+ âgood_disk_format && (some_condition || some_other_condition)â. We
+ can achieve this using And_ and Or_ functors:
+ <programlisting>And_<good_disk_format,Or_< some_condition , some_other_condition> ></programlisting>It
+ even starts looking like functional programming. MSM ships with functors for
+ operators, state machine usage, STL algorithms or container methods.</para>
+ </sect2>
+ <sect2>
+ <title>Defining states with entry/exit actions</title>
+ <para>You probably noticed that we just showed a different transition table and
+ that we even mixed rows from different front-ends. This means that you can
+ do this and leave the definitions for states unchanged. Most examples are
+ doing this as it is the simplest solution. You still enjoy the simplicity of
+ the first front-end with the extended power of the new transition types.
+ This <link xlink:href="examples/SimpleWithFunctors.cpp">tutorial</link>,
+ adapted from the earlier example does just this.</para>
+ <para>Of course, it is also possible to define states where entry and exit
+ actions are also provided as functors as these are generated by eUML and
+ both front-ends are equivalent. For example, we can define a state
+ as:</para>
+ <programlisting>struct Empty_Entry
+{
+ template <class Event,class Fsm,class State>
+ void operator()(Event const&,Fsm&,State&)
+ {
+ ...
+ }
+}; // same for Empty_Exit
+struct Empty : public msm::front::euml::func_state<Empty_Entry,Empty_Exit>{};</programlisting>
+ <para>This also means that you can, like in the transition table, write entry /
+ exit actions made of more complicated action combinations. The previous
+ example can therefore <link xlink:href="examples/SimpleWithFunctors2.cpp">be
+ rewritten</link>.</para>
+ <para>Usually, however, one will probably use the standard state definition as
+ it provides the same capabilities as this front-end state definition, unless
+ one needs some of the shipped predefined functors or is a fan of functional
+ programming.</para>
+ </sect2>
+ <sect2>
+ <title>Defining a simple state machine</title>
+ <para>Like states, state machines can be defined using the previous front-end,
+ as the previous example showed, or with the functor front-end, which allows
+ you to define a state machine entry and exit functions as functors, as in
+ <link xlink:href="examples/SimpleWithFunctors2.cpp">this
+ example</link>.</para>
+ </sect2>
+ <sect2>
+ <title>Anonymous transitions</title>
+ <para>Anonymous (completion) transitions are transitions without a named event.
+ We saw how this front-end uses <code>none</code> when no action or guard is
+ required. We can also use <code>none</code> instead of an event to mark an
+ anonymous transition. For example, the following transition makes an
+ immediate transition from State1 to State2:</para>
+ <programlisting>Row < State1 , none , State2 ></programlisting>
+ <para>The following transition does the same but calling an action in the
+ process:</para>
+ <programlisting>Row < State1 , none , State2 , State1ToState2, none ></programlisting>
+ <para>The following diagram shows an example and its <link
+ xlink:href="examples/AnonymousTutorialWithFunctors.cpp"
+ >implementation</link>:</para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/Anonymous.jpg" width="70%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="functor-internal-transitions"/>Internal
+ transitions</title>
+ <para>The <link xlink:href="examples/SimpleTutorialInternalFunctors.cpp"
+ >following example</link> uses internal transitions with the functor
+ front-end. As for the simple standard front-end, both methods of defining
+ internal transitions are supported:<itemizedlist>
+ <listitem>
+ <para>providing a <code>Row</code> in the state machine's transition
+ table with <code>none</code> as target state defines an internal
+ transition.</para>
+ </listitem>
+ <listitem>
+ <para>providing an <code>internal_transition_table</code> made of
+ <code>Internal</code> rows inside a state or submachine
+ defines UML-conform internal transitions with higher
+ priority.</para>
+ </listitem>
+ <listitem>
+ <para>transitions defined inside
+ <code>internal_transition_table</code> require no source or
+ target state as the source state is known (<code>Internal</code>
+ really are <code>Row</code> without a source or target state)
+ .</para>
+ </listitem>
+ </itemizedlist>Like for the <command xlink:href="#internal-transitions-note"
+ >standard front-end internal transitions</command>, internal transition
+ tables are added into the main state machine's table, thus allowing you to
+ distribute the transition table definition and reuse states.</para>
+ <para>There is an added bonus offered for submachines, which can have both the
+ standard transition_table and an internal_transition_table (which has higher
+ priority). This makes it easier if you decide to make a full submachine from
+ a state later. It is also slightly faster than the standard alternative,
+ adding orthogonal regions, because event dispatching will, if accepted by
+ the internal table, not continue to the subregions. This gives you a O(1)
+ dispatch instead of O(number of regions). While the example is with eUML,
+ the same is also possible with this front-end.</para>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title><command xml:id="eUML-front-end"/>eUML (experimental)</title>
+ <para><emphasis role="underline">Important note</emphasis>: eUML requires a compiler
+ supporting the C++0x decltype/typeof feature (for example VC >= 9, g++ >= 4.3.
+ VC8 supports eUML but will crash with middle-size state machines). More
+ generally, eUML has experimental status because most compilers will start
+ crashing when a state machine becomes too big. Only g++ 4.3 (unfortunately not
+ 4.4 which shows a serious regression) seems perfectly resilient.</para>
+ <para>The previous front-ends are simple to write but still force an amount of
+ noise, mostly MPL types, so it would be nice to write code looking like C++
+ (with a C++ action language) directly inside the transition table, like UML
+ designers like to do on their state machine diagrams. If it were functional
+ programming, it would be even better. This is what eUML is for.</para>
+ <para>eUML is a Boost.Proto and Boost.Typeof-based compile-time domain specific
+ embedded language. It provides grammars which allow the definition of
+ actions/guards directly inside the transition table or entry/exit in the state
+ definition. There are grammars for actions, guards, flags, attributes, deferred
+ events, initial states.</para>
+ <para>It also relies on Boost.Typeof as a wrapper around the new decltype C++0x
+ feature to provide a compile-time evaluation of all the grammars. Unfortunately,
+ all the underlying Boost libraries are not Typeof-enabled, so for the moment,
+ you will need a compiler where Typeof is natively implemented (like VC8-9-10,
+ g++ >= 4.3).</para>
+ <para>Examples will be provided in the next paragraphs. You need to include eUML
+ basic features: </para>
+ <para>
+ <programlisting>#include <msm/front/euml/euml.hpp></programlisting>
+ </para>
+ <para>To add STL support (at possible cost of longer compilation times), include: </para>
+ <para>
+ <programlisting>#include <msm/front/euml/stl.hpp></programlisting>
+ </para>
+ <para>eUML is defined in the namespace <code>msm::front::euml</code>.</para>
+ <sect2>
+ <title>Transition table</title>
+ <para>A transition can be defined using eUML as: </para>
+ <para>
+ <programlisting>source + event [guard] / action == target</programlisting>
+ </para>
+ <para>or as</para>
+ <para>
+ <programlisting>target == source + event [guard] / action</programlisting>
+ </para>
+ <para>The first version looks like a drawn transition in a diagram, the second
+ one seems natural to a C++ developer.</para>
+ <para>The simple transition table written with the <command
+ xlink:href="#functor-front-end">previous front-end</command> can now be
+ written as:</para>
+ <para>
+ <informaltable frame="void">
+ <tbody>
+ <tr>
+ <td>BOOST_MSM_EUML_TRANSITION_TABLE(( </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Stopped +</td>
+ <td>play [DummyGuard] / (TestFct,start_playback)</td>
+ <td>== Playing</td>
+ </tr>
+ <tr>
+ <td>Stopped +</td>
+ <td>open_close/ open_drawer</td>
+ <td>== Open</td>
+ </tr>
+ <tr>
+ <td>Stopped +</td>
+ <td>stop</td>
+ <td>== Stopped</td>
+ </tr>
+ <tr>
+ <td>Open +</td>
+ <td>open_close / close_drawer</td>
+ <td>== Empty</td>
+ </tr>
+ <tr>
+ <td>Empty +</td>
+ <td>open_close / open_drawer </td>
+ <td>== Open</td>
+ </tr>
+ <tr>
+ <td>Empty +</td>
+ <td>cd_detected [good_disk_format] / store_cd_info </td>
+ <td>== Stopped</td>
+ </tr>
+ <tr>
+ <td>),transition_table)</td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </para>
+ <para>Or, using the alternative notation, it can be:</para>
+ <para>
+ <informaltable>
+ <tbody>
+ <tr>
+ <td>BOOST_MSM_EUML_TRANSITION_TABLE((</td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>Playing == </td>
+ <td>Stopped +</td>
+ <td>play [DummyGuard] / (TestFct,start_playback)</td>
+ </tr>
+ <tr>
+ <td>Open ==</td>
+ <td>Stopped +</td>
+ <td>open_close/ open_drawer</td>
+ </tr>
+ <tr>
+ <td>Stopped ==</td>
+ <td>Stopped +</td>
+ <td>stop</td>
+ </tr>
+ <tr>
+ <td>Empty ==</td>
+ <td>Open +</td>
+ <td>open_close / close_drawer</td>
+ </tr>
+ <tr>
+ <td>Open ==</td>
+ <td>Empty +</td>
+ <td>open_close / open_drawer</td>
+ </tr>
+ <tr>
+ <td>Stopped ==</td>
+ <td>Empty +</td>
+ <td>cd_detected [good_disk_format] / store_cd_info </td>
+ </tr>
+ <tr>
+ <td>),transition_table)</td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </para>
+ <para>The transition table now looks like a list of (readable) rules with little
+ noise.</para>
+ <para>UML defines guards between â[ ]â and actions after a â/â, so the chosen
+ syntax is already more readable for UML designers. UML also allows designers
+ to define several actions sequentially (our previous ActionSequence_)
+ separated by a comma. The first transition does just this: two actions
+ separated by a comma and enclosed inside parenthesis to respect C++ operator
+ precedence.</para>
+ <para>If this seems to you like it will cost you run-time performance, don't
+ worry, eUML is based on typeof (decltype) which only evaluates the
+ parameters to BOOST_MSM_EUML_TRANSITION_TABLE and no run-time cost occurs.
+ Actually, eUML is only a metaprogramming layer on top of "standard" MSM
+ metaprogramming and this first layer generates the previously-introduced
+ <command xlink:href="#functor-front-end">functor
+ front-end</command>.</para>
+ <para>UML also allows designers to define more complicated guards, like
+ [good_disk_format && (some_condition || some_other_condition)]. This
+ was possible with our previously defined functors, but using a complicated
+ template syntax. This syntax is now possible exactly as written, which means
+ without any syntactic noise at all.</para>
+ </sect2>
+ <sect2>
+ <title>Defining events, actions and states with entry/exit actions</title>
+ <sect3>
+ <title>Events</title>
+ <para>Events must be proto-enabled. To achieve this, they must inherit from
+ a proto terminal (euml_event<event-name>). eUML also provides a macro
+ to make this easier:</para>
+ <para>
+ <programlisting>BOOST_MSM_EUML_EVENT(play)</programlisting>
+ </para>
+ <para>This declares an event type and an instance of this type called
+ <code>play</code>, which is now ready to use in state or transition
+ behaviors.</para>
+ <para>There is a second macro, BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES, which
+ takes as second parameter the attributes an event will contain, using
+ the <command xlink:href="#eUML-attributes">attribute
+ syntax</command>.</para>
+ <para><emphasis role="underline">Note</emphasis>: as we now have events
+ defined as instances instead of just types, can we still process an
+ event by creating one on the fly, like:
+ <code>fsm.process_event(play());</code> or do we have to write:
+ <code>fsm.process_event(play);</code></para>
+ <para>The answer is you can do both. The second one is easier but unlike
+ other front-ends, the second uses a defined operator(), which creates an
+ event on the fly.</para>
+ </sect3>
+ <sect3>
+ <title>Actions</title>
+ <para>Actions (returning void) and guards (returning a bool) are defined
+ like previous functors, with the difference that they also must be
+ proto-enabled. This can be done by inheriting from euml_action<
+ functor-name >. eUML also provides a macro:</para>
+ <programlisting>BOOST_MSM_EUML_ACTION(some_condition)
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ bool operator()(Evt const& ,Fsm& ,SourceState&,TargetState& )
+ { return true; }
+}; </programlisting>
+ <para>Like for events, this macro declares a functor type and an instance
+ for use in transition or state behaviors.</para>
+ <para>It is possible to use the same action grammar from the transition
+ table to define state entry and exit behaviors. So
+ <code>(action1,action2)</code> is a valid entry or exit behavior
+ executing both actions in turn.</para>
+ <para>The state functors have a slightly different signature as there is no
+ source and target state but only a current state (entry/exit actions are
+ transition-independent), for example:</para>
+ <programlisting>BOOST_MSM_EUML_ACTION(Empty_Entry)
+{
+ template <class Evt,class Fsm,class State>
+ void operator()(Evt const& ,Fsm& ,State& ) { ... }
+}; </programlisting>
+ </sect3>
+ <sect3>
+ <title>States</title>
+ <para>There is also a macro for states. This macro has 2 arguments, first
+ the expression defining the state, then the state (instance)
+ name:</para>
+ <programlisting>BOOST_MSM_EUML_STATE((),Paused)</programlisting>
+ <para>This defines a simple state without entry or exit action. You can
+ provide in the expression parameter the state behaviors (entry and exit)
+ using the action grammar, like in the transition table:</para>
+ <programlisting>BOOST_MSM_EUML_STATE(((Empty_Entry,Dummy_Entry)/*2 entryactions*/,
+ Empty_Exit/*1 exit action*/ ),
+ Empty)</programlisting>
+ <para>This means that Empty is defined as a state with an entry action made
+ of two sub-actions, Empty_Entry and Dummy_Entry (enclosed inside
+ parenthesis), and an exit action, Empty_Exit.</para>
+ <para>There are several possibilitites for the <command
+ xml:id="eUML-build-state"/> expression syntax:<itemizedlist>
+ <listitem>
+ <para>(): state without entry or exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1): state with entry but no exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2): state with entry and exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes): state with entry and exit
+ action, defining some attributes (read further on).</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure): state with entry and
+ exit action, defining some attributes (read further on) and
+ flags (standard MSM flags) or deferred events (standard MSM
+ deferred events).</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure,Base): state with entry
+ and exit action, defining some attributes (read further on),
+ flags and deferred events (plain msm deferred events) and a
+ non-default base state (as defined in standard MSM).</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>no_action is also defined, which does, well, nothing except being a
+ placeholder (needed for example as entry action if we have no entry but
+ an exit). Expr1 and Expr2 are a sequence of actions, obeying the same
+ action grammar as in the transition table (following the â/â
+ symbol).</para>
+ <para>The BOOST_MSM_EUML_STATE macro will allow you to define most common
+ states, but sometimes you will need more, for example provide in your
+ states some special behavior. In this case, you will have to do the
+ macro's job by hand, which is not very complicated. The state will need
+ to inherit from <code>msm::front::state<></code>, like any state, and
+ from <code>euml_state<state-name></code> to be proto-enabled. You
+ will then need to declare an instance for use in the transition table.
+ For example:</para>
+ <programlisting>struct Empty_impl : public msm::front::state<> , public euml_state<Empty_impl>
+{
+ void activate_empty() {std::cout << "switching to Empty " << std::endl;}
+ template <class Event,class Fsm>
+ void on_entry(Event const& evt,Fsm&fsm){...}
+ template <class Event,class Fsm>
+ void on_exit(Event const& evt,Fsm&fsm){...}
+};
+//instance for use in the transition table
+Empty_impl const Empty;</programlisting>
+ <para>Notice also that we defined a method named activate_empty. We would
+ like to call it inside a behavior. This can be done using the
+ BOOST_MSM_EUML_METHOD macro. </para>
+ <programlisting>BOOST_MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</programlisting>
+ <para>The first parameter is the name of the underlying functor, which you
+ could use with the functor front-end, the second is the state method
+ name, the third is the eUML-generated function, the fourth and fifth the
+ return value when used inside a transition or a state behavior. You can
+ now use this inside a transition:</para>
+ <programlisting>Empty == Open + open_close / (close_drawer,activate_empty_(target_))</programlisting>
+ </sect3>
+ </sect2>
+ <sect2>
+ <title>Defining a simple state machine</title>
+ <para>You can reuse the state machine definition method from the standard
+ front-end and simply replace the transition table by this new one. You can
+ also use eUML to define a state machine "on the fly" (if, for example, you
+ need to provide an on_entry/on_exit for this state machine as a functor).
+ For this, there is also a macro, <command xml:id="eUML-build-sm"
+ />BOOST_MSM_EUML_DECLARE_STATE_MACHINE, which has 2 arguments, an expression
+ describing the state machine and the state machine name. The expression has
+ up to 8 arguments:<itemizedlist>
+ <listitem>
+ <para>(Stt, Init): simplest state machine where only the transition
+ table and initial state(s) are defined.</para>
+ </listitem>
+ <listitem>
+ <para>(Stt, Init, Expr1): state machine where the transition table,
+ initial state and entry action are defined.</para>
+ </listitem>
+ <listitem>
+ <para>(Stt, Init, Expr1, Expr2): state machine where the transition
+ table, initial state, entry and exit actions are defined.</para>
+ </listitem>
+ <listitem>
+ <para>(Stt, Init, Expr1, Expr2, Attributes): state machine where the
+ transition table, initial state, entry and exit actions are
+ defined. Furthermore, some attributes are added (read further
+ on).</para>
+ </listitem>
+ <listitem>
+ <para>(Stt, Init, Expr1, Expr2, Attributes, Configure): state
+ machine where the transition table, initial state, entry and
+ exit actions are defined. Furthermore, some attributes (read
+ further on), flags, deferred events and <link
+ xlink:href="#eUML-Configuration">configuration
+ capabilities</link> (no message queue / no exception
+ catching) are added.</para>
+ </listitem>
+ <listitem>
+ <para>(Stt, Init, Expr1, Expr2, Attributes, Flags, Deferred , Base):
+ state machine where the transition table, initial state, entry
+ and exit actions are defined. Furthermore, attributes (read
+ further on), flags , deferred events and configuration
+ capabilities (no message queue / no exception catching) are
+ added and a non-default base state (see the <link
+ xlink:href="#backend-base-state">back-end
+ description</link>) is defined.</para>
+ </listitem>
+ </itemizedlist>For example, a minimum state machine could be defined
+ as:</para>
+ <para>
+ <informaltable>
+ <tbody>
+ <tr>
+ <td>BOOST_MSM_EUML_TRANSITION_TABLE((</td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ <tr>
+ <td>),transition_table)</td>
+ <td> </td>
+ <td> </td>
+ </tr>
+ </tbody>
+ </informaltable>
+ </para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,init_ << Empty ),
+ player_)</programlisting>
+ <para>Please have a look at the player tutorial written using eUML's <link
+ xlink:href="examples/SimpleTutorialEuml2.cpp">first</link> and <link
+ xlink:href="examples/SimpleTutorialEuml.cpp">second</link> syntax. The
+ BOOST_MSM_EUML_DECLARE_ATTRIBUTE macro, to which we will get back shortly,
+ declares attributes given to an eUML type (state or event) using the
+ <command xlink:href="#eUML-attributes">attribute
+ syntax</command>.</para>
+ </sect2>
+ <sect2>
+ <title>Defining a submachine</title>
+ <para>Defining a submachine (see <link
+ xlink:href="examples/CompositeTutorialEuml.cpp">tutorial</link>) with
+ other front-ends simply means using a state which is a state machine in the
+ transition table of another state machine. This is the same with eUML. One
+ only needs define a second state machine and reference it in the transition
+ table of the containing state machine.</para>
+ <para>Unlike the state or event definition macros,
+ BOOST_MSM_EUML_DECLARE_STATE_MACHINE defines a type, not an instance because
+ a type is what the back-end requires. This means that you will need to
+ declare yourself an instance to reference your submachine into another state
+ machine, for example:</para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_STATE_MACHINE(...,Playing_)
+typedef msm::back::state_machine<Playing_> Playing_type;
+Playing_type const Playing;</programlisting>
+ <para>We can now use this instance inside the transition table of the containing
+ state machine:</para>
+ <programlisting>Paused == Playing + pause / pause_playback</programlisting>
+ </sect2>
+ <sect2>
+ <title>
+ <command xml:id="eUML-attributes"/>Attributes / Function call</title>
+ <para>We now want to make our grammar more useful. Very often, one needs only
+ very simple action methods, for example ++Counter or Counter > 5 where
+ Counter is usually defined as some attribute of the class containing the
+ state machine. It seems like a waste to write a functor for such a simple
+ action. Furthermore, states within MSM are also classes so they can have
+ attributes, and we would also like to provide them with attributes. </para>
+ <para>If you look back at our examples using the <link
+ xlink:href="examples/SimpleTutorialEuml2.cpp">first</link> and <link
+ xlink:href="examples/SimpleTutorialEuml.cpp">second</link> syntaxes, you
+ will find a BOOST_MSM_EUML_DECLARE_ATTRIBUTE and a BOOST_MSM_EUML_ATTRIBUTES
+ macro. The first one declares possible attributes:</para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,cd_name)
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)</programlisting>
+ <para>This declares two attributes: cd_name of type std::string and cd_type of
+ type DiskTypeEnum. These attributes are not part of any event or state in
+ particular, we just declared a name and a type. Now, we can add attributes
+ to our cd_detected event using the second one:</para>
+ <programlisting>BOOST_MSM_EUML_ATTRIBUTES((attributes_ << cd_name << cd_type ),
+ cd_detected_attributes)</programlisting>
+ <para>This declares an attribute list which is not linked to anything in
+ particular yet. It can be attached to a state or an event. For example, if
+ we want the event cd_detected to have these defined attributes we
+ write:</para>
+ <programlisting>BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(cd_detected,cd_detected_attributes)</programlisting>
+ <para>For states, we use the BOOST_MSM_EUML_STATE macro, which has an expression
+ form where one can provide attributes. For example:</para>
+ <programlisting>BOOST_MSM_EUML_STATE((no_action /*entry*/,no_action/*exit*/,
+ attributes_ << cd_detected_attributes),
+ some_state)</programlisting>
+ <para>OK, great, we now have a way to add attributes to a class, which we could
+ have done more easily, so what is the point? The point is that we can now
+ reference these attributes directly, at compile-time, in the transition
+ table. For example, in the example, you will find this transition:</para>
+ <programlisting>Stopped==Empty+cd_detected[good_disk_format&&(event_(cd_type)==Int_<DISK_CD>())] </programlisting>
+ <para>Read event_(cd_type) as event_->cd_type with event_ a type generic for
+ events, whatever the concrete event is (in this particular case, it happens
+ to be a cd_detected as the transition shows).</para>
+ <para>The main advantage of this feature is that you do not need to define a new
+ functor and you do not need to look inside the functor to know what it does,
+ you have all at hand.</para>
+ <para>MSM provides more generic objects for state machine types:<itemizedlist>
+ <listitem>
+ <para>event_ : used inside any action, the event triggering the
+ transition</para>
+ </listitem>
+ <listitem>
+ <para>state_: used inside entry and exit actions, the entered /
+ exited state</para>
+ </listitem>
+ <listitem>
+ <para>source_: used inside a transition action, the source
+ state</para>
+ </listitem>
+ <listitem>
+ <para>target_: used inside a transition action, the target
+ state</para>
+ </listitem>
+ <listitem>
+ <para>fsm_: used inside any action, the (lowest-level) state machine
+ processing the transition</para>
+ </listitem>
+ <listitem>
+ <para>Int_<int value>: a functor representing an int</para>
+ </listitem>
+ <listitem>
+ <para>Char_<value>: a functor representing a char</para>
+ </listitem>
+ <listitem>
+ <para>Size_t_<value>: a functor representing a size_t</para>
+ </listitem>
+ <listitem>
+ <para>String_<mpl::string> (boost >= 1.40): a functor
+ representing a string.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>These helpers can be used in two different ways:<itemizedlist>
+ <listitem>
+ <para>helper(attribute_name) returns the attribute with name
+ attribute_name</para>
+ </listitem>
+ <listitem>
+ <para>helper returns the state / event type itself.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>The second form is helpful if you want to provide your states with their
+ own methods, which you also want to use inside the transition table. In the
+ <link xlink:href="examples/SimpleTutorialEuml.cpp">above
+ tutorial</link>, we provide Empty with an activate_empty method. We would
+ like to create a eUML functor and call it from inside the transition table.
+ This is done using the MSM_EUML_METHOD / MSM_EUML_FUNCTION macros. The first
+ creates a functor to a method, the second to a free function. In the
+ tutorial, we write:</para>
+ <programlisting>MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</programlisting>
+ <para>The first parameter is the functor name, for use with the functor
+ front-end. The second is the name of the method to call. The third is the
+ function name for use with eUML, the fourth is the return type of the
+ function if used in the context of a transition action, the fifth is the
+ result type if used in the context of a state entry / exit action (usually
+ fourth and fifth are the same). We now have a new eUML function calling a
+ method of "something", and this "something" is one of the five previously
+ shown generic helpers. We can now use this in a transition, for
+ example:</para>
+ <programlisting>Empty == Open + open_close / (close_drawer,activate_empty_(target_))</programlisting>
+ <para>The action is now defined as a sequence of two actions: close_drawer and
+ activate_empty, which is called on the target itself. The target being Empty
+ (the state defined left), this really will call Empty::activate_empty().
+ This method could also have an (or several) argument(s), for example the
+ event, we could then call activate_empty_(target_ , event_).</para>
+ <para>More examples can be found in the <link
+ xlink:href="examples/CompilerStressTestEuml.cpp">terrible compiler
+ stress test</link>, the <link xlink:href="examples/SimpleTimer.cpp"
+ >timer example</link> or in the <link
+ xlink:href="examples/iPodSearchEuml.cpp">iPodSearch with eUML</link>
+ (for String_ and more).</para>
+ </sect2>
+ <sect2>
+ <title>Orthogonal regions, flags, event deferring</title>
+ <para>Defining orthogonal regions really means providing more initial states. To
+ add more initial states, âshift leftâ some, for example, if we had another
+ initial state named AllOk :</para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
+ init_ << Empty << AllOk ),
+ player_)</programlisting>
+ <para>You remember from the <command xlink:href="#eUML-build-state"
+ >BOOST_MSM_EUML_STATE </command> and <command
+ xlink:href="#eUML-build-sm"
+ >BOOST_MSM_EUML_DECLARE_STATE_MACHINE</command> signatures that just
+ after attributes, we can define flags, like in the basic MSM front-end. To
+ do this, we have another "shift-left" grammar, for example:</para>
+ <programlisting>BOOST_MSM_EUML_STATE((no_action,no_action, attributes_ <<no_attributes_,
+ /* flags */ configure_<< PlayingPaused << CDLoaded),
+ Paused)</programlisting>
+ <para>We now defined that Paused will get two flags, PlayingPaused and CDLoaded,
+ defined, with another macro:</para>
+ <programlisting>BOOST_MSM_EUML_FLAG(CDLoaded)</programlisting>
+ <para>This corresponds to the following basic front-end definition of
+ Paused:</para>
+ <programlisting>struct Paused : public msm::front::state<>
+{
+ typedef mpl::vector2<PlayingPaused,CDLoaded> flag_list;
+};</programlisting>
+ <para>Under the hood, what you get really is a mpl::vector2.</para>
+ <para><emphasis role="underline">Note</emphasis>: As we use the version of
+ BOOST_MSM_EUML_STATE's expression with 4 arguments, we need to tell eUML
+ that we need no attributes. Similarly to a <code>cout << endl</code>,
+ we need a <code>attributes_ << no_attributes_</code> syntax.</para>
+ <para>You can use the flag with the is_flag_active method of a state machine.
+ You can also use the provided helper function is_flag_ (returning a bool)
+ for state and transition behaviors. For example, in the <link
+ xlink:href="examples/iPodEuml.cpp">iPod implementation with eUML</link>,
+ you find the following transition:</para>
+ <programlisting>ForwardPressed == NoForward + EastPressed[!is_flag_(NoFastFwd)]</programlisting>
+ <para>The function also has an optional second parameter which is the state
+ machine on which the function is called. By default, fsm_ is used (the
+ current state machine) but you could provide a functor returning a reference
+ to another state machine.</para>
+ <para>eUML also supports defining deferred events in the state (state machine)
+ definition. To this aim, we can reuse the flag grammar. For example:</para>
+ <programlisting>BOOST_MSM_EUML_STATE((Empty_Entry,Empty_Exit, attributes_ << no_attributes_,
+ /* deferred */ configure_<< play ),Empty) </programlisting>
+ <para>The configure_ left shift is also responsible for deferring events. Shift
+ inside configure_ a flag and the state will get a flag, shift an event and
+ it will get a deferred event. This replaces the basic front-end
+ definition:</para>
+ <programlisting>typedef mpl::vector<play> deferred_events;</programlisting>
+ <para>In <link xlink:href="examples/OrthogonalDeferredEuml.cpp">this
+ tutorial</link>, player is defining a second orthogonal region with
+ AllOk as initial state. The <code>Empty</code> and <code>Open</code> states
+ also defer the event <code>play</code>. <code>Open</code>,
+ <code>Stopped</code> and <code>Pause</code> also support the flag
+ <code>CDLoaded</code> using the same left shift into
+ <code>configure_</code>.</para>
+ <para>In the functor front-end, we also had the possibility to defer an event
+ inside a transition, which makes possible conditional deferring. This is
+ also possible with eUML through the use of the defer_ order, as shown in
+ <link xlink:href="examples/OrthogonalDeferredEuml.cpp">this
+ tutorial</link>. You will find the following transition:</para>
+ <programlisting>Open + play / defer_</programlisting>
+ <para>This is an <command xlink:href="#eUML-internal">internal
+ transition</command>. Ignore it for the moment. Interesting is, that
+ when the event <code>play</code> is fired and <code>Open</code> is active,
+ the event will be deferred. Now add a guard and you can conditionally defer
+ the event, for example:</para>
+ <programlisting>Open + play [ some_condition ] / defer_</programlisting>
+ <para>This is similar to what we did with the functor front-end. This means that
+ we have the same constraints. Using defer_ instead of a state declaration,
+ we need to tell MSM that we have deferred events in this state machine. We
+ do this (again) using a configure_ declaration in the state machine
+ definition in which we shift the deferred_events configuration flag:</para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
+ init_ << Empty << AllOk,
+ Entry_Action,
+ Exit_Action,
+ attributes_ << no_attributes_,
+ configure_<< deferred_events ),
+ player_)</programlisting>
+ <para>A <link xlink:href="examples/OrthogonalDeferredEuml2.cpp">tutorial</link>
+ illustrates this possibility.</para>
+ </sect2>
+ <sect2>
+ <title>
+ <command xml:id="eUML-Configuration"/>Customizing a state machine / Getting
+ more speed</title>
+ <para>We just saw how to use configure_ to define deferred events or flags. We
+ can also use it to configure our state machine like we did with the other front-ends:<itemizedlist>
+ <listitem>
+ <para><code>configure_ << no_exception</code>: disables
+ exception handling</para>
+ </listitem>
+ <listitem>
+ <para><code>configure_ << no_msg_queue</code> deactivates the
+ message queue</para>
+ </listitem>
+ <listitem>
+ <para><code>configure_ << deferred_events</code> manually
+ enables event deferring</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>Deactivating the first two features and not activating the third if not
+ needed greatly improves the event dispatching speed of your state machine.
+ Our <link xlink:href="examples/EumlSimple.cpp">speed testing</link> example
+ with eUML does this for the best performance.</para>
+ </sect2>
+ <sect2>
+ <title>Completion / Anonymous transitions</title>
+ <para>Anonymous transitions (See <command xlink:href="#uml-anonymous">UML
+ tutorial</command>) are transitions without a named event, which are
+ therefore triggered immediately when the source state becomes active,
+ provided a guard allows it. As there is no event, to define such a
+ transition, simply omit the â+â part of the transition (the event), for
+ example: </para>
+ <programlisting>State3 == State4 [always_true] / State3ToState4
+State4 [always_true] / State3ToState4 == State3</programlisting>
+ <para>Please have a look at <link
+ xlink:href="examples/AnonymousTutorialEuml.cpp">this example</link>,
+ which implements the <command xlink:href="#anonymous-transitions">previously
+ defined</command> state machine with eUML.</para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="eUML-internal"/>Internal transitions</title>
+ <para>Like both other front-ends, eUML supports two ways of defining internal transitions:<itemizedlist>
+ <listitem>
+ <para>in the state machine's transition table. In this case, you
+ need to specify a source state, event, actions and guards but no
+ target state, which eUML will interpret as an internal
+ transition, for example this defines a transition internal to
+ Open, on the event open_close:</para>
+ <programlisting>Open + open_close [internal_guard1] / internal_action1</programlisting>
+ <para><link xlink:href="examples/EumlInternal.cpp">A full
+ example</link> is also provided.</para>
+ </listitem>
+ <listitem>
+ <para>in a state's <code>internal_transition_table</code>. For
+ example:</para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
+struct Open_impl : public Open_def
+{
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ open_close [internal_guard1] / internal_action1
+ ))
+};</programlisting>
+ <para>Notice how we do not need to repeat that the transition
+ originates from Open as we already are in Open's context. </para>
+ <para>The <link xlink:href="examples/EumlInternalDistributed.cpp"
+ >implementation</link> also shows the added bonus offered
+ for submachines, which can have both the standard
+ transition_table and an internal_transition_table (which has
+ higher priority). This makes it easier if you decide to make a
+ full submachine from a state. It is also slightly faster than
+ the standard alternative, adding orthogonal regions, because
+ event dispatching will, if accepted by the internal table, not
+ continue to the subregions. This gives you a O(1) dispatch
+ instead of O(number of regions).</para>
+ </listitem>
+ </itemizedlist></para>
+ </sect2>
+ <sect2>
+ <title>Other state types</title>
+ <para>We saw the <command xlink:href="#eUML-build-state">build_state</command>
+ function, which creates a simple state. Likewise, eUML provides other
+ state-building macros for other types of states:<itemizedlist>
+ <listitem>
+ <para>BOOST_MSM_EUML_TERMINATE_STATE takes the same arguments as
+ BOOST_MSM_EUML_STATE and defines, well, a terminate
+ state.</para>
+ </listitem>
+ <listitem>
+ <para>BOOST_MSM_EUML_INTERRUPT_STATE takes the same arguments as
+ BOOST_MSM_EUML_STATE and defines an interrupt state. However,
+ the expression argument must contain as first element the event
+ ending the interruption, for example:
+ <code>BOOST_MSM_EUML_INTERRUPT_STATE(( end_error /*end
+ interrupt event*/,ErrorMode_Entry,ErrorMode_Exit
+ ),ErrorMode)</code></para>
+ </listitem>
+ <listitem>
+ <para>BOOST_MSM_EUML_EXIT_STATE takes the same arguments as
+ BOOST_MSM_EUML_STATE and defines an exit pseudo state. However,
+ the expression argument must contain as first element the event
+ propagated from the exit point:
+ <code>BOOST_MSM_EUML_EXIT_STATE(( event6 /*propagated
+ event*/,PseudoExit1_Entry,PseudoExit1_Exit
+ ),PseudoExit1)</code></para>
+ </listitem>
+ <listitem>
+ <para>BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE defines an entry pseudo
+ state. It takes 3 parameters: the region index to be entered is
+ defined as an int argument, followed by the configuration
+ expression like BOOST_MSM_EUML_STATE and the state name, so that
+ <code>BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(0 /*region
+ index*/,( SubState2_Entry,SubState2_Exit ),SubState2)</code>
+ defines an entry state into the first region of a
+ submachine.</para>
+ </listitem>
+ <listitem>
+ <para>BOOST_MSM_EUML_ENTRY_STATE defines an entry pseudo state. It
+ takes 3 parameters: the region index to be entered is defined as
+ an int argument, followed by the configuration expression like
+ BOOST_MSM_EUML_STATE and the state name, so that
+ <code>BOOST_MSM_EUML_ENTRY_STATE(0,(
+ PseudoEntry1_Entry,PseudoEntry1_Exit ),PseudoEntry1)</code>
+ defines a pseudo entry state into the first region of a
+ submachine.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>To use these states in the transition table, eUML offers the functions
+ <code>explicit_</code>, <code>exit_pt_</code> and
+ <code>entry_pt_</code>. For example, a direct entry into the substate
+ SubState2 from SubFsm2 could be:</para>
+ <programlisting>explicit_(SubFsm2,SubState2) == State1 + event2</programlisting>
+ <para>Forks being a list on direct entries, eUML supports a logical syntax
+ (state1, state2, ...), for example:</para>
+ <programlisting>(explicit_(SubFsm2,SubState2),
+ explicit_(SubFsm2,SubState2b),
+ explicit_(SubFsm2,SubState2c)) == State1 + event3 </programlisting>
+ <para>An entry point is entered using the same syntax as explicit entries:
+ <programlisting>entry_pt_(SubFsm2,PseudoEntry1) == State1 + event4</programlisting></para>
+ <para>For exit points, it is again the same syntax except that exit points are
+ used as source of the transition:
+ <programlisting>State2 == exit_pt_(SubFsm2,PseudoExit1) + event6 </programlisting></para>
+ <para>The <link xlink:href="examples/DirectEntryEuml.cpp">entry tutorial</link>
+ is also available with eUML.</para>
+ </sect2>
+ <sect2>
+ <title>Helper functions</title>
+ <para>We saw a few helpers but there are more, so let us have a more complete description:<itemizedlist>
+ <listitem>
+ <para>event_ : used inside any action, the event triggering the
+ transition</para>
+ </listitem>
+ <listitem>
+ <para>state_: used inside entry and exit actions, the entered /
+ exited state</para>
+ </listitem>
+ <listitem>
+ <para>source_: used inside a transition action, the source
+ state</para>
+ </listitem>
+ <listitem>
+ <para>target_: used inside a transition action, the target
+ state</para>
+ </listitem>
+ <listitem>
+ <para>fsm_: used inside any action, the (deepest-level) state
+ machine processing the transition</para>
+ </listitem>
+ <listitem>
+ <para>These objects can also be used as a function and return an
+ attribute, for example event_(cd_name)</para>
+ </listitem>
+ <listitem>
+ <para>Int_<int value>: a functor representing an int</para>
+ </listitem>
+ <listitem>
+ <para>Char_<value>: a functor representing a char</para>
+ </listitem>
+ <listitem>
+ <para>Size_t_<value>: a functor representing a size_t</para>
+ </listitem>
+ <listitem>
+ <para>True_ and False_ functors returning true and false
+ respectively</para>
+ </listitem>
+ <listitem>
+ <para>String_<mpl::string> (boost >= 1.40): a functor
+ representing a string.</para>
+ </listitem>
+ <listitem>
+ <para>if_then_else_(guard, action, action) where action can be an
+ action sequence</para>
+ </listitem>
+ <listitem>
+ <para>if_then_(guard, action) where action can be an action
+ sequence</para>
+ </listitem>
+ <listitem>
+ <para>while_(guard, action) where action can be an action
+ sequence</para>
+ </listitem>
+ <listitem>
+ <para>do_while_(guard, action) where action can be an action
+ sequence</para>
+ </listitem>
+ <listitem>
+ <para>for_(action, guard, action, action) where action can be an
+ action sequence</para>
+ </listitem>
+ <listitem>
+ <para>process_(some_event [, some state machine] [, some state
+ machine] [, some state machine] [, some state machine]) will
+ call process_event (some_event) on the current state machine or
+ on the one(s) passed as 2nd , 3rd, 4th, 5th argument. This allow
+ sending events to several external machines</para>
+ </listitem>
+ <listitem>
+ <para>process2_(some_event,Value [, some state machine] [, some
+ state machine] [, some state machine]) will call process_event
+ (some_event(Value)) on the current state machine or on the
+ one(s) passed as 3rd, 4th, 5th argument</para>
+ </listitem>
+ <listitem>
+ <para>is_ flag_(some_flag[, some state machine]) will call
+ is_flag_active on the current state machine or on the one passed
+ as 2nd argument</para>
+ </listitem>
+ <listitem>
+ <para>Predicate_<some predicate>: Used in STL algorithms. Wraps
+ unary/binary functions to make them eUML-compatible so that they
+ can be used in STL algorithms</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>This can be quite fun. For example, </para>
+ <programlisting>/( if_then_else_(--fsm_(m_SongIndex) > Int_<0>(),/*if clause*/
+ show_playing_song, /*then clause*/
+ (fsm_(m_SongIndex)=Int_<1>(),process_(EndPlay))/*else clause*/
+ )
+ )</programlisting>
+ <para>means: if (fsm.SongIndex > 0, call show_playing_song else
+ {fsm.SongIndex=1; process EndPlay on fsm;}</para>
+ <para>A few examples are using these features:<itemizedlist>
+ <listitem>
+ <para>the iPod example introduced at the BoostCon09 <link
+ xlink:href="examples/iPodEuml.cpp">has been rewritten</link>
+ with eUML (weak compilers please move on...)</para>
+ </listitem>
+ <listitem>
+ <para>the iPodSearch example also introduced at the BoostCon09 <link
+ xlink:href="examples/iPodSearchEuml.cpp">has been
+ rewritten</link> with eUML. In this example, you will also
+ find some examples of STL functor usage.</para>
+ </listitem>
+ <listitem>
+ <para><link xlink:href="examples/SimpleTimer.cpp">A simpler
+ timer</link> example is a good starting point. </para>
+ </listitem>
+ </itemizedlist></para>
+ <para>There is unfortunately a small catch. Defining a functor using
+ MSM_EUML_METHOD or MSM_EUML_FUNCTION will create a correct functor. Your own
+ eUML functors written as described at the beginning of this section will
+ also work well, <emphasis role="underline">except</emphasis>, for the
+ moment, with the while_, if_then_, if_then_else_ functions.</para>
+ </sect2>
+ <sect2>
+ <title>Phoenix-like STL support</title>
+ <para>eUML supports most C++ operators (except address-of). For example it is
+ possible to write event_(some_attribute)++ or [source_(some_bool) &&
+ fsm_(some_other_bool)]. But a programmer needs more than operators in his
+ daily programming. The STL is clearly a must have. Therefore, eUML comes in
+ with a lot of functors to further reduce the need for your own functors for
+ the transition table. For almost every algorithm or container method of the
+ STL, a corresponding eUML function is defined. Like Boost.Phoenix, â.â And
+ â->â of call on objects are replaced by a functional programming paradigm,
+ for example:<itemizedlist>
+ <listitem>
+ <para>begin_(container), end_(container): return iterators of a
+ container.</para>
+ </listitem>
+ <listitem>
+ <para>empty_(container): returns container.empty()</para>
+ </listitem>
+ <listitem>
+ <para>clear_(container): container.clear()</para>
+ </listitem>
+ <listitem>
+ <para>transform_ : std::transform</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>In a nutshell, almost every STL method or algorithm is matched by a
+ corresponding functor, which can then be used in the transition table or
+ state actions. The <link xlink:href="#Reference-begin">reference</link>
+ lists all eUML functions and the underlying functor (so that this
+ possibility is not reserved to eUML but also to the functor-based
+ front-end). The file structure of this Phoenix-like library matches the one
+ of Boost.Phoenix. All functors for STL algorithms are to be found in:</para>
+ <programlisting>#include <msm/front/euml/algorithm.hpp></programlisting>
+ <para>The algorithms are also divided into sub-headers, matching the phoenix
+ structure for simplicity:</para>
+ <programlisting>#include < msm/front/euml/iteration.hpp>
+#include < msm/front/euml/transformation.hpp>
+#include < msm/front/euml/querying.hpp> </programlisting>
+ <para>Container methods can be found in:</para>
+ <programlisting>#include < msm/front/euml/container.hpp></programlisting>
+ <para>Or one can simply include the whole STL support (you will also need to
+ include euml.hpp):</para>
+ <programlisting>#include < msm/front/euml/stl.hpp></programlisting>
+ <para>A few examples (to be found in <link
+ xlink:href="examples/iPodSearchEuml.cpp">this tutorial</link>):<itemizedlist>
+ <listitem>
+ <para><code>push_back_(fsm_(m_tgt_container),event_(m_song))</code>:
+ the state machine has an attribute m_tgt_container of type
+ std::vector<OneSong> and the event has an attribute m_song of
+ type OneSong. The line therefore pushes m_song at the end of
+ m_tgt_container</para>
+ </listitem>
+ <listitem>
+ <para><code>if_then_( state_(m_src_it) !=
+ end_(fsm_(m_src_container)),
+ process2_(OneSong(),*(state_(m_src_it)++)) )</code>: the
+ current state has an attribute m_src_it (an iterator). If this
+ iterator != fsm.m_src_container.end(), process OneSong on fsm,
+ copy-constructed from state.m_src_it which we
+ post-increment</para>
+ </listitem>
+ </itemizedlist></para>
+ </sect2>
+ </sect1>
+ <sect1>
+ <title>Back-end</title>
+ <para>There is, at the moment, one back-end. This back-end contains the library
+ engine and defines the performance and functionality trade-offs. The currently
+ available back-end implements most of the functionality defined by the UML 2.0
+ standard at very high runtime speed, in exchange for longer compile-time. The
+ runtime speed is due to a constant-time double-dispatch and self-adapting
+ capabilities allowing the framework to adapt itself to the features used by a
+ given concrete state machine. All unneeded features either disable themselves or
+ can be manually disabled. See section 5.1 for a complete description of the
+ run-to-completion algorithm.</para>
+ <sect2>
+ <title>Creation </title>
+ <para>MSM being divided between front and back-end, one needs to first define a
+ front-end. Then, to create a real state machine, the back-end must be
+ declared:
+ <programlisting>typedef msm::back::state_machine<my_front_end> my_fsm;</programlisting></para>
+ <para>We now have a fully functional state machine type. The next sections will
+ describe what can be done with it.</para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="backend-start"/>Starting a state machine</title>
+ <para>The <code>start</code> method starts the state machine, meaning it will
+ activate the initial state, which means in turn that the initial state's
+ entry behavior will be called. We need the start method because you do not
+ always want the entry behavior of the initial state to be called immediately
+ but only when your state machine is ready to process events. A good example
+ of this is when you use a state machine to write an algorithm and each loop
+ back to the initial state is an algorithm call. Each call to start will make
+ the algorithm run once. The <link xlink:href="examples/iPodSearch.cpp"
+ >iPodSearch</link> example uses this possibility.</para>
+ </sect2>
+ <sect2>
+ <title>Event dispatching</title>
+ <para>The main reason to exist for a state machine is to dispatch events. For
+ MSM, events are objects of a given event type. The object itself can contain
+ data, but the event type is what decides of the transition to be taken. For
+ MSM, if some_event is a given type (a simple struct for example) and e1 and
+ e2 concrete instances of some_event, e1 and e2 are equivalent, from a
+ transition perspective. Of course, e1 and e2 can have different values and
+ you can use them inside actions. Events are dispatched as const reference,
+ so actions cannot modify events for obvious side-effect reasons. To dispatch
+ an event of type some_event, you can simply create one on the fly or
+ instantiate if before processing: </para>
+ <programlisting>my_fsm fsm; fsm.process_event(some_event());
+some_event e1; fsm.process_event(e1)</programlisting>
+ <para>Creating an event on the fly will be optimized by the compiler so the
+ performance will not degrade.</para>
+ </sect2>
+ <sect2>
+ <title>Active state(s)</title>
+ <para>The backend also offers a way to know which state is active, though you
+ will normally only need this for debugging purposes. If what you need simply
+ is doing something with the active state, <command
+ xlink:href="#UML-internal-transition">internal transitions</command> or
+ <command xlink:href="#backend-visitor">visitors</command> are a better
+ alternative. If you need to know what state is active, const int*
+ current_state() will return an array of state ids. Please refer to the
+ <command xlink:href="#internals-state-id">internals section</command> to
+ know how state ids are generated.</para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="backend-base-state"/>Base state type </title>
+ <para>Sometimes, one needs to customize states to avoid repetition and provide a
+ common functionality, for example in the form of a virtual method. You might
+ also want to make your states polymorphic so that you can call typeid on
+ them for logging or debugging. It is also useful if you need a visitor, like
+ the next section will show. You will notice that all front-ends offer the
+ possibility of adding a base type. Note that all states and state machines
+ must have the same base state, so this could reduce reuse. For example,
+ using the basic front end, you need to:<itemizedlist>
+ <listitem>
+ <para>Add the non-default base state in your msm::front::state<>
+ definition, as first template argument (except for
+ interrupt_states for which it is the second argument, the first
+ one being the event ending the interrupt), for example,
+ my_base_state being your new base state for all states in a
+ given state machine:
+ <programlisting>struct Empty : public msm::front::state<my_base_state></programlisting>
+ Now, my_base_state is your new base state. If it has a virtual
+ function, your states become polymorphic. MSM also provides a
+ default polymorphic base type,
+ <code>msm::front::polymorphic_state</code>
+ </para>
+ </listitem>
+ <listitem>
+ <para>Add the user-defined base state in the state machine frontend
+ definition, as a second template argument, for example:
+ <programlisting>struct player_ : public msm::front::state_machine<player_,my_base_state> </programlisting></para>
+ </listitem>
+ </itemizedlist></para>
+ <para>You can also ask for a state with a given id (which you might have gotten
+ from current_state()) using <code>const base_state* get_state_by_id(int id)
+ const</code> where base_state is the one you just defined. You can now
+ do something polymorphically.</para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="backend-visitor"/>Visitor</title>
+ <para>In some cases, having a pointer-to-base of the currently active states is
+ not enough. You might want to call non-virtually a method of the currently
+ active states. It will not be said that MSM forces the virtual keyword down
+ your throat!</para>
+ <para>To achieve this goal, MSM provides its own variation of a visitor pattern
+ using the previously described user-defined state technique. If you add to
+ your user-defined base state an <code>accept_sig</code> typedef giving the
+ return value (unused for the moment) and parameters and provide an accept
+ method with this signature, calling visit_current_states will cause accept
+ to be called on the currently active states. Typically, you will also want
+ to provide an empty default accept in your base state in order in order not
+ to force all your states to implement accept. For example your base state
+ could be:</para>
+ <programlisting>struct my_visitable_state
+{
+ // signature of the accept function
+ typedef args<void> accept_sig;
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept() const {}
+};</programlisting>
+ <para>This makes your states polymorphic and visitable. In this case, accept is
+ made const and takes no argument. It could also be:</para>
+ <programlisting>struct SomeVisitor {â¦};
+struct my_visitable_state
+{
+ // signature of the accept function
+ typedef args<void,SomeVisitor&> accept_sig;
+ // we also want polymorphic states
+ virtual ~my_visitable_state() {}
+ // default implementation for states who do not need to be visited
+ void accept(SomeVisitor&) const {}
+};</programlisting>
+ <para>And now, <code>accept</code> will take one argument (it could also be
+ non-const). By default, <code>accept</code> takes up to 2 arguments. To get
+ more, set #define BOOST_MSM_VISITOR_ARG_SIZE to another value before
+ including state_machine.hpp. For example:</para>
+ <programlisting>#define BOOST_MSM_VISITOR_ARG_SIZE 3
+#include <boost/msm/back/state_machine.hpp></programlisting>
+ <para>Note that accept will be called on ALL active states <emphasis
+ role="underline">and also automatically on sub-states of a
+ submachine</emphasis>.</para>
+ <para><emphasis role="underline">Important warning</emphasis>: The method
+ visit_current_states takes its parameter by value, so if the signature of
+ the accept function is to contain a parameter passed by reference, pass this
+ parameter with a boost:ref/cref to avoid undesired copies or slicing. So,
+ for example, in the above case, call:</para>
+ <programlisting>SomeVisitor vis; sm.visit_current_states(boost::ref(vis));</programlisting>
+ <para>This <link xlink:href="examples/SM-2Arg.cpp">example</link> uses a
+ visiting function with 2 arguments.</para>
+ </sect2>
+ <sect2>
+ <title>Flags</title>
+ <para>Flags is a MSM-only concept, supported by all front-ends, which base
+ themselves on the functions: </para>
+ <programlisting>template <class Flag> bool is_flag_active()
+template <class Flag,class BinaryOp> bool is_flag_active()</programlisting>
+ <para>These functions return true if the currently active state(s) support the
+ Flag property. The first variant ORs the result if there are several
+ orthogonal regions, the second one expects OR or AND, for example:</para>
+ <programlisting>my_fsm.is_flag_active<MyFlag>()
+my_fsm.is_flag_active<MyFlag,my_fsm_type::Flag_OR>()</programlisting>
+ <para>Please refer to the front-ends sections for usage examples.</para>
+ </sect2>
+ <sect2>
+ <title>Getting a state</title>
+ <para>It is sometimes necessary to have the client code get access to the
+ states' data. After all, the states are created once for good and hang
+ around as long as the state machine does so why not use it? You simply just
+ need sometimes to get information about any state, even inactive ones. An
+ example is if you want to write a coverage tool and know how many times a
+ state was visited. To get a state, use the get_state method giving the state
+ name, for example: </para>
+ <programlisting>player::Stopped* tempstate = p.get_state<player::Stopped*>();</programlisting>
+ <para> or </para>
+ <programlisting>player::Stopped& tempstate2 = p.get_state<player::Stopped&>();</programlisting>
+ <para>depending on your personal taste. </para>
+ </sect2>
+ <sect2>
+ <title> State machine constructor with arguments </title>
+ <para>You might want to define a state machine with a non-default constructor.
+ For example, you might want to write: </para>
+ <programlisting>struct player_ : public msm::front::state_machine_def<player_>
+{
+ player_(int some_value){â¦}
+}; </programlisting>
+ <para>This is possible, using the back-end as forwarding object: </para>
+ <programlisting>typedef msm::back::state_machine<player_ > player; player p(3);</programlisting>
+ <para>The back-end will call the corresponding front-end constructor upon
+ creation.</para>
+ <para>You can pass arguments up to the value of the
+ BOOST_MSM_CONSTRUCTOR_ARG_SIZE macro (currently 5) arguments. Change this
+ value before including any header if you need to overwrite the default.
+ </para>
+ </sect2>
+ <sect2>
+ <title><command xml:id="backend-tradeof-rt-ct"/>Trading run-time speed for
+ better compile-time / multi-TU compilation</title>
+ <para>MSM is optimized for run-time speed at the cost of longer compile-time.
+ This can become a problem with older compilers and big state machines,
+ especially if you don't really care about run-time speed that much and would
+ be satisfied by a performance roughly the same as most state machine
+ libraries. MSM offers a back-end policy to help there. But before you try
+ it, if you are using a VC compiler, deactivate the /Gm compiler option
+ (default for debug builds). This option can cause builds to be 3 times
+ longer... If the compile-time still is a problem, read further. MSM offers a
+ policy which will speed up compiling in two main cases:<itemizedlist>
+ <listitem>
+ <para>many transition conflicts</para>
+ </listitem>
+ <listitem>
+ <para>submachines</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>The back-end <code>msm::back::state_machine</code> has a third template
+ argument (first is the front-end, second is the history policy) defaulting
+ to <code>favor_runtime_speed</code>. To switch to
+ <code>favor_compile_time</code>, which is declared in
+ <code><msm/back/favor_compile_time.hpp></code>, you need to:<itemizedlist>
+ <listitem>
+ <para>switch the policy to <code>favor_compile_time</code> for the
+ main state machine (and possibly submachines)</para>
+ </listitem>
+ <listitem>
+ <para>move the submachine declarations into their own header which
+ includes
+ <code><msm/back/favor_compile_time.hpp></code></para>
+ </listitem>
+ <listitem>
+ <para>add for each submachine a cpp file including your header and
+ calling a macro, which generates helper code, for
+ example:</para>
+ <programlisting>#include "mysubmachine.hpp"
+BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(mysubmachine)</programlisting>
+ </listitem>
+ <listitem>
+ <para>configure your compiler for multi-core compilation</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>You will now compile your state machine on as many cores as you have
+ submachines, which will greatly speed up the compilation if you factor your
+ state machine into smaller submachines.</para>
+ <para>Independently, transition conflicts resolution will also be much
+ faster.</para>
+ <para>This policy uses boost.any behind the hood, which means that we will lose
+ one feature which MSM offers with the default policy, <link
+ xlink:href="#event-hierarchy">event hierarchy</link>. The following
+ example takes our iPod example and speeds up compile-time by using this
+ technique. We have:<itemizedlist>
+ <listitem>
+ <para><link xlink:href="examples/iPod_distributed/iPod.cpp">our main
+ state machine and main function</link></para>
+ </listitem>
+ <listitem>
+ <para><link xlink:href="examples/iPod_distributed/PlayingMode.hpp"
+ >PlayingMode moved to a separate header</link></para>
+ </listitem>
+ <listitem>
+ <para><link xlink:href="examples/iPod_distributed/PlayingMode.cpp">a
+ cpp for PlayingMode</link></para>
+ </listitem>
+ <listitem>
+ <para><link xlink:href="examples/iPod_distributed/MenuMode.hpp"
+ >MenuMode moved to a separate header</link></para>
+ </listitem>
+ <listitem>
+ <para><link xlink:href="examples/iPod_distributed/MenuMode.cpp">a
+ cpp for MenuMode</link></para>
+ </listitem>
+ <listitem>
+ <para><link xlink:href="examples/iPod_distributed/Events.hpp">events
+ move to a separate header as all machines use
+ it</link></para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+ </sect1>
+ </chapter>
+ <chapter>
+ <title> Performance / Compilers</title>
+ <para>Tests were made on different PCs running Windows XP and Vista and compiled with
+ VC9 SP1 or Ubuntu and compiled with g++ 4.2 and 4.3. For these tests, the same
+ player state machine was written using Boost.Statechart, as a <link
+ xlink:href="examples/SC Simple.cpp">state machine with only simple states</link>
+ and as a <link xlink:href="examples/SC Composite.cpp">state machine with a composite
+ state</link>. The same simple and composite state machines are implemented with
+ MSM with a standard frontend <link xlink:href="examples/MsmSimple.cpp"
+ >(simple)</link><link xlink:href="examples/MsmComposite.cpp">(composite)</link>,
+ the simple one also with <link xlink:href="examples/MsmSimpleFunctors.cpp"
+ >functors</link> and with <link xlink:href="examples/EumlSimple.cpp"
+ >eUML</link>. As these simple machines need no terminate/interrupt states, no
+ message queue and have no-throw guarantee on their actions, the MSM state machines
+ are defined with minimum functionality. Test machine is a Q6600 2.4GHz, Vista
+ 64.</para>
+ <sect1>
+ <title>Speed</title>
+ <para>VC9:<itemizedlist>
+ <listitem>
+ <para>The simple test completes 90 times faster with MSM than with
+ Boost.Statechart</para>
+ </listitem>
+ <listitem>
+ <para>The composite test completes 25 times faster with MSM</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>gcc 4.2.3 (Ubuntu 8.04 in VMWare, same PC):<itemizedlist>
+ <listitem>
+ <para>The simple test completes 46 times faster with MSM</para>
+ </listitem>
+ <listitem>
+ <para>The composite test completes 19 times faster with Msm</para>
+ </listitem>
+ </itemizedlist></para>
+ </sect1>
+ <sect1>
+ <title>Executable size</title>
+ <para>There are some worries that MSM generates huge code. Is it true? The 2
+ compilers I tested disagree with this claim. On VC9, the test state machines
+ used in the performance section produce executables of 14kB (for simple and
+ eUML) and 21kB (for the composite). This includes the test code and iostreams.
+ By comparison, an empty executable with iostreams generated by VC9 has a size of
+ 7kB. Boost.Statechart generates executables of 43kB and 54kB. As a bonus, eUML
+ comes for âfreeâ in terms of executable size. You even get a speed gain. With
+ g++ 4.3, it strongly depends on the compiler options (much more than VC). A good
+ size state machine with âO3 can generate an executable of 600kB, and with eUML
+ you can get to 1.5MB. Trying with âOs âs I come down to 18kB and 30kB for the
+ test state machines, while eUML will go down to 1MB (which is still big), so in
+ this case eUML does not come for free.</para>
+ </sect1>
+ <sect1>
+ <title>Supported compilers</title>
+ <para> MSM was successfully tested with: <itemizedlist>
+ <listitem>
+ <para>VC8 (please read further), VC9SP1, VC10 Beta 1 and 2</para>
+ </listitem>
+ <listitem>
+ <para>g++ 4.1 and higher</para>
+ </listitem>
+ <listitem>
+ <para>Green Hills Software MULTI for ARM v5.0.5 patch 4416 (Simple and
+ Composite tutorials)</para>
+ </listitem>
+ </itemizedlist></para>
+ <para> eUML will only work with: <itemizedlist>
+ <listitem>
+ <para>VC8 (partly). You cannot, however use any overloaded function
+ (like splice) and compile times and RAM consumption explode</para>
+ </listitem>
+ <listitem>
+ <para>VC9SP1, VC10 Beta1-2</para>
+ </listitem>
+ <listitem>
+ <para>g++ 4.3 and higher (previous versions lack native typeof
+ support)</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>VC8 and to some lesser extent VC9 suffer from a bug. Enabling the option
+ "Enable Minimal Rebuild" (/Gm) will cause much higher compile-time (up to three
+ times with VC8!). This option being activated per default in Debug mode, this
+ can be a big problem.</para>
+ </sect1>
+ <sect1>
+ <title> Limitations </title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Compilation times of state machines with > 80 transitions that are
+ going to make you storm the CFO's office and make sure you get a
+ shiny octocore with 12GB RAM by next week, unless he's interested in
+ paying you watch the compiler agonize for hours... (Make sure you
+ ask for dual 24" as well, it doesn't hurt).</para>
+ </listitem>
+ <listitem>
+ <para>eUML allows very long constructs but will also quickly increase
+ your compile time on some compilers (VC9, VC10 Beta1) with buggy
+ decltype support (I suspect some at least quadratic algorithms
+ there). Even g++ 4.4 shows some regression compared to 4.3 and will
+ crash if the constructs become too big.</para>
+ </listitem>
+ <listitem>
+ <para>Need to overwrite the mpl::vector/list default-size-limit of 20
+ and fusion default vector size of 10 if more than 10 states found in
+ a state machine</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+ <sect1>
+ <title> Compilers corner </title>
+ <para>Compilers are sometimes full of surprises and such strange errors happened in
+ the course of the development that I wanted to list the most fun for readersâ
+ entertainment.</para>
+ <para><emphasis role="underline">VC8</emphasis>: </para>
+ <programlisting>template <class StateType>
+typename ::boost::enable_if<
+ typename ::boost::mpl::and_<
+ typename ::boost::mpl::not_<
+ typename has_exit_pseudo_states<StateType>::type
+ >::type,
+ typename ::boost::mpl::not_<
+ typename is_pseudo_exit<StateType>::type
+ >::type
+ >::type,
+ BaseState*>::type </programlisting>
+ <para>I get the following error:</para>
+ <para>error C2770: invalid explicit template argument(s) for '`global
+ namespace'::boost::enable_if<...>::...' </para>
+ <para>If I now remove the first â::â in ::boost::mpl , the compiler shuts up. So in
+ this case, it is not possible to follow Boostâs guidelines.</para>
+ <para><emphasis role="underline">VC9</emphasis>:<itemizedlist>
+ <listitem>
+ <para>This one is my all timesâ favorite. Do you know why the exit
+ pseudo states are referenced in the transition table with a
+ âsubmachine::exit_ptâ ? Because âexitâ will crash the compiler.
+ âExitâ is not possible either because it will crash the compiler on
+ one machine, but not on another (the compiler was installed from the
+ same disk).</para>
+ </listitem>
+ <listitem>
+ <para>Sometimes, removing a policy crashes the compiler, so some
+ versions are defining a dummy policy called WorkaroundVC9.</para>
+ </listitem>
+ <listitem>
+ <para>Typeof: While g++ and VC9 compile âstandardâ state machines in
+ comparable times, Typeof (while in both ways natively supported)
+ seems to behave in a quadratic complexity with VC9 and VC10.</para>
+ </listitem>
+ <listitem>
+ <para>eUML: in case of a compiler crash, changing the order of state
+ definitions (first states without entry or exit) sometimes solves
+ the problem.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para><emphasis role="underline">g++ 4.x</emphasis>: Boring compiler, almost all is
+ working almost as expected. Being not a language lawyer I am unsure about the
+ following âTypeof problemâ. VC9 and g++ disagree on the question if you can
+ derive from the BOOST_TYPEOF generated type without first defining a typedef. I
+ will be thankful for an answer on this. I only found two ways to break the compiler:<itemizedlist>
+ <listitem>
+ <para>Add more eUML constructs until something explodes (especially with
+ g++-4.4) </para>
+ </listitem>
+ <listitem>
+ <para>The build_terminate function uses 2 mpl::push_back instead of
+ mpl::insert_range because g++ would not accept insert_range.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>You can test your compilerâs decltype implementation with the <link
+ xlink:href="examples/CompilerStressTestEuml.cpp">following stress
+ test</link> and reactivate the commented-out code until the compiler
+ crashes.</para>
+ </sect1>
+ </chapter>
+ <chapter>
+ <title>Questions & Answers</title>
+ <para><emphasis role="underline">Question</emphasis>: on_entry gets as argument, the
+ sent event. What event do I get when the state becomes default-activated (because it
+ is an initial state)?</para>
+ <para>
+ <emphasis role="underline">Answer</emphasis>: To allow you to know that the state
+ was default-activated, MSM generates a boost::msm::InitEvent default event. </para>
+ <para><emphasis role="underline">Question</emphasis>: Why do I see no call to
+ no_transition in my submachine? </para>
+ <para><emphasis role="underline">Answer</emphasis>: Because of the priority rule defined
+ by UML. It says that in case of transition conflict, the most inner state has a
+ higher priority. So after asking the inner state, the containing composite has to be
+ also asked to handle the transition and could find a possible transition.</para>
+ <para><emphasis role="underline">Question</emphasis>: Why do I get a compile error
+ saying the compiler cannot convert to a function ...Fsm::*(some_event)? </para>
+ <para><emphasis role="underline">Answer</emphasis>: You probably defined a transition
+ triggered by the event some_event, but used a guard/action method taking another
+ event. </para>
+ <para><emphasis role="underline">Question</emphasis>: Why do I get a compile error
+ saying something like âtoo fewâ or âtoo manyâ template arguments? </para>
+ <para><emphasis role="underline">Answer</emphasis>: You probably defined a transition in
+ form of a a_row or g_row where you wanted just a _row or the other way around. With
+ Row, it could mean that you forgot a "none". </para>
+ <para><emphasis role="underline">Question</emphasis>: Why do I get a very long compile
+ error when I define more than 20 rows in the transition table? </para>
+ <para><emphasis role="underline">Answer</emphasis>: MSM uses Boost.MPL under the hood
+ and this is the default maximum size. Please define the following 3 macros before
+ including any MSM headers: </para>
+ <programlisting>#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS
+#define BOOST_MPL_LIMIT_VECTOR_SIZE 30 // or whatever you need
+#define BOOST_MPL_LIMIT_MAP_SIZE 30 // or whatever you need </programlisting>
+ <para><emphasis role="underline">Question</emphasis>: Why do I get this error: âerror
+ C2977: 'boost::mpl::vector' : too many template argumentsâ? </para>
+ <para><emphasis role="underline">Answer</emphasis>: The first possibility is that you
+ defined a transition table as, say, vector17 and have 18 entries. The second is that
+ you have 17 entries and have a composite state. Under the hood, MSM adds a row for
+ every event in the composite transition table. The third one is that you used a
+ mpl::vector without the number of entries but are close to the MPL default of 50 and
+ have a composite, thus pushing you above 50. Then you need mpl/vector60/70â¦.hpp and
+ a mpl/map60/70â¦.hpp </para>
+ <para><emphasis role="underline">Question</emphasis>: Why do I get a very long compile
+ error when I define more than 10 states in a state machine? </para>
+ <para><emphasis role="underline">Answer</emphasis>: MSM uses Boost.Fusion under the hood
+ and this is the default maximum size. Please define the following macro before
+ including any MSM headers: </para>
+ <programlisting>#define FUSION_MAX_VECTOR_SIZE 20 // or whatever you need </programlisting>
+ </chapter>
+ <chapter>
+ <title>Internals</title>
+ <para>This chapter describes the internal machinery of the back-end, which can be useful
+ for UML experts but can be safely ignored for most users. For implementers, the
+ interface between front- and back- end is also described in detail.</para>
+ <sect1>
+ <title><command xml:id="run-to-completion"/>Backend: Run To Completion</title>
+ <para>The back-end implements the following run-to completion algorithm:<itemizedlist>
+ <listitem>
+ <para>Check if one region of the concrete state machine is in a
+ terminate or interrupt state. If yes, event processing is disabled
+ while the condition lasts (forever for a terminate pseudo-state,
+ while active for an interrupt pseudo-state).</para>
+ </listitem>
+ <listitem>
+ <para>If the message queue feature is enabled and if the state machine
+ is already processing an event, push the currently processed event
+ into the queue and end processing. Otherwise, remember that the
+ state machine is now processing an event and continue.</para>
+ </listitem>
+ <listitem>
+ <para>If the state machine detected that no deferred event is used, skip
+ this step. Otherwise, mark the first deferred event from the
+ deferred queue as active.</para>
+ </listitem>
+ <listitem>
+ <para>Now start the core of event dispatching. If exception handling is
+ activated, this will happen inside a try/catch block and the
+ front-end <code>exception_caught</code> is called if an exception
+ occurs. </para>
+ </listitem>
+ <listitem>
+ <para>The event is now dispatched in turn to every region, in the order
+ defined by the initial state front-end definition. This will, for
+ every region, call the corresponding front-end transition definition
+ (the "row" or "Row" of the transition table).</para>
+ </listitem>
+ <listitem>
+ <para>Without transition conflict, if for a given region a transition is
+ possible, the guard condition is checked. If it returns
+ <code>true</code>, the transition processing continues and the
+ current state's exit action is called, followed by the transition
+ action behavior and the new active state's entry behavior.</para>
+ </listitem>
+ <listitem>
+ <para>With transition conflicts (several possible transitions,
+ disambiguated by mutually exclusive guard conditions), the guard
+ conditions are tried in reverse order of their transition definition
+ in the transition table. The first one returning <code>true</code>
+ selects its transition. Note that this is not defined by the UML
+ standard, which simply specifies that if the guard conditions are
+ not mutually exclusive, the state machine is ill-formed and the
+ behaviour undefined. Relying on this implementation-specific
+ behaviour will make it harder for the developer to support another
+ state machine framework.</para>
+ </listitem>
+ <listitem>
+ <para>If at least one region processes the event, this event is seen as
+ having been accepted. If not, the library calls
+ <code>no_transition</code> on the state machine for every
+ contained region.</para>
+ </listitem>
+ <listitem>
+ <para>If the currently active state is a submachine, the behaviour is
+ slightly different. The UML standard specifies that internal
+ transitions have to be tried first, so the event is first dispatched
+ to the submachine. Only if the submachine does not accept the event
+ are other (non internal) transitions tried.</para>
+ </listitem>
+ <listitem>
+ <para>This back-end supports simple states' and submachines' internal
+ transitions. These are provided in the state's
+ <code>internal_transition_table</code> type. Transitions defined
+ in this table are added at the end of the main state machine's
+ transition table, but with a lesser priority than the submachine's
+ transitions (defined in <code>transition_table</code>). This means,
+ for simple states, that these transitions have higher priority than
+ non-internal transitions, conform to the UML standard which gives
+ higher priority to deeper-level transitions. For submachines, this
+ is a non-standard addition which can help make event processing
+ faster by giving a chance to bypass subregion processing. With
+ standard UML, one would need to add a subregion only to process
+ these internal transitions, which would be slower.</para>
+ </listitem>
+ <listitem>
+ <para>After the dispatching itself, the deferred event marked in step 3
+ (if any) now gets a chance of processing.</para>
+ </listitem>
+ <listitem>
+ <para>Then, events queued in the message queue also get a dispatching
+ chance</para>
+ </listitem>
+ <listitem>
+ <para>Finally, completion / anonymous transitions, if to be found in the
+ transition table, also get their dispatching chance.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>This algorithm illustrates how the back-end configures itself at compile-time
+ as much as possible. Every feature not found in a given state machine definition
+ is deactivated and has therefore no runtime cost. Completion events, deferred
+ events, terminate states, dispatching to several regions, internal transitions
+ are all deactivated if not used. User configuration is only for exception
+ handling and message queue necessary.</para>
+ </sect1>
+ <sect1>
+ <title><command xml:id="internals-front-back-interface"/>Frontend / Backend
+ interface</title>
+ <para>The design of MSM tries to make front-ends and back-ends (later) to be as
+ interchangeable as possible. Of course, no back-end will ever implement every
+ feature defined by any possible front-end and inversely, but the goal is to make
+ it as easy as possible to extend the current state of the library.</para>
+ <para>To achieve this, MSM divides the functionality between both sides: the
+ front-end is a sort of user interface and is descriptive, the back-end
+ implements the state machine engine.</para>
+ <para>MSM being based on a transition table, a concrete state machine (or a given
+ front-end) must provide a transition_table. This transition table must be made
+ of rows. And each row must tell what kind of transition it is and implement the
+ calls to the actions and guards. A state machine must also define its regions
+ (marked by initial states) And that is about the only constraints for
+ front-ends. How the rows are described is implementer's choice. </para>
+ <para>Every row must provide:</para>
+ <itemizedlist>
+ <listitem>
+ <para>A <code>Source</code> typedef indicating, well, the type of the source
+ state.</para>
+ </listitem>
+ <listitem>
+ <para>A <code>Target</code> typedef indicating, well, the type of the target
+ state.</para>
+ </listitem>
+ <listitem>
+ <para>A <code>Evt</code> typedef indicating the type of the event triggering
+ the transition.</para>
+ </listitem>
+ <listitem>
+ <para>A <code>row_type_tag</code> typedef indicating the type of the
+ transition.</para>
+ </listitem>
+ <listitem>
+ <para>Rows having a type requiring transition actions must provide a static
+ function <code>action_call</code> with the following signature: <code>
+ template <class Fsm,class SourceState,class TargetState,class
+ AllStates> </code></para>
+ <para><code>static void action_call (Fsm& fsm, Event const& evt,
+ SourceState&, TargetState&, AllStates&) </code></para>
+ <para>The function gets as parameters the (back-end) state machine, the
+ event, source and target states and a container (in the current
+ back-end, a fusion::set) of all the states defined in the state machine.
+ For example, as the back-end has the front-end as basic class,
+ <code>action_call</code> is simply defined as
+ <code>(fsm.*action)(evt)</code>.</para>
+ </listitem>
+ <listitem>
+ <para>Rows having a type requiring a guard must provide a static function
+ <code>guard_call</code> with the following signature:<code
+ > </code></para>
+ <para><code>template <class Fsm,class SourceState,class TargetState,class
+ AllStates></code></para>
+ <para><code>static bool guard_call (Fsm&, Event const&,
+ SourceState&, TargetState&, AllStates&)</code></para>
+ </listitem>
+ <listitem>
+ <para>The possible transition (row) types are:<itemizedlist>
+ <listitem>
+ <para>a_row_tag: a transition with actions and no guard</para>
+ </listitem>
+ <listitem>
+ <para>g_row_type: a transition with a guard and no
+ actions</para>
+ </listitem>
+ <listitem>
+ <para>_row_tag: a transition without actions or guard</para>
+ </listitem>
+ <listitem>
+ <para>row_tag: a transition with guard and actions</para>
+ </listitem>
+ <listitem>
+ <para>a_irow_tag: an internal transition (defined inside the
+ <code>transition_table</code>) with actions</para>
+ </listitem>
+ <listitem>
+ <para>g_irow_tag: an internal transition (defined inside the
+ <code>transition_table</code>) with guard</para>
+ </listitem>
+ <listitem>
+ <para>irow_tag: an internal transition (defined inside the
+ <code>transition_table</code>) with actions and
+ guards</para>
+ </listitem>
+ <listitem>
+ <para>_irow_tag: an internal transition (defined inside the
+ <code>transition_table</code>) without action or guard.
+ Due to higher priority for internal transitions, this is
+ equivalent to a "ignore event"</para>
+ </listitem>
+ <listitem>
+ <para>sm_a_i_row_tag: an internal transition (defined inside the
+ <code>internal_transition_table</code>) with
+ actions</para>
+ </listitem>
+ <listitem>
+ <para>sm_g_i_row_tag: an internal transition (defined inside the
+ <code>internal_transition_table</code>) with
+ guard</para>
+ </listitem>
+ <listitem>
+ <para>sm_i_row_tag: an internal transition (defined inside the
+ <code>internal_transition_table</code>) with actions and
+ guards</para>
+ </listitem>
+ <listitem>
+ <para>sm__i_row_tag: an internal transition (defined inside the
+ <code>internal_transition_table</code>) without action
+ or guard. Due to higher priority for internal transitions,
+ this is quivalent to a "ignore event"</para>
+ </listitem>
+ </itemizedlist></para>
+ </listitem>
+ </itemizedlist>
+ <para>Furthermore, a front-end must provide the definition of states and state
+ machines. State machine definitions must provide (the implementer is free to
+ provide it or let it be done by every concrete state machine. Different MSM
+ front-ends took one or the other approach):<itemizedlist>
+ <listitem>
+ <para><code>initial_state</code>: This typedef can be a single state or
+ a mpl container and provides the initial states defining one or
+ several orthogonal regions.</para>
+ </listitem>
+ <listitem>
+ <para><code>transition_table</code>: This typedef is a MPL sequence of
+ transition rows.</para>
+ </listitem>
+ <listitem>
+ <para><code>configuration</code>: this typedef is a MPL sequence of
+ known types triggering special behavior in the back-end, for example
+ if a concrete fsm requires a message queue or exception
+ catching.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>States and state machines must both provide a (possibly empty) definition of:<itemizedlist>
+ <listitem>
+ <para><code>flag_list</code>: the flags being active when this state or
+ state machine become the current state of the fsm.</para>
+ </listitem>
+ <listitem>
+ <para><code>deferred_events</code>: events being automatically deferred
+ when the state is the current state of the fsm.</para>
+ </listitem>
+ <listitem>
+ <para><code>internal_transition_table</code>: the internal transitions
+ of this state.</para>
+ </listitem>
+ <listitem>
+ <para><code>on_entry</code> and <code>on_exit</code> methods.</para>
+ </listitem>
+ </itemizedlist></para>
+ </sect1>
+ <sect1>
+ <title><command xml:id="internals-state-id"/> Generated state ids </title>
+ <para>Normally, one does not need to know the ids are generated for all the states
+ of a state machine, unless for debugging purposes, like the pstate function does
+ in the tutorials in order to display the name of the current state. This section
+ will show how to automatically display typeid-generated names, but these are not
+ very readable on all platforms, so it can help to know how the ids are
+ generated. The ids are generated using the transition table, from the âStartâ
+ column up to down, then from the âNextâ column, up to down, as shown in the next
+ image: </para>
+ <para><inlinemediaobject>
+ <imageobject>
+ <imagedata fileref="images/AnnexA.jpg" width="90%" scalefit="1"/>
+ </imageobject>
+ </inlinemediaobject></para>
+ <para>Stopped will get id 0, Open id 1, ErrorMode id 6 and SleepMode (seen only in
+ the âNextâ column) id 7. If you have some implicitly created states, like
+ transition-less initial states or states created using the explicit_creation
+ typedef, these will be added as a source at the end of the transition table. If
+ you have submachine states, a row will be added for them at the end of the
+ table, after the automatically or explicitly created states, which can change
+ their id. The next help you will need for debugging would be to call the
+ current_state method of the state_machine class, then the display_type helper to
+ generate a readable name from the id. If you do not want to go through the
+ transition table to fill an array of names, the library provides another helper,
+ fill_state_names, which, given an array of sufficient size (please see next
+ section to know how many states are defined in the state machine), will fill it
+ with typeid-generated names. </para>
+ </sect1>
+ <sect1>
+ <title>Metaprogramming tools</title>
+ <para>We can find for the transition table more uses than what we have seen so far.
+ Let's suppose you need to write a coverage tool. A state machine would be
+ perfect for such a job, if only it could provide some information about its
+ structure. Thanks to the transition table and Boost.MPL, it does.</para>
+ <para>What is needed for a coverage tool? You need to know how many states are
+ defined in the state machine, and how many events can be fired. This way you can
+ log the fired events and the states visited in the life of a concrete machine
+ and be able to perform some coverage analysis, like âfired 65% of all possible
+ events and visited 80% of the states defined in the state machineâ. To achieve
+ this, MSM provides a few useful tools:<itemizedlist>
+ <listitem>
+ <para>generate_state_set<transition table>: returns a mpl::set of all
+ the states defined in the table.</para>
+ </listitem>
+ <listitem>
+ <para>generate_event_set<transition table>: returns a mpl::set of all
+ the events defined in the table.</para>
+ </listitem>
+ <listitem>
+ <para>using mpl::size<>::value you can get the number of elements in
+ the set.</para>
+ </listitem>
+ <listitem>
+ <para>display_type defines an operator() sending typeid(Type).name() to
+ cout.</para>
+ </listitem>
+ <listitem>
+ <para>fill_state_names fills an array of char const* with names of all
+ states (found by typeid)</para>
+ </listitem>
+ <listitem>
+ <para>using mpl::for_each on the result of generate_state_set and
+ generate_event_set passing display_type as argument will display all
+ the states of the state machine.</para>
+ </listitem>
+ <listitem>
+ <para>let's suppose you need to recursively find the states and events
+ defined in the composite states and thus also having a transition
+ table. Calling recursive_get_transition_table<Composite> will
+ return you the transition table of the composite state, recursively
+ adding the transition tables of all sub-state machines and
+ sub-sub...-sub-state machines. Then call generate_state_set or
+ generate_event_set on the result to get the full list of states and
+ events. </para>
+ </listitem>
+ </itemizedlist></para>
+ <para> An <link xlink:href="examples/BoostCon09Full.cpp">example</link> shows the
+ tools in action. </para>
+ </sect1>
+ </chapter>
+ <chapter>
+ <title>Acknowledgements</title>
+ <para>I am in debt to the following people who helped MSM along the way.</para>
+ <sect1>
+ <title>MSM v2</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Thanks to Dave Abrahams for managing the review</para>
+ </listitem>
+ <listitem>
+ <para>Thanks to Eric Niebler for his patience correcting my grammar
+ errors</para>
+ </listitem>
+ <listitem>
+ <para>Special thanks to Joel de Guzman who gave me very good ideas at
+ the BoostCon09. These ideas were the starting point of the redesign.
+ Any time again, Joel âº</para>
+ </listitem>
+ <listitem>
+ <para>Thanks to Richard OâHara for making Green Hills bring a patch in
+ less than 1 week, thus adding one more compiler to the supported
+ list.</para>
+ </listitem>
+ <listitem>
+ <para>Big thanks to those who took the time to write a review: Franz
+ Alt, David Bergman, Michael Caisse, Barend Gehrels, Darryl Greene,
+ Juraj Ivancic, Erik Nelson, Kenny Riddile.</para>
+ </listitem>
+ <listitem>
+ <para>Thanks to Matt Calabrese, Juraj Ivancic, Adam Merz and Joseph Wu
+ for reporting bugs.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+ <sect1>
+ <title> MSM v1</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>The original version of this framework is based on the brilliant
+ work of David Abrahams and Aleksey Gurtovoy who laid down the base
+ and the principles of the framework in their excellent book, âC++
+ template Metaprogrammingâ. The implementation also makes heavy use
+ of the boost::mpl.</para>
+ </listitem>
+ <listitem>
+ <para>Thanks to Jeff Flinn for his idea of the user-defined base state
+ and his review which allowed MSM to be presented at the
+ BoostCon09.</para>
+ </listitem>
+ <listitem>
+ <para>Thanks to my MSM v1 beta testers, Christoph Woskowski and Franz
+ Alt for using the framework with little documentation and to my
+ private reviewer, Edouard Alligand</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+ </chapter>
+ <chapter>
+ <title>Version history</title>
+ <sect1>
+ <title>From V2.0 to V2.10</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>New documentation</para>
+ </listitem>
+ <listitem>
+ <para>Internal transitions. Either as part of the transition table or
+ using a state's internal transition table</para>
+ </listitem>
+ <listitem>
+ <para>increased dispatch and copy speed</para>
+ </listitem>
+ <listitem>
+ <para><command xlink:href="#basic-row2">new row types</command> for the
+ basic front-end</para>
+ </listitem>
+ <listitem>
+ <para>new eUML syntax, better attribute support, macros to ease
+ developer's life. Even VC8 seems to like it better.</para>
+ </listitem>
+ <listitem>
+ <para>New policy for reduced compile-time at the cost of dispatch
+ speed</para>
+ </listitem>
+ <listitem>
+ <para>Support for base events</para>
+ </listitem>
+ <listitem>
+ <para>possibility to choose the initial event</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect1>
+ </chapter>
+ </part>
+ <part>
+ <title><command xml:id="Reference-begin"/>Reference</title>
+ <chapter>
+ <title>eUML operators and basic helpers</title>
+ <para>The following table lists the supported operators: </para>
+ <para>
+ <table frame="all">
+ <title>Operators and state machine helpers</title>
+ <tgroup cols="3">
+ <colspec colname="c1" colnum="1"/>
+ <colspec colname="c2" colnum="2"/>
+ <colspec colname="c3" colnum="3"/>
+ <thead>
+ <row>
+ <entry>eUML function / operator</entry>
+ <entry>Description</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>&&</entry>
+ <entry>Calls lazily Action1&& Action2</entry>
+ <entry>And_</entry>
+ </row>
+ <row>
+ <entry>||</entry>
+ <entry>Calls lazily Action1|| Action2</entry>
+ <entry>Or_</entry>
+ </row>
+ <row>
+ <entry>!</entry>
+ <entry>Calls lazily !Action1</entry>
+ <entry>Not_</entry>
+ </row>
+ <row>
+ <entry>!=</entry>
+ <entry>Calls lazily Action1 != Action2</entry>
+ <entry>NotEqualTo_</entry>
+ </row>
+ <row>
+ <entry>==</entry>
+ <entry>Calls lazily Action1 == Action2</entry>
+ <entry>EqualTo_</entry>
+ </row>
+ <row>
+ <entry>></entry>
+ <entry>Calls lazily Action1 > Action2</entry>
+ <entry>Greater_</entry>
+ </row>
+ <row>
+ <entry>>=</entry>
+ <entry>Calls lazily Action1 >= Action2</entry>
+ <entry>Greater_Equal_</entry>
+ </row>
+ <row>
+ <entry><</entry>
+ <entry>Calls lazily Action1 < Action2</entry>
+ <entry>Less_</entry>
+ </row>
+ <row>
+ <entry><=</entry>
+ <entry>Calls lazily Action1 <= Action2</entry>
+ <entry>Less_Equal_</entry>
+ </row>
+ <row>
+ <entry>&</entry>
+ <entry>Calls lazily Action1 & Action2</entry>
+ <entry>Bitwise_And_</entry>
+ </row>
+ <row>
+ <entry>|</entry>
+ <entry>Calls lazily Action1 | Action2</entry>
+ <entry>Bitwise_Or_</entry>
+ </row>
+ <row>
+ <entry>^</entry>
+ <entry>Calls lazily Action1 ^ Action2</entry>
+ <entry>Bitwise_Xor_</entry>
+ </row>
+ <row>
+ <entry>--</entry>
+ <entry>Calls lazily --Action1 / Action1--</entry>
+ <entry>Pre_Dec_ / Post_Dec_</entry>
+ </row>
+ <row>
+ <entry>++</entry>
+ <entry>Calls lazily ++Action1 / Action1++</entry>
+ <entry>Pre_Inc_ / Post_Inc_</entry>
+ </row>
+ <row>
+ <entry>/</entry>
+ <entry>Calls lazily Action1 / Action2</entry>
+ <entry>Divides_</entry>
+ </row>
+ <row>
+ <entry>/=</entry>
+ <entry>Calls lazily Action1 /= Action2</entry>
+ <entry>Divides_Assign_</entry>
+ </row>
+ <row>
+ <entry>*</entry>
+ <entry>Calls lazily Action1 * Action2</entry>
+ <entry>Multiplies_</entry>
+ </row>
+ <row>
+ <entry>*=</entry>
+ <entry>Calls lazily Action1 *= Action2</entry>
+ <entry>Multiplies_Assign_</entry>
+ </row>
+ <row>
+ <entry>+ (binary)</entry>
+ <entry>Calls lazily Action1 + Action2</entry>
+ <entry>Plus_</entry>
+ </row>
+ <row>
+ <entry>+ (unary)</entry>
+ <entry>Calls lazily +Action1</entry>
+ <entry>Unary_Plus_</entry>
+ </row>
+ <row>
+ <entry>+=</entry>
+ <entry>Calls lazily Action1 += Action2</entry>
+ <entry>Plus_Assign_</entry>
+ </row>
+ <row>
+ <entry>- (binary)</entry>
+ <entry>Calls lazily Action1 - Action2</entry>
+ <entry>Minus_</entry>
+ </row>
+ <row>
+ <entry>- (unary)</entry>
+ <entry>Calls lazily -Action1</entry>
+ <entry>Unary_Minus_</entry>
+ </row>
+ <row>
+ <entry>-=</entry>
+ <entry>Calls lazily Action1 -= Action2</entry>
+ <entry>Minus_Assign_</entry>
+ </row>
+ <row>
+ <entry>%</entry>
+ <entry>Calls lazily Action1 % Action2</entry>
+ <entry>Modulus_</entry>
+ </row>
+ <row>
+ <entry>%=</entry>
+ <entry>Calls lazily Action1 %= Action2</entry>
+ <entry>Modulus_Assign_</entry>
+ </row>
+ <row>
+ <entry>>></entry>
+ <entry>Calls lazily Action1 >> Action2</entry>
+ <entry>ShiftRight_</entry>
+ </row>
+ <row>
+ <entry>>>=</entry>
+ <entry>Calls lazily Action1 >>= Action2</entry>
+ <entry>ShiftRight_Assign_</entry>
+ </row>
+ <row>
+ <entry><<</entry>
+ <entry>Calls lazily Action1 << Action2</entry>
+ <entry>ShiftLeft_</entry>
+ </row>
+ <row>
+ <entry><<=</entry>
+ <entry>Calls lazily Action1 <<= Action2</entry>
+ <entry>ShiftLeft_Assign_</entry>
+ </row>
+ <row>
+ <entry>[] (works on vector, map, arrays)</entry>
+ <entry>Calls lazily Action1 [Action2]</entry>
+ <entry>Subscript_</entry>
+ </row>
+ <row>
+ <entry>if_then_else_(Condition,Action1,Action2)</entry>
+ <entry>Returns either the result of calling Action1 or the result of
+ calling Action2</entry>
+ <entry>If_Else_</entry>
+ </row>
+ <row>
+ <entry>if_then_(Condition,Action)</entry>
+ <entry>Returns the result of calling Action if Condition</entry>
+ <entry>If_Then_</entry>
+ </row>
+ <row>
+ <entry>while_(Condition, Body)</entry>
+ <entry>While Condition(), calls Body(). Returns nothing</entry>
+ <entry>While_Do_</entry>
+ </row>
+ <row>
+ <entry>do_while_(Condition, Body)</entry>
+ <entry>Calls Body() while Condition(). Returns nothing</entry>
+ <entry>Do_While_</entry>
+ </row>
+ <row>
+ <entry>for_(Begin,Stop,EndLoop,Body)</entry>
+ <entry>Calls for(Begin;Stop;EndLoop){Body;}</entry>
+ <entry>For_Loop_</entry>
+ </row>
+ <row>
+ <entry>process_(Event [,fsm1] [,fsm2] [,fsm3] [,fsm4])</entry>
+ <entry>Processes Event on the current state machine (if no fsm
+ specified) or on up to 4 state machines returned by an
+ appropriate functor.</entry>
+ <entry>Process_</entry>
+ </row>
+ <row>
+ <entry>process2_(Event, Data [,fsm1] [,fsm2] [,fsm3])</entry>
+ <entry>Processes Event on the current state machine (if no fsm
+ specified) or on up to 2 state machines returned by an
+ appropriate functor. The event is copy-constructed from what
+ Data() returns.</entry>
+ <entry>Process2_</entry>
+ </row>
+ <row>
+ <entry>is_flag_(Flag [,fsm])</entry>
+ <entry>Calls is_flag_active() on the current state machine or the
+ one returned by calling fsm.</entry>
+ <entry>Get_Flag_</entry>
+ </row>
+ <row>
+ <entry>event_ [(attribute name)]</entry>
+ <entry>Returns the current event (as const reference)</entry>
+ <entry>GetEvent_</entry>
+ </row>
+ <row>
+ <entry>source_ [(attribute name)]</entry>
+ <entry>Returns the source state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</entry>
+ <entry>GetSource_</entry>
+ </row>
+ <row>
+ <entry>target_ [(attribute name)]</entry>
+ <entry>Returns the target state of the currently triggered
+ transition (as reference). If an attribute name is provided,
+ returns the attribute by reference.</entry>
+ <entry>GetTarget_</entry>
+ </row>
+ <row>
+ <entry>state_ [(attribute name)]</entry>
+ <entry>Returns the source state of the currently active state (as
+ reference). Valid inside a state entry/exit action. If an
+ attribute name is provided, returns the attribute by
+ reference.</entry>
+ <entry>GetState_</entry>
+ </row>
+ <row>
+ <entry>fsm_ [(attribute name)]</entry>
+ <entry>Returns the current state machine (as reference). Valid
+ inside a state entry/exit action or a transition. If an
+ attribute name is provided, returns the attribute by
+ reference.</entry>
+ <entry>GetFsm_</entry>
+ </row>
+ <row>
+ <entry>substate_(state_name [,fsm])</entry>
+ <entry>Returns (as reference) the state state_name referenced in the
+ current state machine or the one given as argument.</entry>
+ <entry>SubState_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>To use these functions, you need to include: </para>
+ <para><code>#include <msm/front/euml/euml.hpp></code></para>
+ </chapter>
+ <chapter>
+ <title>
+ <command xml:id="eUML-STL-all"/>Functional programming </title>
+ <para>To use these functions, you need to include: </para>
+ <para><code>#include <msm/front/euml/stl.hpp></code></para>
+ <para>or the specified header in the following tables.</para>
+ <para>The following tables list the supported STL algorithms: </para>
+ <para>
+ <command xml:id="eUML-STL-querying"/>
+ <table frame="all">
+ <title>STL algorithms</title>
+ <tgroup cols="2">
+ <colspec colname="c2" colnum="1"/>
+ <colspec colname="c3" colnum="2"/>
+ <thead>
+ <row>
+ <entry>STL algorithms in querying.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>find_(first, last, value)</entry>
+ <entry>Find_</entry>
+ </row>
+ <row>
+ <entry>find_if_(first, last, value)</entry>
+ <entry>FindIf_</entry>
+ </row>
+ <row>
+ <entry>lower_bound_(first, last, value [,opáµ])</entry>
+ <entry>LowerBound_</entry>
+ </row>
+ <row>
+ <entry>upper_bound_(first, last, value [,opáµ])</entry>
+ <entry>UpperBound_</entry>
+ </row>
+ <row>
+ <entry>equal_range_(first, last, value [,opáµ])</entry>
+ <entry>EqualRange_</entry>
+ </row>
+ <row>
+ <entry>binary_search_(first, last, value [,opáµ])</entry>
+ <entry>BinarySearch_</entry>
+ </row>
+ <row>
+ <entry>min_element_(first, last[,opáµ])</entry>
+ <entry>MinElement_</entry>
+ </row>
+ <row>
+ <entry>max_element_(first, last[,opáµ])</entry>
+ <entry>MaxElement_</entry>
+ </row>
+ <row>
+ <entry>adjacent_find_(first, last[,opáµ])</entry>
+ <entry>AdjacentFind_</entry>
+ </row>
+ <row>
+ <entry>find_end_( first1, last1, first2, last2 [,op áµ])</entry>
+ <entry>FindEnd_</entry>
+ </row>
+ <row>
+ <entry>find_first_of_( first1, last1, first2, last2 [,op áµ])</entry>
+ <entry>FindFirstOf_</entry>
+ </row>
+ <row>
+ <entry>equal_( first1, last1, first2 [,op áµ])</entry>
+ <entry>Equal_</entry>
+ </row>
+ <row>
+ <entry>search_( first1, last1, first2, last2 [,op áµ])</entry>
+ <entry>Search_</entry>
+ </row>
+ <row>
+ <entry>includes_( first1, last1, first2, last2 [,op áµ])</entry>
+ <entry>Includes_</entry>
+ </row>
+ <row>
+ <entry>lexicographical_compare_ ( first1, last1, first2, last2 [,op
+ áµ]) </entry>
+ <entry>LexicographicalCompare_</entry>
+ </row>
+ <row>
+ <entry>count_(first, last, value [,size])</entry>
+ <entry>Count_</entry>
+ </row>
+ <row>
+ <entry>count_if_(first, last, op áµ [,size])</entry>
+ <entry>CountIf_</entry>
+ </row>
+ <row>
+ <entry>distance_(first, last)</entry>
+ <entry>Distance_</entry>
+ </row>
+ <row>
+ <entry>mismatch _( first1, last1, first2 [,op áµ])</entry>
+ <entry>Mismatch_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ <command xml:id="eUML-STL-iteration"/>
+ <table frame="all">
+ <title>STL algorithms</title>
+ <tgroup cols="2">
+ <colspec colname="c2" colnum="1"/>
+ <colspec colname="c3" colnum="2"/>
+ <thead>
+ <row>
+ <entry>STL algorithms in iteration.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>for_each_(first,last, unary opáµ)</entry>
+ <entry>ForEach_</entry>
+ </row>
+ <row>
+ <entry>accumulate_first, last, init [,opáµ])</entry>
+ <entry>Accumulate_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ <command xml:id="eUML-STL-transformation"/>
+ <table>
+ <title>STL algorithms</title>
+ <tgroup cols="2">
+ <colspec colname="c2" colnum="1"/>
+ <colspec colname="c3" colnum="2"/>
+ <thead>
+ <row>
+ <entry>STL algorithms in transformation.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>copy_(first, last, result)</entry>
+ <entry>Copy_</entry>
+ </row>
+ <row>
+ <entry>copy_backward_(first, last, result)</entry>
+ <entry>CopyBackward_</entry>
+ </row>
+ <row>
+ <entry>reverse_(first, last)</entry>
+ <entry>Reverse_</entry>
+ </row>
+ <row>
+ <entry>reverse_copy_(first, last , result)</entry>
+ <entry>ReverseCopy_</entry>
+ </row>
+ <row>
+ <entry>remove_(first, last, value)</entry>
+ <entry>Remove_</entry>
+ </row>
+ <row>
+ <entry>remove_if_(first, last , opáµ)</entry>
+ <entry>RemoveIf_</entry>
+ </row>
+ <row>
+ <entry>remove_copy_(first, last , output, value)</entry>
+ <entry>RemoveCopy_</entry>
+ </row>
+ <row>
+ <entry>remove_copy_if_(first, last, output, opáµ)</entry>
+ <entry>RemoveCopyIf_</entry>
+ </row>
+ <row>
+ <entry>fill_(first, last, value)</entry>
+ <entry>Fill_</entry>
+ </row>
+ <row>
+ <entry>fill_n_(first, size, value)áµ</entry>
+ <entry>FillN_</entry>
+ </row>
+ <row>
+ <entry>generate_(first, last, generatoráµ)</entry>
+ <entry>Generate_</entry>
+ </row>
+ <row>
+ <entry>generate_(first, size, generatoráµ)áµ</entry>
+ <entry>GenerateN_</entry>
+ </row>
+ <row>
+ <entry>unique_(first, last [,opáµ])</entry>
+ <entry>Unique_</entry>
+ </row>
+ <row>
+ <entry>unique_copy_(first, last, output [,opáµ])</entry>
+ <entry>UniqueCopy_</entry>
+ </row>
+ <row>
+ <entry>random_shuffle_(first, last [,opáµ])</entry>
+ <entry>RandomShuffle_</entry>
+ </row>
+ <row>
+ <entry>rotate_copy_(first, middle, last, output)</entry>
+ <entry>RotateCopy_</entry>
+ </row>
+ <row>
+ <entry>partition_ (first, last [,opáµ])</entry>
+ <entry>Partition_</entry>
+ </row>
+ <row>
+ <entry>stable_partition_ (first, last [,opáµ])</entry>
+ <entry>StablePartition_</entry>
+ </row>
+ <row>
+ <entry>stable_sort_(first, last [,opáµ])</entry>
+ <entry>StableSort_</entry>
+ </row>
+ <row>
+ <entry>sort_(first, last [,opáµ])</entry>
+ <entry>Sort_</entry>
+ </row>
+ <row>
+ <entry>partial_sort_(first, middle, last [,opáµ])</entry>
+ <entry>PartialSort_</entry>
+ </row>
+ <row>
+ <entry>partial_sort_copy_ (first, last, res_first, res_last [,opáµ]) </entry>
+ <entry>PartialSortCopy_</entry>
+ </row>
+ <row>
+ <entry>nth_element_(first, nth, last [,opáµ])</entry>
+ <entry>NthElement_</entry>
+ </row>
+ <row>
+ <entry>merge_( first1, last1, first2, last2, output [,op áµ])</entry>
+ <entry>Merge_</entry>
+ </row>
+ <row>
+ <entry>inplace_merge_(first, middle, last [,opáµ])</entry>
+ <entry>InplaceMerge_</entry>
+ </row>
+ <row>
+ <entry>set_union_(first1, last1, first2, last2, output [,op
+ áµ])</entry>
+ <entry>SetUnion_</entry>
+ </row>
+ <row>
+ <entry>push_heap_(first, last [,op áµ])</entry>
+ <entry>PushHeap_</entry>
+ </row>
+ <row>
+ <entry>pop_heap_(first, last [,op áµ])</entry>
+ <entry>PopHeap_</entry>
+ </row>
+ <row>
+ <entry>make_heap_(first, last [,op áµ])</entry>
+ <entry>MakeHeap_</entry>
+ </row>
+ <row>
+ <entry>sort_heap_(first, last [,op áµ])</entry>
+ <entry>SortHeap_</entry>
+ </row>
+ <row>
+ <entry>next_permutation_(first, last [,op áµ])</entry>
+ <entry>NextPermutation_</entry>
+ </row>
+ <row>
+ <entry>prev_permutation_(first, last [,op áµ])</entry>
+ <entry>PrevPermutation_</entry>
+ </row>
+ <row>
+ <entry>inner_product_(first1, last1, first2, init [,op1áµ] [,op2áµ]) </entry>
+ <entry>InnerProduct_</entry>
+ </row>
+ <row>
+ <entry>partial_sum_(first, last, output [,opáµ])</entry>
+ <entry>PartialSum_</entry>
+ </row>
+ <row>
+ <entry>adjacent_difference_(first, last, output [,opáµ])</entry>
+ <entry>AdjacentDifference_</entry>
+ </row>
+ <row>
+ <entry>replace_(first, last, old_value, new_value)</entry>
+ <entry>Replace_</entry>
+ </row>
+ <row>
+ <entry>replace_if_(first, last, opáµ, new_value)</entry>
+ <entry>ReplaceIf_</entry>
+ </row>
+ <row>
+ <entry>replace_copy_(first, last, result, old_value,
+ new_value)</entry>
+ <entry>ReplaceCopy_</entry>
+ </row>
+ <row>
+ <entry>replace_copy_if_(first, last, result, opáµ, new_value)</entry>
+ <entry>ReplaceCopyIf_</entry>
+ </row>
+ <row>
+ <entry>rotate_(first, middle, last)áµ</entry>
+ <entry>Rotate_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ <command xml:id="eUML-STL-container"/>
+ <table>
+ <title>STL container methods</title>
+ <tgroup cols="2">
+ <colspec colname="c2" colnum="1"/>
+ <colspec colname="c3" colnum="2"/>
+ <thead>
+ <row>
+ <entry>STL container methods(common) in container.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>container::reference front_(container)</entry>
+ <entry>Front_</entry>
+ </row>
+ <row>
+ <entry>container::reference back_(container)</entry>
+ <entry>Back_</entry>
+ </row>
+ <row>
+ <entry>container::iterator begin_(container)</entry>
+ <entry>Begin_</entry>
+ </row>
+ <row>
+ <entry>container::iterator end_(container)</entry>
+ <entry>End_</entry>
+ </row>
+ <row>
+ <entry>container::reverse_iterator rbegin_(container)</entry>
+ <entry>RBegin_</entry>
+ </row>
+ <row>
+ <entry>container::reverse_iterator rend_(container)</entry>
+ <entry>REnd_</entry>
+ </row>
+ <row>
+ <entry>void push_back_(container, value)</entry>
+ <entry>Push_Back_</entry>
+ </row>
+ <row>
+ <entry>void pop_back_(container, value)</entry>
+ <entry>Pop_Back_</entry>
+ </row>
+ <row>
+ <entry>void push_front_(container, value)</entry>
+ <entry>Push_Front_</entry>
+ </row>
+ <row>
+ <entry>void pop_front_(container, value)</entry>
+ <entry>Pop_Front_</entry>
+ </row>
+ <row>
+ <entry>void clear_(container)</entry>
+ <entry>Clear_</entry>
+ </row>
+ <row>
+ <entry>size_type capacity_(container)</entry>
+ <entry>Capacity_</entry>
+ </row>
+ <row>
+ <entry>size_type size_(container)</entry>
+ <entry>Size_</entry>
+ </row>
+ <row>
+ <entry>size_type max_size_(container)</entry>
+ <entry>Max_Size_</entry>
+ </row>
+ <row>
+ <entry>void reserve_(container, value)</entry>
+ <entry>Reserve _</entry>
+ </row>
+ <row>
+ <entry>void resize_(container, value)</entry>
+ <entry>Resize _</entry>
+ </row>
+ <row>
+ <entry>iterator insert_(container, pos, value)</entry>
+ <entry>Insert_</entry>
+ </row>
+ <row>
+ <entry>void insert_( container , pos, first, last)</entry>
+ <entry>Insert_</entry>
+ </row>
+ <row>
+ <entry>void insert_( container , pos, number, value)</entry>
+ <entry>Insert_</entry>
+ </row>
+ <row>
+ <entry>void swap_( container , other_container)</entry>
+ <entry>Swap_</entry>
+ </row>
+ <row>
+ <entry>void erase_( container , pos)</entry>
+ <entry>Erase_</entry>
+ </row>
+ <row>
+ <entry>void erase_( container , first, last) </entry>
+ <entry>Erase_</entry>
+ </row>
+ <row>
+ <entry>bool empty_( container)</entry>
+ <entry>Empty_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ <table>
+ <title>STL list methods</title>
+ <tgroup cols="2">
+ <colspec colname="c2" colnum="1"/>
+ <colspec colname="c3" colnum="2"/>
+ <thead>
+ <row>
+ <entry>std::list methods in container.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>void list_remove_(container, value)</entry>
+ <entry>ListRemove_</entry>
+ </row>
+ <row>
+ <entry>void list_remove_if_(container, opáµ)</entry>
+ <entry>ListRemove_If_</entry>
+ </row>
+ <row>
+ <entry>void list_merge_(container, other_list)</entry>
+ <entry>ListMerge_</entry>
+ </row>
+ <row>
+ <entry>void list_merge_(container, other_list, opáµ)</entry>
+ <entry>ListMerge_</entry>
+ </row>
+ <row>
+ <entry>void splice_(container, iterator, other_list)</entry>
+ <entry>Splice_</entry>
+ </row>
+ <row>
+ <entry>void splice_(container, iterator, other_list,
+ iterator)</entry>
+ <entry>Splice_</entry>
+ </row>
+ <row>
+ <entry>void splice_(container, iterator, other_list, first,
+ last)</entry>
+ <entry>Splice_</entry>
+ </row>
+ <row>
+ <entry>void list_reverse_(container)</entry>
+ <entry>ListReverse_</entry>
+ </row>
+ <row>
+ <entry>void list_unique_(container)</entry>
+ <entry>ListUnique_</entry>
+ </row>
+ <row>
+ <entry>void list_unique_(container, opáµ)</entry>
+ <entry>ListUnique_</entry>
+ </row>
+ <row>
+ <entry>void list_sort_(container)</entry>
+ <entry>ListSort_</entry>
+ </row>
+ <row>
+ <entry>void list_sort_(container, opáµ)</entry>
+ <entry>ListSort_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ <table>
+ <title>STL associative container methods </title>
+ <tgroup cols="2">
+ <colspec colname="c2" colnum="1"/>
+ <colspec colname="c3" colnum="2"/>
+ <thead>
+ <row>
+ <entry>Associative container methods in container.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>iterator insert_(container, pos, value)</entry>
+ <entry>Insert_</entry>
+ </row>
+ <row>
+ <entry>void insert_( container , first, last)</entry>
+ <entry>Insert_</entry>
+ </row>
+ <row>
+ <entry>pair<iterator, bool> insert_( container , value)</entry>
+ <entry>Insert_</entry>
+ </row>
+ <row>
+ <entry>void associative_erase_( container , pos)</entry>
+ <entry>Associative_Erase_</entry>
+ </row>
+ <row>
+ <entry>void associative_erase_( container , first, last)</entry>
+ <entry>Associative_Erase_</entry>
+ </row>
+ <row>
+ <entry>size_type associative_erase_( container , key)</entry>
+ <entry>Associative_Erase_</entry>
+ </row>
+ <row>
+ <entry>iterator associative_find_( container , key)</entry>
+ <entry>Associative_Find_</entry>
+ </row>
+ <row>
+ <entry>size_type associative_count_( container , key)</entry>
+ <entry>AssociativeCount_</entry>
+ </row>
+ <row>
+ <entry>iterator associative_lower_bound_( container , key)</entry>
+ <entry>Associative_Lower_Bound_</entry>
+ </row>
+ <row>
+ <entry>iterator associative_upper_bound_( container , key)</entry>
+ <entry>Associative_Upper_Bound_</entry>
+ </row>
+ <row>
+ <entry>pair<iterator, iterator> associative_equal_range_(
+ container , key)</entry>
+ <entry>Associative_Equal_Range_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ <table>
+ <title>STL pair</title>
+ <tgroup cols="2">
+ <colspec colname="c2" colnum="1"/>
+ <colspec colname="c3" colnum="2"/>
+ <thead>
+ <row>
+ <entry>std::pair in container.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>first_type first_(pair<T1, T2>)</entry>
+ <entry>First_</entry>
+ </row>
+ <row>
+ <entry>second_type second_(pair<T1, T2>)</entry>
+ <entry>Second_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para>
+ <table>
+ <title>STL string</title>
+ <tgroup cols="3">
+ <colspec colname="newCol1" colnum="1"/>
+ <colspec colname="c2" colnum="2"/>
+ <colspec colname="c3" colnum="3"/>
+ <thead>
+ <row>
+ <entry>STL string method</entry>
+ <entry>std::string method in container.hpp</entry>
+ <entry>Functor</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>substr (size_type pos, size_type size)</entry>
+ <entry>string substr_(container, pos, length)</entry>
+ <entry>Substr_</entry>
+ </row>
+ <row>
+ <entry>int compare(string)</entry>
+ <entry>int string_compare_(container, another_string)</entry>
+ <entry>StringCompare_</entry>
+ </row>
+ <row>
+ <entry>int compare(char*)</entry>
+ <entry>int string_compare_(container, another_string)</entry>
+ <entry>StringCompare_</entry>
+ </row>
+ <row>
+ <entry>int compare(size_type pos, size_type size, string)</entry>
+ <entry>int string_compare_(container, pos, size,
+ another_string)</entry>
+ <entry>StringCompare_</entry>
+ </row>
+ <row>
+ <entry>int compare (size_type pos, size_type size, string, size_type
+ length)</entry>
+ <entry>int string_compare_(container, pos, size, another_string,
+ length)</entry>
+ <entry>StringCompare_</entry>
+ </row>
+ <row>
+ <entry>string& append(const string&)</entry>
+ <entry>string& append_(container, another_string)</entry>
+ <entry>Append_</entry>
+ </row>
+ <row>
+ <entry>string& append (charT*)</entry>
+ <entry>string& append_(container, another_string)</entry>
+ <entry>Append_</entry>
+ </row>
+ <row>
+ <entry>string& append (string , size_type pos, size_type
+ size)</entry>
+ <entry>string& append_(container, other_string, pos,
+ size)</entry>
+ <entry>Append_</entry>
+ </row>
+ <row>
+ <entry>string& append (charT*, size_type size)</entry>
+ <entry>string& append_(container, another_string,
+ length)</entry>
+ <entry>Append_</entry>
+ </row>
+ <row>
+ <entry>string& append (size_type size, charT)</entry>
+ <entry>string& append_(container, size, char)</entry>
+ <entry>Append_</entry>
+ </row>
+ <row>
+ <entry>string& append (iterator begin, iterator end)</entry>
+ <entry>string& append_(container, begin, end)</entry>
+ <entry>Append_</entry>
+ </row>
+ <row>
+ <entry>string& insert (size_type pos, charT*)</entry>
+ <entry>string& string_insert_(container, pos,
+ other_string)</entry>
+ <entry>StringInsert_</entry>
+ </row>
+ <row>
+ <entry>string& insert(size_type pos, charT*,size_type n)</entry>
+ <entry>string& string_insert_(container, pos, other_string,
+ n)</entry>
+ <entry>StringInsert_</entry>
+ </row>
+ <row>
+ <entry>string& insert(size_type pos,size_type n, charT
+ c)</entry>
+ <entry>string& string_insert_(container, pos, n, c)</entry>
+ <entry>StringInsert_</entry>
+ </row>
+ <row>
+ <entry>string& insert (size_type pos, const string&)</entry>
+ <entry>string& string_insert_(container, pos,
+ other_string)</entry>
+ <entry>StringInsert_</entry>
+ </row>
+ <row>
+ <entry>string& insert (size_type pos, const string&,
+ size_type pos1, size_type n)</entry>
+ <entry>string& string_insert_(container, pos, other_string,
+ pos1, n)</entry>
+ <entry>StringInsert_</entry>
+ </row>
+ <row>
+ <entry>string& erase(size_type pos=0, size_type n=npos)</entry>
+ <entry>string& string_erase_(container, pos, n)</entry>
+ <entry>StringErase_</entry>
+ </row>
+ <row>
+ <entry>string& assign(const string&)</entry>
+ <entry>string& string_assign_(container, another_string)</entry>
+ <entry>StringAssign_</entry>
+ </row>
+ <row>
+ <entry>string& assign(const charT*)</entry>
+ <entry>string& string_assign_(container, another_string)</entry>
+ <entry>StringAssign_</entry>
+ </row>
+ <row>
+ <entry>string& assign(const string&, size_type pos,
+ size_type n)</entry>
+ <entry>string& string_assign_(container, another_string, pos,
+ n)</entry>
+ <entry>StringAssign_</entry>
+ </row>
+ <row>
+ <entry>string& assign(const charT*, size_type n)</entry>
+ <entry>string& string_assign_(container, another_string,
+ n)</entry>
+ <entry>StringAssign_</entry>
+ </row>
+ <row>
+ <entry>string& assign(size_type n, charT c)</entry>
+ <entry>string& string_assign_(container, n, c)</entry>
+ <entry>StringAssign_</entry>
+ </row>
+ <row>
+ <entry>string& assign(iterator first, iterator last)</entry>
+ <entry>string& string_assign_(container, first, last)</entry>
+ <entry>StringAssign_</entry>
+ </row>
+ <row>
+ <entry>string& replace(size_type pos, size_type n, const
+ string&)</entry>
+ <entry>string& string_replace_(container, pos, n,
+ another_string)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(size_type pos, size_type n, const charT*,
+ size_type n1)</entry>
+ <entry>string& string_replace_(container, pos, n,
+ another_string, n1)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(size_type pos, size_type n, const
+ charT*)</entry>
+ <entry>string& string_replace_(container, pos, n,
+ another_string)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(size_type pos, size_type n, size_type n1,
+ charT c)</entry>
+ <entry>string& string_replace_(container, pos, n, n1, c)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(iterator first, iterator last, const
+ string&)</entry>
+ <entry>string& string_replace_(container, first, last,
+ another_string)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(iterator first, iterator last, const
+ charT*, size_type n)</entry>
+ <entry>string& string_replace_(container, first, last,
+ another_string, n)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(iterator first, iterator last, const
+ charT*)</entry>
+ <entry>string& string_replace_(container, first, last,
+ another_string)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(iterator first, iterator last, size_type
+ n, charT c)</entry>
+ <entry>string& string_replace_(container, first, last, n,
+ c)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>string& replace(iterator first, iterator last, iterator
+ f, iterator l)</entry>
+ <entry>string& string_replace_(container, first, last, f,
+ l)</entry>
+ <entry>StringReplace_</entry>
+ </row>
+ <row>
+ <entry>const charT* c_str()</entry>
+ <entry>const charT* c_str_(container)</entry>
+ <entry>CStr_</entry>
+ </row>
+ <row>
+ <entry>const charT* data()</entry>
+ <entry>const charT* string_data_(container)</entry>
+ <entry>StringData_</entry>
+ </row>
+ <row>
+ <entry>size_type copy(charT* buf, size_type n, size_type pos =
+ 0)</entry>
+ <entry>size_type string_copy_(container, buf, n, pos); size_type
+ string_copy_(container, buf, n) </entry>
+ <entry>StringCopy_</entry>
+ </row>
+ <row>
+ <entry>size_type find(charT* s, size_type pos, size_type n)</entry>
+ <entry>size_type string_find_(container, s, pos, n)</entry>
+ <entry>StringFind_</entry>
+ </row>
+ <row>
+ <entry>size_type find(charT* s, size_type pos=0)</entry>
+ <entry>size_type string_find_(container, s, pos); size_type
+ string_find_(container, s) </entry>
+ <entry>StringFind_</entry>
+ </row>
+ <row>
+ <entry>size_type find(const string& s, size_type pos=0)</entry>
+ <entry>size_type string_find_(container, s, pos) size_type
+ string_find_(container, s) </entry>
+ <entry>StringFind_</entry>
+ </row>
+ <row>
+ <entry>size_type find(charT c, size_type pos=0)</entry>
+ <entry>size_type string_find_(container, c, pos) size_type
+ string_find_(container, c) </entry>
+ <entry>StringFind_</entry>
+ </row>
+ <row>
+ <entry>size_type rfind(charT* s, size_type pos, size_type n)</entry>
+ <entry>size_type string_rfind_(container, s, pos, n)</entry>
+ <entry>StringRFind_</entry>
+ </row>
+ <row>
+ <entry>size_type rfind(charT* s, size_type pos=npos)</entry>
+ <entry>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </entry>
+ <entry>StringRFind_</entry>
+ </row>
+ <row>
+ <entry>size_type rfind(const string& s, size_type
+ pos=npos)</entry>
+ <entry>size_type string_rfind_(container, s, pos); size_type
+ string_rfind_(container, s) </entry>
+ <entry>StringRFind_</entry>
+ </row>
+ <row>
+ <entry>size_type rfind(charT c, size_type pos=npos)</entry>
+ <entry>size_type string_rfind_(container, c, pos) size_type
+ string_rfind_(container, c) </entry>
+ <entry>StringRFind_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_of(charT* s, size_type pos, size_type
+ n)</entry>
+ <entry>size_type find_first_of_(container, s, pos, n)</entry>
+ <entry>StringFindFirstOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_of (charT* s, size_type pos=0)</entry>
+ <entry>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </entry>
+ <entry>StringFindFirstOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_of (const string& s, size_type
+ pos=0)</entry>
+ <entry>size_type find_first_of_(container, s, pos); size_type
+ find_first_of_(container, s) </entry>
+ <entry>StringFindFirstOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_of (charT c, size_type pos=0)</entry>
+ <entry>size_type find_first_of_(container, c, pos) size_type
+ find_first_of_(container, c) </entry>
+ <entry>StringFindFirstOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_not_of(charT* s, size_type pos,
+ size_type n)</entry>
+ <entry>size_type find_first_not_of_(container, s, pos, n)</entry>
+ <entry>StringFindFirstNotOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_not_of (charT* s, size_type
+ pos=0)</entry>
+ <entry>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </entry>
+ <entry>StringFindFirstNotOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_not_of (const string& s, size_type
+ pos=0)</entry>
+ <entry>size_type find_first_not_of_(container, s, pos); size_type
+ find_first_not_of_(container, s) </entry>
+ <entry>StringFindFirstNotOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_first_not_of (charT c, size_type
+ pos=0)</entry>
+ <entry>size_type find_first_not_of_(container, c, pos); size_type
+ find_first_not_of_(container, c) </entry>
+ <entry>StringFindFirstNotOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_of(charT* s, size_type pos, size_type
+ n)</entry>
+ <entry>size_type find_last_of_(container, s, pos, n)</entry>
+ <entry>StringFindLastOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_of (charT* s, size_type pos=npos)</entry>
+ <entry>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </entry>
+ <entry>StringFindLastOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_of (const string& s, size_type
+ pos=npos)</entry>
+ <entry>size_type find_last_of_(container, s, pos); size_type
+ find_last_of_(container, s) </entry>
+ <entry>StringFindLastOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_of (charT c, size_type pos=npos)</entry>
+ <entry>size_type find_last_of_(container, c, pos); size_type
+ find_last_of_(container, c) </entry>
+ <entry>StringFindLastOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_not_of(charT* s, size_type pos, size_type
+ n)</entry>
+ <entry>size_type find_last_not_of_(container, s, pos, n)</entry>
+ <entry>StringFindLastNotOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_not_of (charT* s, size_type
+ pos=npos)</entry>
+ <entry>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_of_(container, s) </entry>
+ <entry>StringFindLastNotOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_not_of (const string& s, size_type
+ pos=npos)</entry>
+ <entry>size_type find_last_not_of_(container, s, pos); size_type
+ find_last_not_of_(container, s) </entry>
+ <entry>StringFindLastNotOf_</entry>
+ </row>
+ <row>
+ <entry>size_type find_last_not_of (charT c, size_type
+ pos=npos)</entry>
+ <entry>size_type find_last_not_of_(container, c, pos); size_type
+ find_last_not_of_(container, c) </entry>
+ <entry>StringFindLastNotOf_</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </para>
+ <para><emphasis role="underline">Notes</emphasis>: <itemizedlist>
+ <listitem>
+ <para>áµ: algorithms requiring a predicate need to make them eUML compatible
+ by wrapping them inside a Predicate_ functor. For example,
+ std::less<int> => Predicate_<std::less<int> >()</para>
+ </listitem>
+ <listitem>
+ <para>áµ: If using the SGI STL implementation, these functors use the SGI
+ return value</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </chapter>
+ <refentry>
+ <refnamediv>
+ <refname>Common headers</refname>
+ <refpurpose>The common types used by front- and back-ends</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>msm/common.hpp</title>
+ <para>This header provides one type, wrap, which is an empty type whose only reason
+ to exist is to be cheap to construct, so that it can be used with mpl::for_each,
+ as shown in the Metaprogramming book, chapter 9.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class Dummy> wrap{};</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect1>
+ <refsect1>
+ <title>msm/row_tags.hpp</title>
+ <para>This header contains the row type tags which front-ends can support partially
+ or totally. Please see the <command xlink:href="#internals-front-back-interface"
+ >Internals</command> section for a description of the different
+ types.</para>
+ </refsect1>
+ </refentry>
+ <refentry>
+ <refnamediv>
+ <refname>Back-end</refname>
+ <refpurpose>The back-end headers</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>msm/back/state_machine.hpp</title>
+ <para> This header provides one type, state_machine, MSM's state machine engine
+ implementation.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class Derived,class HistoryPolicy=NoHistory,class
+ CompilePolicy=favor_runtime_speed> state_machine</classname>
+ </ooclass>
+ </classsynopsis>
+ <refsect2>
+ <title> Template arguments </title>
+ <refsect3>
+ <title> Derived </title>
+ <para>The name of the front-end state machine definition. All three
+ front-ends are possible.</para>
+ </refsect3>
+ <refsect3>
+ <title> HistoryPolicy </title>
+ <para>The desired history. This can be: AlwaysHistory, NoHistory,
+ ShallowHistory. Default is NoHistory.</para>
+ </refsect3>
+ <refsect3>
+ <title> CompilePolicy </title>
+ <para>The trade-off performance / compile-time. There are two predefined
+ policies, favor_runtime_speed and favor_compile_time. Default is
+ favor_runtime_speed, best performance, longer compile-time. See <link
+ xlink:href="#backend-tradeof-rt-ct">the backend</link>.</para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title> methods </title>
+ <refsect3>
+ <title>start</title>
+ <para> The start methods must be called before any call to process_event. It
+ activates the entry action of the initial state(s). This allows you to
+ choose when a state machine can start. See <link
+ xlink:href="#backend-start">backend</link>.</para>
+ <methodsynopsis>
+ <methodname>void start</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>process_event</title>
+ <para>The event processing method implements the double-dispatch. Each call
+ to this function with a new event type instantiates a new dispatch
+ algorithm and increases compile-time.</para>
+ <methodsynopsis>
+ <methodname>template <class Event> HandledEnum
+ process_event</methodname>
+ <methodparam>
+ <funcparams>Event const&</funcparams>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>current_state</title>
+ <para>Returns the ids of currently active states. You will typically need it
+ only for debugging or logging purposes.</para>
+ <methodsynopsis>
+ <methodname>const int* current_state const</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>get_state_by_id</title>
+ <para>Returns the state whose id is given. As all states of a concrete state
+ machine share a common base state, the return value is a base state. If
+ the id corresponds to no state, a null pointer is returned.</para>
+ <methodsynopsis>
+ <methodname>const BaseState* get_state_by_id const</methodname>
+ <methodparam>
+ <funcparams>int id</funcparams>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>is_contained</title>
+ <para>Helper returning true if the state machine is contained as a
+ submachine of another state machine.</para>
+ <methodsynopsis>
+ <methodname>bool is_contained const</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>get_state</title>
+ <para>Returns the required state of the state machine as a pointer. A
+ compile error will occur if the state is not to be found in the state
+ machine.</para>
+ <methodsynopsis>
+ <methodname>template <class State> State* get_state</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>get_state</title>
+ <para>Returns the required state of the state machine as a reference. A
+ compile error will occur if the state is not to be found in the state
+ machine.</para>
+ <methodsynopsis>
+ <methodname>template <class State> State& get_state</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>is_flag_active</title>
+ <para>Returns true if the given flag is currently active. A flag is active
+ if the active state of one region is tagged with this flag (using OR as
+ BinaryOp) or active states of <emphasis role="underline">all</emphasis>
+ regions (using AND as BinaryOp)</para>
+ <methodsynopsis>
+ <methodname>template <class Flag,class BinaryOp> bool
+ is_flag_active</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>is_flag_active</title>
+ <para>Returns true if the given flag is currently active. A flag is active
+ if the active state of one region is tagged with this flag.</para>
+ <methodsynopsis>
+ <methodname>template <class Flag> bool is_flag_active</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>visit_current_states</title>
+ <para>Visits all active states and their substates. A state is visited using
+ the <code>accept</code> method without argument. The base class of all
+ states must provide an <code>accept_sig</code> type.</para>
+ <methodsynopsis>
+ <methodname>void visit_current_states</methodname>
+ <methodparam>
+ <funcparams/>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>visit_current_states</title>
+ <para>Visits all active states and their substates. A state is visited using
+ the <code>accept</code> method with arguments. The base class of all
+ states must provide an <code>accept_sig</code> type defining the
+ signature and thus the number and type of the parameters.</para>
+ <methodsynopsis>
+ <methodname>void visit_current_states</methodname>
+ <methodparam>
+ <funcparams>any-type param1, any-type param2,...</funcparams>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>defer_event</title>
+ <para> Defers the provided event. This method can be called only if at least
+ one state defers an event or if the state machine provides the
+ <code>activate_deferred_events</code>(see <link
+ xlink:href="examples/Orthogonal-deferred2.cpp">example</link>) type
+ either directly or using the deferred_events configuration of eUML
+ (<code>configure_ << deferred_events</code>)</para>
+ <methodsynopsis>
+ <methodname>template <class Event> void defer_event</methodname>
+ <methodparam>
+ <funcparams>Event const&</funcparams>
+ </methodparam>
+ </methodsynopsis>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>Types</title>
+ <refsect3>
+ <title>nr_regions </title>
+ <para>The number of orthogonal regions contained in the state machine</para>
+ </refsect3>
+ <refsect3>
+ <title>entry_pt</title>
+ <para>This nested type provides the necessary typedef for entry point
+ pseudostates.
+ <code>state_machine<...>::entry_pt<state_name></code> is a
+ transition's valid target inside the containing state machine's
+ transition table.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>entry_pt</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>exit_pt</title>
+ <para>This nested type provides the necessary typedef for exit point
+ pseudostates. <code>state_machine<...>::exit_pt<state_name></code>
+ is a transition's valid source inside the containing state machine's
+ transition table.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>exit_pt</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>direct</title>
+ <para>This nested type provides the necessary typedef for an explicit entry
+ inside a submachine.
+ <code>state_machine<...>::direct<state_name></code> is a
+ transition's valid target inside the containing state machine's
+ transition table.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>direct</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>stt</title>
+ <para>Calling state_machine<frontend>::stt returns a mpl::vector
+ containing the transition table of the state machine. This type can then
+ be used with generate_state_set or generate_event_set.</para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>args.hpp</title>
+ <para>This header provides one type, args. which provides the necessary types for a
+ visitor implementation.</para>
+ </refsect1>
+ <refsect1>
+ <title><command xml:id="history-interface"/>msm/back/history_policies.hpp</title>
+ <para>This header provides the out-of-the-box history policies supported by MSM.
+ There are 3 such policies.</para>
+ <refsect2>
+ <title>Every history policy must implement the following methods: </title>
+ <refsect3>
+ <title> set_initial_states </title>
+ <para> This method is called by msm::back::state_machine when constructed.
+ It gives the policy a chance to save the ids of all initial states
+ (passed as array).</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>void set_initial_states</funcdef>
+ <paramdef>
+ <funcparams>int* const</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ <refsect3>
+ <title> history_exit </title>
+ <para>This method is called by msm::back::state_machine when the submachine
+ is exited. It gives the policy a chance to remember the ids of the last
+ active substates of this submachine (passed as array).</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>void history_exit</funcdef>
+ <paramdef>
+ <funcparams>int* const</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ <refsect3>
+ <title> history_entry </title>
+ <para>This method is called by msm::back::state_machine when the submachine
+ is entered. It gives the policy a chance to set the active states
+ according to the policy's aim. The policy gets as parameter the event
+ which activated the submachine and returns an array of active states
+ ids.</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Event> int* const history_exit</funcdef>
+ <paramdef>
+ <funcparams>Event const&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>Out-of-the-box policies: </title>
+ <refsect3>
+ <title>NoHistory</title>
+ <para>This policy is the default used by state_machine. No active state of a
+ submachine is remembered and at every new activation of the submachine,
+ the initial state(s) are activated. </para>
+ </refsect3>
+ <refsect3>
+ <title>AlwaysHistory</title>
+ <para>This policy is a non-UML-standard extension. The active state(s) of a
+ submachine is (are) always remembered at every new activation of the
+ submachine. </para>
+ </refsect3>
+ <refsect3>
+ <title>ShallowHistory</title>
+ <para>This policy activates the active state(s) of a submachine if the event
+ is found in the policy's event list. </para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/back/default_compile_policy.hpp</title>
+ <para>This header contains the definition of favor_runtime_speed. This policy has
+ two settings:<itemizedlist>
+ <listitem>
+ <para>Submachines dispatch faster because their transitions are added
+ into their containing machine's transition table instead of simply
+ forwarding events.</para>
+ </listitem>
+ <listitem>
+ <para>It solves transition conflicts at compile-time</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect1>
+ <refsect1>
+ <title>msm/back/favor_compile_time.hpp</title>
+ <para>This header contains the definition of favor_compile_time. This policy has two settings:<itemizedlist>
+ <listitem>
+ <para>Submachines dispatch is slower because all events, even those with
+ no dispatch chance, are forwarded to submachines. In exchange, no
+ row is added into the containing machine's transition table, which
+ reduces compile-time.</para>
+ </listitem>
+ <listitem>
+ <para>It solves transition conflicts at run-time.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect1>
+ <refsect1>
+ <title>msm/back/metafunctions.hpp </title>
+ <para>This header contains metafunctions for use by the library. Three metafunctions
+ can be useful for the user:<itemizedlist>
+ <listitem>
+ <para><code>generate_state_set< stt ></code>: generates the list of
+ all states referenced by the transition table stt. If stt is a
+ recursive table (generated by
+ <code>recursive_get_transition_table</code>), the metafunction
+ finds recursively all states of the submachines. A non-recursive
+ table can be obtained with some_backend_fsm::stt.</para>
+ </listitem>
+ <listitem>
+ <para><code>generate_event_set< stt></code>: generates the list of
+ all events referenced by the transition table stt. If stt is a
+ recursive table (generated by
+ <code>recursive_get_transition_table</code>), the metafunction
+ finds recursively all events of the submachines. A non-recursive
+ table can be obtained with some_backend_fsm::stt.</para>
+ </listitem>
+ <listitem>
+ <para><code>recursive_get_transition_table<fsm></code>: recursively
+ extends the transition table of the state machine fsm with tables
+ from the submachines.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect1>
+ <refsect1>
+ <title>msm/back/tools.hpp </title>
+ <para> This header contains a few metaprogramming tools to get some information out
+ of a state machine.</para>
+ <refsect2>
+ <title>fill_state_names </title>
+ <refsect3>
+ <title>attributes </title>
+ <para> fill_state_names has for attribute:<itemizedlist>
+ <listitem>
+ <para><code>char const** m_names</code>: an already allocated
+ array of const char* where the typeid-generated names of a
+ state machine states will be witten.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>constructor </title>
+ <constructorsynopsis>
+ <methodparam>
+ <funcparams>char const** names_to_fill</funcparams>
+ </methodparam>
+ </constructorsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>usage</title>
+ <para> fill_state_names is made for use in a mpl::for_each iterating on a
+ state list and writing inside a pre-allocated array the state names.
+ Example:</para>
+ <programlisting>typedef some_fsm::stt Stt;
+typedef msm::back::generate_state_set<Stt>::type all_states; //states
+static char const* state_names[mpl::size<all_states>::value];
+// array to fill with names
+// fill the names of the states defined in the state machine
+mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1> >
+ (msm::back::fill_state_names<Stt>(state_names));
+// display all active states
+for (unsigned int i=0;i<some_fsm::nr_regions::value;++i)
+{
+ std::cout << " -> "
+ << state_names[my_fsm_instance.current_state()[i]]
+ << std::endl;
+}</programlisting>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>get_state_name </title>
+ <refsect3>
+ <title> attributes </title>
+ <para>get_state_name has for attributes:<itemizedlist>
+ <listitem>
+ <para>std::string& m_name: the return value of the
+ iteration</para>
+ </listitem>
+ <listitem>
+ <para>int m_state_id: the searched state's id</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>constructor</title>
+ <para>The constructor takes as argument a reference to the string to fill
+ with the state name and the id which must be searched.</para>
+ <constructorsynopsis>
+ <methodparam>
+ <funcparams>string& name_to_fill,int state_id</funcparams>
+ </methodparam>
+ </constructorsynopsis>
+ </refsect3>
+ <refsect3>
+ <title> usage</title>
+ <para>This type is made for the same search as in the previous example,
+ using a mpl::for_each to iterate on states. After the iteration, the
+ state name reference has been set.</para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>display_type </title>
+ <refsect3>
+ <title> attributes </title>
+ <para>none</para>
+ </refsect3>
+ <refsect3>
+ <title> usage</title>
+ <para>Reusing the state list from the previous example, we can output all
+ state names:</para>
+ <para><code>mpl::for_each<all_states,boost::msm::wrap<mpl::placeholders::_1>
+ >(msm::back::display_type ());</code></para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ </refentry>
+ <refentry>
+ <refnamediv>
+ <refname>Front-end</refname>
+ <refpurpose>The front-end headers</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>msm/front/common_states.hpp</title>
+ <para>This header contains the predefined types to serve as base for states or state machines:<itemizedlist>
+ <listitem>
+ <para>default_base_state: non-polymorphic empty type.</para>
+ </listitem>
+ <listitem>
+ <para>polymorphic_state: type with a virtual destructor, which makes all
+ states polymorphic.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/completion_event.hpp</title>
+ <para>This header contains one type, <code>none</code>. This type has several
+ meanings inside a transition table:<itemizedlist>
+ <listitem>
+ <para>as action or guard: that there is no action or guard</para>
+ </listitem>
+ <listitem>
+ <para>as target state: that the transition is an internal
+ transition</para>
+ </listitem>
+ <listitem>
+ <para>as event: the transition is an anonymous (completion)
+ transition</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/functor_row.hpp</title>
+ <para>This header implements the functor front-end's transitions and helpers.</para>
+ <refsect2>
+ <title>Row</title>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class Source,class Event,class Target,class
+ Action,class Guard> Row</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>tags</title>
+ <para>row_type_tag is defined differently for every specialization:<itemizedlist>
+ <listitem>
+ <para>all 5 template parameters means a normal transition with
+ action and guard: <code>typedef row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Row<Source,Event,Target,none,none> a normal transition
+ without action or guard: <code>typedef _row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Row<Source,Event,Target,Action,none> a normal
+ transition without guard: <code>typedef a_row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Row<Source,Event,Target,none,Guard> a normal transition
+ without action: <code>typedef g_row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Row<Source,Event,none,Action,none> an internal
+ transition without guard: <code>typedef a_irow_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Row<Source,Event,none,none,Guard> an internal
+ transition without action: <code>typedef g_irow_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Row<Source,Event,none,none,Guard> an internal
+ transition with action and guard: <code>typedef irow_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Row<Source,Event,none,none,none> an internal transition
+ without action or guard: <code>typedef _irow_tag
+ row_type_tag;</code></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>methods</title>
+ <para>Like any other front-end, Row implements the two necessary static
+ functions for action and guard call. Each function receives as parameter
+ the (deepest-level) state machine processsing the event, the event
+ itself, the source and target states and all the states contained in a
+ state machine.</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>Internal</title>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class Event,class Action,class Guard>
+ Internal</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>tags</title>
+ <para>row_type_tag is defined differently for every specialization:<itemizedlist>
+ <listitem>
+ <para>all 3 template parameters means an internal transition
+ with action and guard: <code>typedef sm_i_row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Internal<Event,none,none> an internal transition
+ without action or guard: <code>typedef sm__i_row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Internal<Event,Action,none> an internal transition
+ without guard: <code>typedef sm_a_i_row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ <listitem>
+ <para>Internal<Event,none,Guard> an internal transition
+ without action: <code>typedef sm_g_i_row_tag
+ row_type_tag;</code></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>methods</title>
+ <para>Like any other front-end, Internal implements the two necessary static
+ functions for action and guard call. Each function receives as parameter
+ the (deepest-level) state machine processsing the event, the event
+ itself, the source and target states and all the states contained in a
+ state machine.</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>ActionSequence_</title>
+ <para>This functor calls every element of the template Sequence (which are also
+ callable functors) in turn. It is also the underlying implementation of the
+ eUML sequence grammar (action1,action2,...).</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class Sequence> ActionSequence_</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>methods</title>
+ <para>This helper functor is made for use in a transition table and in a
+ state behavior and therefore implements an operator() with 3 and with 4
+ arguments:</para>
+ <para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Evt,class Fsm,class
+ SourceState,class TargetState> operator()</funcdef>
+ <paramdef>Evt const& ,Fsm& ,SourceState&
+ ,TargetState& </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </para>
+ <para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Evt,class Fsm,class State>
+ operator()</funcdef>
+ <paramdef>Evt const&, Fsm&, State&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>Defer</title>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>Defer</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>methods</title>
+ <para>This helper functor is made for use in a transition table and
+ therefore implements an operator() with 4 arguments:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Evt,class Fsm,class SourceState,class
+ TargetState> operator()</funcdef>
+ <paramdef>Evt const&, Fsm& , SourceState&,
+ TargetState&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/internal_row.hpp</title>
+ <para>This header implements the internal transition rows for use inside an
+ internal_transition_table. All these row types have no source or target state,
+ as the backend will recognize internal transitions from this
+ internal_transition_table.</para>
+ <refsect2>
+ <title>methods</title>
+ <para>Like any other front-end, the following transition row types implements
+ the two necessary static functions for action and guard call. Each function
+ receives as parameter the (deepest-level) state machine processsing the
+ event, the event itself, the source and target states and all the states
+ contained in a state machine.</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect2>
+ <refsect2>
+ <title>a_internal</title>
+ <refsect3>
+ <title>definition</title>
+ <para>This is an internal transition with an action called during the
+ transition.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Event, class CalledForAction, void
+ (CalledForAction::*action)(Event const&)>
+ a_internal</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the internal
+ transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method which CalledForAction
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>g_internal</title>
+ <para>This is an internal transition with a guard called before the transition
+ and allowing the transition if returning true.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Event, class CalledForGuard, bool
+ (CalledForGuard::*guard)(Event const&)>
+ g_internal</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the internal
+ transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method which CalledForGuard
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>internal</title>
+ <para>This is an internal transition with a guard called before the transition
+ and allowing the transition if returning true. It also calls an action
+ called during the transition.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Event, class CalledForAction, void
+ (CalledForAction::*action)(Event const&), class
+ CalledForGuard, bool (CalledForGuard::*guard)(Event const&)>
+ internal</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the internal transition</para>
+ </listitem>
+ <listitem>
+ <para>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method which CalledForAction
+ provides.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method which CalledForGuard
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>_internal</title>
+ <para>This is an internal transition without action or guard. This is equivalent
+ to an explicit "ignore event".</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Event > _internal</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the internal
+ transition.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/row2.hpp</title>
+ <para>This header contains the variants of row2, which are an extension of the
+ standard row transitions for use in the transition table. They offer the
+ possibility to define action and guard not only in the state machine, but in any
+ state of the state machine. They can also be used in internal transition tables
+ through their irow2 variants.</para>
+ <refsect2>
+ <title>methods</title>
+ <para>Like any other front-end, the following transition row types implements
+ the two necessary static functions for action and guard call. Each function
+ receives as parameter the (deepest-level) state machine processsing the
+ event, the event itself, the source and target states and all the states
+ contained in a state machine.</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect2>
+ <refsect2>
+ <title>_row2</title>
+ <para>This is a transition without action or guard. The state machine only
+ changes active state.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Source, class Event, class Target >
+ _row2</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>a_row2</title>
+ <para>This is a transition with action and without guard.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Source, class Event, class Target,
+ </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForAction, void
+ (CalledForAction::*action)(Event const&) > _row2</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method which CalledForAction
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>g_row2</title>
+ <para>This is a transition with guard and without action.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Source, class Event, class Target,
+ </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method which CalledForGuard
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>row2</title>
+ <para>This is a transition with guard and action.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Source, class Event, class Target,
+ </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForAction, void
+ (CalledForAction::*action)(Event const&), </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method which CalledForAction
+ provides.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method which CalledForGuard
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>a_irow2</title>
+ <para>This is an internal transition for use inside a transition table, with
+ action and without guard.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Source, class Event, </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForAction, void
+ (CalledForAction::*action)(Event const&) > _row2</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method which CalledForAction
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>g_irow2</title>
+ <para>This is an internal transition for use inside a transition table, with
+ guard and without action.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Source, class Event, </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method which CalledForGuard
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>irow2</title>
+ <para>This is an internal transition for use inside a transition table, with
+ guard and action.</para>
+ <refsect3>
+ <title>definition</title>
+ <classsynopsis>
+ <ooclass>
+ <classname>template< class Source, class Event, </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForAction, void
+ (CalledForAction::*action)(Event const&), </classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class CalledForGuard, bool (CalledForGuard::*guard)(Event
+ const&) > _row2</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>template parameters</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForAction: the type on which the action method will
+ be called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method which CalledForAction
+ provides.</para>
+ </listitem>
+ <listitem>
+ <para>CalledForGuard: the type on which the guard method will be
+ called. It can be either a state of the containing state
+ machine or the state machine itself.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method which CalledForGuard
+ provides.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/state_machine_def.hpp</title>
+ <para>This header provides the implementation of the <command
+ xlink:href="#basic-front-end">basic front-end</command>. It contains one
+ type, <code>state_machine_def</code></para>
+ <refsect2>
+ <title>state_machine_def definition</title>
+ <para>This type is the basic class for a basic (or possibly any other)
+ front-end. It provides the standard row types (which includes internal
+ transitions) and a default implementation of the required methods and
+ typedefs.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class Derived,class BaseState =
+ default_base_state> state_machine_def</classname>
+ </ooclass>
+ </classsynopsis>
+ <refsect3>
+ <title>typedefs</title>
+ <para>
+ <itemizedlist>
+ <listitem>
+ <para>flag_list: by default, no flag is set in the state
+ machine</para>
+ </listitem>
+ <listitem>
+ <para>deferred_events: by default, no event is deferred.</para>
+ </listitem>
+ <listitem>
+ <para>configuration: by default, no configuration customization
+ is done.</para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>row methods</title>
+ <para>Like any other front-end, the following transition row types
+ implements the two necessary static functions for action and guard call.
+ Each function receives as parameter the (deepest-level) state machine
+ processsing the event, the event itself, the source and target states
+ and all the states contained in a state machine (ignored).</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static void action_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class SourceState,class TargetState,
+ class AllStates> static bool guard_call</funcdef>
+ <paramdef>
+ <funcparams>Fsm& fsm,Event const&
+ evt,SourceState&,TargetState,AllStates&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>a_row</title>
+ <para>This is a transition with action and without guard.</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event, class Target,
+ void (Derived::*action)(Event const&) > a_row</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>g_row</title>
+ <para>This is a transition with guard and without action.</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event, class Target,
+ bool (Derived::*guard)(Event const&) > g_row</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>row</title>
+ <para>This is a transition with guard and action.</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event, class Target,
+ void (Derived::*action)(Event const&), bool
+ (Derived::*guard)(Event const&) > row</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>_row</title>
+ <para>This is a transition without action or guard. The state machine only
+ changes active state.</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event, class Target >
+ _row</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Target: the target state of the transition.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>a_irow</title>
+ <para>This is an internal transition for use inside a transition table, with
+ action and without guard.</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event, void
+ (Derived::*action)(Event const&) > a_irow</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>g_irow</title>
+ <para>This is an internal transition for use inside a transition table, with
+ guard and without action.</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event, bool
+ (Derived::*guard)(Event const&) > g_irow</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>irow</title>
+ <para>This is an internal transition for use inside a transition table, with
+ guard and action.</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event, void
+ (Derived::*action)(Event const&), bool
+ (Derived::*guard)(Event const&) > irow</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ <listitem>
+ <para>action: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ <listitem>
+ <para>guard: a pointer to the method provided by the concrete
+ front-end (represented by <code>Derived</code>).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>_irow</title>
+ <para>This is an internal transition without action or guard. As it does
+ nothing, it means "ignore event".</para>
+ <para><ooclass>
+ <classname>template< class Source, class Event >
+ _irow</classname>
+ </ooclass><itemizedlist>
+ <listitem>
+ <para>Event: the event triggering the transition.</para>
+ </listitem>
+ <listitem>
+ <para>Source: the source state of the transition.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>methods</title>
+ <para><code>state_machine_def</code> provides a default implementation in
+ case of an event which cannot be processed by a state machine (no
+ transition found). The implementation is using a
+ <code>BOOST_ASSERT</code> so that the error will only be noticed in
+ debug mode. Overwrite this method in your implementation to change the
+ behavior.</para>
+ <para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class Event> static void
+ no_transition</funcdef>
+ <paramdef>
+ <funcparams>Event const& ,Fsm&, int
+ state</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </para>
+ <para><code>state_machine_def</code> provides a default implementation in
+ case an exception is thrown by a state (entry/exit) or transition
+ (action/guard) behavior. The implementation is using a
+ <code>BOOST_ASSERT</code> so that the error will only be noticed in
+ debug mode. Overwrite this method in your implementation to change the
+ behavior. This method will be called only if exception handling is not
+ deactivated (default) by defining
+ <code>has_no_message_queue</code>.</para>
+ <para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class Fsm,class Event> static void
+ exception_caught</funcdef>
+ <paramdef>
+ <funcparams>Event const& ,Fsm&,
+ std::exception&</funcparams>
+ </paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/states.hpp </title>
+ <para>This header provides the different states (except state machines) for the
+ basic front-end (or mixed with other front-ends).</para>
+ <refsect2>
+ <title>types</title>
+ <para>This header provides the following types:</para>
+ <refsect3>
+ <title>no_sm_ptr</title>
+ <para>deprecated: default policy for states. It means that states do not
+ need to save a pointer to their containing state machine.</para>
+ </refsect3>
+ <refsect3>
+ <title>sm_ptr</title>
+ <para>deprecated: state policy. It means that states need to save a pointer
+ to their containing state machine. When seeing this flag, the back-end
+ will call set_sm_ptr(fsm*) and give itself as argument.</para>
+ </refsect3>
+ <refsect3>
+ <title>state</title>
+ <para>Basic type for simple states. Inherit from this type to define a
+ simple state. The first argument is needed if you want your state (and
+ all others used in a concrete state machine) to inherit a basic type for
+ logging or providing a common behavior.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template<class Base = default_base_state,class
+ SMPtrPolicy = no_sm_ptr> state</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>terminate_state</title>
+ <para>Basic type for terminate states. Inherit from this type to define a
+ terminate state. The first argument is needed if you want your state
+ (and all others used in a concrete state machine) to inherit a basic
+ type for logging or providing a common behavior.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template<class Base = default_base_state,class
+ SMPtrPolicy = no_sm_ptr> terminate_state</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>interrupt_state</title>
+ <para>Basic type for interrupt states. Interrupt states prevent any further
+ event handling until EndInterruptEvent is sent. Inherit from this type
+ to define a terminate state. The first argument is the name of the event
+ ending the interrupt. The second argument is needed if you want your
+ state (and all others used in a concrete state machine) to inherit a
+ basic type for logging or providing a common behavior.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template<class EndInterruptEvent,class Base =
+ default_base_state,</classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class SMPtrPolicy = no_sm_ptr>
+ interrupt_state</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>explicit_entry</title>
+ <para>Inherit from this type <emphasis role="underline">in
+ addition</emphasis> to the desired state type to enable this state
+ for direct entering. The template parameter gives the region id of the
+ state (regions are numbered in the order of the
+ <code>initial_state</code> typedef).</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <int ZoneIndex=-1> explicit_entry</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>entry_pseudo_state</title>
+ <para>Basic type for entry pseudo states. Entry pseudo states are an
+ predefined entry into a submachine and connect two transitions. The
+ first argument is the id of the region entered by this state (regions
+ are numbered in the order of the <code>initial_state</code> typedef).
+ The second argument is needed if you want your state (and all others
+ used in a concrete state machine) to inherit a basic type for logging or
+ providing a common behavior.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template<int RegionIndex=-1,class Base =
+ default_base_state,</classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class SMPtrPolicy = no_sm_ptr>
+ entry_pseudo_state</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>exit_pseudo_state</title>
+ <para>Basic type for exit pseudo states. Exit pseudo states are an
+ predefined exit from a submachine and connect two transitions. The first
+ argument is the name of the event which will be "thrown" out of the exit
+ point. This event does not need to be the same as the one sent by the
+ inner region but must be convertible from it. The second argument is
+ needed if you want your state (and all others used in a concrete state
+ machine) to inherit a basic type for logging or providing a common
+ behavior.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template<class Event,class Base =
+ default_base_state,</classname>
+ </ooclass>
+ </classsynopsis>
+ <classsynopsis>
+ <ooclass>
+ <classname>class SMPtrPolicy = no_sm_ptr>
+ exit_pseudo_state</classname>
+ </ooclass>
+ </classsynopsis>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/euml.hpp</title>
+ <para>This header includes all of eUML except the STL functors.</para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/stl.hpp</title>
+ <para>This header includes all the functors for STL support in eUML. These <command
+ xlink:href="#eUML-STL-all">tables</command> show a full description.</para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/algorithm.hpp</title>
+ <para>This header includes all the functors for STL algorithms support in eUML.
+ These <command xlink:href="#eUML-STL-all">tables</command> show a full
+ description.</para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/iteration.hpp</title>
+ <para>This header includes iteration functors for STL support in eUML. This <command
+ xlink:href="#eUML-STL-iteration">tables</command> shows a full
+ description.</para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/querying.hpp</title>
+ <para>This header includes querying functors for STL support in eUML. This <command
+ xlink:href="#eUML-STL-querying">tables</command> shows a full
+ description.</para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/transformation.hpp</title>
+ <para>This header includes transformation functors for STL support in eUML. This
+ <command xlink:href="#eUML-STL-transformation">tables</command> shows a full
+ description.</para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/container.hpp</title>
+ <para>This header includes container functors for STL support in eUML (functors
+ calling container methods). This <command xlink:href="#eUML-STL-container"
+ >tables</command> shows a full description. It also provides npos for
+ strings.</para>
+ <refsect2>
+ <title>Npos_<container type></title>
+ <para>Functor returning npos for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Example:</para>
+ <para><code>string_find_(event_(m_song),Char_<'S'>(),Size_t_<0>()) !=
+ Npos_<string>() // compare result of string::find with
+ npos</code></para>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/stt_grammar.hpp</title>
+ <para>This header provides the transition table grammars. This includes internal
+ transition tables.</para>
+ <refsect2>
+ <title>functions</title>
+ <refsect3>
+ <title>build_stt</title>
+ <para>The function build_stt evaluates the grammar-conform expression as
+ parameter. It returns a transition table, which is a mpl::vector of
+ transitions (rows) or, if the expression is ill-formed (does not match
+ the grammar), the type <code>invalid_type</code>, which will lead to a
+ compile-time static assertion when this transition table is passed to a
+ state machine. </para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template<class Expr> [mpl::vector<...> /
+ msm::front::euml::invalid_type] build_stt</funcdef>
+ <paramdef>Expr const& expr</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ <refsect3>
+ <title>build_internal_stt</title>
+ <para>The function build_internal_stt evaluates the grammar-conform
+ expression as parameter. It returns a transition table, which is a
+ mpl::vector of transitions (rows) or, if the expression is ill-formed
+ (does not match the grammar), the type <code>invalid_type</code>, which
+ will lead to a compile-time static assertion when this transition table
+ is passed to a state machine. </para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template<class Expr> [mpl::vector<...> /
+ msm::front::euml::invalid_type] build_internal_stt</funcdef>
+ <paramdef>Expr const& expr</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsect3>
+ </refsect2>
+ <refsect2>
+ <title>grammars</title>
+ <refsect3>
+ <title><command xml:id="reference-stt-grammar">transition
+ table</command></title>
+ <para>The transition table accepts the following grammar:</para>
+ <programlisting>Stt := Row | (Stt ',' Stt)
+Row := (Target '==' (SourcePlusEvent)) /* first syntax*/
+ | ( (SourcePlusEvent) '==' Target ) /* second syntax*/
+ | (SourcePlusEvent) /* internal transitions */
+SourcePlusEvent := (BuildSource '+' BuildEvent)/* standard transition*/
+ | (BuildSource) /* anonymous transition */
+BuildSource := state_tag | (state_tag '/' Action) | (state_tag '[' Guard ']')
+ | (state_tag '[' Guard ']' '/' Action)
+BuildEvent := event_tag | (event_tag '/' Action) | (event_tag '[' Guard ']')
+ | (event_tag '[' Guard ']' '/' Action)</programlisting>
+ <para>The grammars Action and Guard are defined in state_grammar.hpp and
+ guard_grammar.hpp respectively. state_tag and event_tag are inherited
+ from euml_state (or other state variants) and euml_event respectively.
+ For example, following declarations are possible:</para>
+ <programlisting>target == source + event [guard] / action,
+source + event [guard] / action == target,
+source + event [guard] / (action1,action2) == target,
+target == source + event [guard] / (action1,action2),
+target == source + event,
+source + event == target,
+target == source + event [guard],
+source + event [guard] == target,
+target == source + event / action,
+source + event /action == target,
+source / action == target, /*anonymous transition*/
+target == source / action, /*anonymous transition*/
+source + event /action, /* internal transition*/</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>internal transition table</title>
+ <para>The internal transition table accepts the following grammar:</para>
+ <programlisting>IStt := BuildEvent | (IStt ',' IStt)</programlisting>
+ <para>BuildEvent being defined for both internal and standard transition
+ tables.</para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/guard_grammar.hpp</title>
+ <para>This header contains the <code>Guard</code> grammar used in the previous
+ section. This grammar is long but pretty simple:</para>
+ <programlisting>Guard := action_tag | (Guard '&&' Guard)
+ | (Guard '||' Guard) | ... /* operators*/
+ | (if_then_else_(Guard,Guard,Guard)) | (function (Action,...Action))</programlisting>
+ <para>Most C++ operators are supported (address-of is not). With
+ <code>function</code> is meant any eUML predefined function or any self-made
+ (using <code>MSM_EUML_METHOD</code> or <code>MSM_EUML_FUNCTION</code>). Action
+ is a grammar defined in state_grammar.hpp.</para>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/state_grammar.hpp</title>
+ <para>This header provides the grammar for actions and the different grammars and
+ functions to build states using eUML.</para>
+ <refsect2>
+ <title>action grammar</title>
+ <para>Like the guard grammar, this grammar supports relevant C++ operators and
+ eUML functions:</para>
+ <programlisting>Action := action_tag | (Action '+' Action)
+ | ('--' Action) | ... /* operators*/
+ | if_then_else_(Guard,Action,Action) | if_then_(Action)
+ | while_(Guard,Action)
+ | do_while_(Guard,Action) | for_(Action,Guard,Action,Action)
+ | (function(Action,...Action))
+ActionSequence := Action | (Action ',' Action)</programlisting>
+ <para>Relevant operators are: ++ (post/pre), -- (post/pre), dereferencing, +
+ (unary/binary), - (unary/binary), *, /, %, &(bitwise), | (bitwise),
+ ^(bitwise), +=, -=, *=, /=, %=, <<=, >>=, <<, >>, =, [].</para>
+ </refsect2>
+ <refsect2>
+ <title>attributes</title>
+ <para>This grammar is used to add attributes to states (or state machines) or
+ events: It evaluates to a fusion::map. You can use two forms:<itemizedlist>
+ <listitem>
+ <para><code>attributes_ << no_attributes_</code></para>
+ </listitem>
+ <listitem>
+ <para><code>attributes_ << attribute_1 << ... <<
+ attribute_n</code></para>
+ </listitem>
+ </itemizedlist></para>
+ <para>Attributes can be of any default-constructible type (fusion
+ requirement).</para>
+ </refsect2>
+ <refsect2>
+ <title>configure</title>
+ <para>This grammar also has two forms:<itemizedlist>
+ <listitem>
+ <para><code>configure_ << no_configure_</code></para>
+ </listitem>
+ <listitem>
+ <para><code>configure_ << type_1 << ... <<
+ type_n</code></para>
+ </listitem>
+ </itemizedlist></para>
+ <para>This grammar is used to create inside one syntax:<itemizedlist>
+ <listitem>
+ <para>flags: <code>configure_ << some_flag</code> where
+ some_flag inherits from <code>euml_flag<some_flag></code> or
+ is defined using BOOST_MSM_EUML_FLAG.</para>
+ </listitem>
+ <listitem>
+ <para>deferred events: <code>configure_ << some_event</code>
+ where some_event inherits from
+ <code>euml_event<some_event></code> or is defined using
+ BOOST_MSM_EUML_EVENT or
+ BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES.</para>
+ </listitem>
+ <listitem>
+ <para>configuration (message queue, manual deferring, exception
+ handling): <code>configure_ << some_config</code> where
+ some_config inherits from
+ <code>euml_config<some_config></code>. At the moment,
+ three predefined objects exist (in msm//front/euml/common.hpp):<itemizedlist>
+ <listitem>
+ <para>no_exception: disable catching exceptions</para>
+ </listitem>
+ <listitem>
+ <para>no_msg_queue: disable message queue</para>
+ </listitem>
+ <listitem>
+ <para>deferred_events: manually enable handling of
+ deferred events</para>
+ </listitem>
+ </itemizedlist></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect2>
+ <refsect2>
+ <title>initial states</title>
+ <para>The grammar to define initial states for a state machine is: <code>init_
+ << state_1 << ... << state_n</code> where
+ state_1...state_n inherit from euml_state or is defined using
+ BOOST_MSM_EUML_STATE, BOOST_MSM_EUML_INTERRUPT_STATE,
+ BOOST_MSM_EUML_TERMINATE_STATE, BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE,
+ BOOST_MSM_EUML_ENTRY_STATE or BOOST_MSM_EUML_EXIT_STATE.</para>
+ </refsect2>
+ <refsect2>
+ <title>functions</title>
+ <refsect3>
+ <title>build_sm</title>
+ <para>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</para>
+ <para>Defines a state machine without entry or exit:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Stt,class Init>
+ func_state_machine<...> build_sm</funcdef>
+ <paramdef>Stt ,Init</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a state machine with entry behavior:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Stt,class Init,class
+ Expr1> func_state_machine<...> build_sm</funcdef>
+ <paramdef>Stt ,Init,Expr1 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a state machine with entry and exit behaviors:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2> func_state_machine<...>
+ build_sm</funcdef>
+ <paramdef>Stt ,Init,Expr1 const&,Expr2 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a state machine with entry, exit behaviors and
+ attributes:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2, class Attributes> func_state_machine<...>
+ build_sm</funcdef>
+ <paramdef>Stt ,Init,Expr1 const&, Expr2 const&, Attributes
+ const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a state machine with entry, exit behaviors, attributes and
+ configuration (deferred events, flags):</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2, class Attributes, class Configure>
+ func_state_machine<...> build_sm</funcdef>
+ <paramdef>Stt ,Init,Expr1 const&, Expr2 const&, Attributes
+ const&, Configure const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a state machine with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Stt,class Init,class
+ Expr1, class Expr2, class Attributes, class Configure, class
+ Base> func_state_machine<...> build_sm</funcdef>
+ <paramdef>Stt ,Init,Expr1 const&, Expr2 const&, Attributes
+ const&, Configure const&, Base</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate state machines having the same parameters
+ but still being different.</para>
+ </refsect3>
+ <refsect3>
+ <title>build_state</title>
+ <para>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</para>
+ <para>Defines a simple state without entry or exit:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>func_state<class StateNameTag,...> build_state</funcdef>
+ <paramdef/>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a simple state with entry behavior:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Expr1>
+ func_state<...> build_state</funcdef>
+ <paramdef>Expr1 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a simple state with entry and exit behaviors:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Expr1, class Expr2>
+ func_state<...> build_state</funcdef>
+ <paramdef>Expr1 const&,Expr2 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a simple state with entry, exit behaviors and
+ attributes:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Expr1, class Expr2,
+ class Attributes> func_state<...> build_state</funcdef>
+ <paramdef>Expr1 const&, Expr2 const&, Attributes
+ const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a simple state with entry, exit behaviors, attributes and
+ configuration (deferred events, flags):</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Expr1, class Expr2,
+ class Attributes, class Configure> func_state<...>
+ build_state</funcdef>
+ <paramdef>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines a simple state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Expr1, class Expr2,
+ class Attributes, class Configure, class Base>
+ func_state<...> build_state</funcdef>
+ <paramdef>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&, Base</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</para>
+ </refsect3>
+ <refsect3>
+ <title>build_terminate_state</title>
+ <para>This function has the same overloads as build_state.</para>
+ </refsect3>
+ <refsect3>
+ <title>build_interrupt_state</title>
+ <para>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</para>
+ <para>Defines an interrupt state without entry or exit:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class EndInterruptEvent>
+ func_state<...> build_interrupt_state</funcdef>
+ <paramdef>EndInterruptEvent const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an interrupt state with entry behavior:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class
+ EndInterruptEvent,class Expr1> func_state<...>
+ build_interrupt_state</funcdef>
+ <paramdef>EndInterruptEvent const&,Expr1 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an interrupt state with entry and exit behaviors:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2> func_state<...>
+ build_interrupt_state</funcdef>
+ <paramdef>EndInterruptEvent const&,Expr1 const&,Expr2
+ const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an interrupt state with entry, exit behaviors and
+ attributes:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2, class Attributes>
+ func_state<...> build_interrupt_state</funcdef>
+ <paramdef>EndInterruptEvent const&,Expr1 const&, Expr2
+ const&, Attributes const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an interrupt state with entry, exit behaviors, attributes and
+ configuration (deferred events, flags):</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2, class Attributes,
+ class Configure> func_state<...>
+ build_interrupt_state</funcdef>
+ <paramdef>EndInterruptEvent const&,Expr1 const&, Expr2
+ const&, Attributes const&, Configure
+ const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an interrupt state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class
+ EndInterruptEvent,class Expr1, class Expr2, class Attributes,
+ class Configure, class Base> func_state<...>
+ build_interrupt_state</funcdef>
+ <paramdef>EndInterruptEvent const&,Expr1 const&, Expr2
+ const&, Attributes const&, Configure const&,
+ Base</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</para>
+ </refsect3>
+ <refsect3>
+ <title>build_entry_state</title>
+ <para>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</para>
+ <para>Defines an entry pseudo state without entry or exit:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,int RegionIndex>
+ entry_func_state<...> build_entry_state</funcdef>
+ <paramdef/>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an entry pseudo state with entry behavior:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,int RegionIndex,class
+ Expr1> entry_func_state<...> build_entry_state</funcdef>
+ <paramdef>Expr1 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an entry pseudo state with entry and exit behaviors:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2> entry_func_state<...>
+ build_entry_state</funcdef>
+ <paramdef>Expr1 const&,Expr2 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an entry pseudo state with entry, exit behaviors and
+ attributes:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2, class Attributes> entry_func_state<...>
+ build_entry_state</funcdef>
+ <paramdef>Expr1 const&, Expr2 const&, Attributes
+ const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an entry pseudo state with entry, exit behaviors, attributes
+ and configuration (deferred events, flags):</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2, class Attributes, class Configure>
+ entry_func_state<...> build_entry_state</funcdef>
+ <paramdef>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an entry pseudo state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,int RegionIndex,class
+ Expr1, class Expr2, class Attributes, class Configure, class
+ Base> entry_func_state<...> build_entry_state</funcdef>
+ <paramdef>Expr1 const&, Expr2 const&, Attributes const&,
+ Configure const&, Base</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</para>
+ </refsect3>
+ <refsect3>
+ <title>build_exit_state</title>
+ <para>This function has several overloads. The return type is not relevant
+ to you as only decltype (return type) is what one needs.</para>
+ <para>Defines an exit pseudo state without entry or exit:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Event>
+ exit_func_state<...> build_exit_state</funcdef>
+ <paramdef>Event const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an exit pseudo state with entry behavior:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Event,class Expr1>
+ exit_func_state<...> build_exit_state</funcdef>
+ <paramdef>Event const&,Expr1 const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an exit pseudo state with entry and exit behaviors:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Event,class Expr1,
+ class Expr2> exit_func_state<...> build_exit_state</funcdef>
+ <paramdef>Event const&,Expr1 const&,Expr2
+ const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an exit pseudo state with entry, exit behaviors and
+ attributes:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Event,class Expr1,
+ class Expr2, class Attributes> exit_func_state<...>
+ build_exit_state</funcdef>
+ <paramdef>Event const&,Expr1 const&, Expr2 const&,
+ Attributes const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an exit pseudo state with entry, exit behaviors, attributes
+ and configuration (deferred events, flags):</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Event,class Expr1,
+ class Expr2, class Attributes, class Configure>
+ exit_func_state<...> build_exit_state</funcdef>
+ <paramdef>Event const&,Expr1 const&, Expr2 const&,
+ Attributes const&, Configure const&</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Defines an exit pseudo state with entry, exit behaviors, attributes,
+ configuration (deferred events, flags) and a base state:</para>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>template <class StateNameTag,class Event,class Expr1,
+ class Expr2, class Attributes, class Configure, class Base>
+ exit_func_state<...> build_exit_state</funcdef>
+ <paramdef>Event const&,Expr1 const&, Expr2 const&,
+ Attributes const&, Configure const&, Base</paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ <para>Notice that this function requires the extra parameter class
+ StateNameTag to disambiguate states having the same parameters but still
+ being different.</para>
+ </refsect3>
+ <refsect3>
+ <title>build_explicit_entry_state</title>
+ <para>This function has the same overloads as build_entry_state and
+ explicit_entry_func_state as return type.</para>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>msm/front/euml/common.hpp</title>
+ <refsect2>
+ <title>types</title>
+ <refsect3>
+ <title>euml_event</title>
+ <para>The basic type for events with eUML.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class EventName> euml_event;</classname>
+ </ooclass>
+ </classsynopsis>
+ <programlisting>struct play : euml_event<play>{};</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>euml_state</title>
+ <para>The basic type for states with eUML. You will usually not use this
+ type directly as it is easier to use BOOST_MSM_EUML_STATE,
+ BOOST_MSM_EUML_INTERRUPT_STATE, BOOST_MSM_EUML_TERMINATE_STATE,
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE, BOOST_MSM_EUML_ENTRY_STATE or
+ BOOST_MSM_EUML_EXIT_STATE.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class StateName> euml_state;</classname>
+ </ooclass>
+ </classsynopsis>
+ <para>You can however use this type directly if you want to provide your
+ state with extra functions or provide entry or exit behaviors without
+ functors, for example:</para>
+ <programlisting>struct Empty : public msm::front::state<> , public euml_state<Empty>
+{
+ void foo() {...}
+ template <class Event,class Fsm>
+ void on_entry(Event const& evt,Fsm& fsm){...}
+};</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>euml_flag</title>
+ <para>The basic type for flags with eUML.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class FlagName> euml_flag;</classname>
+ </ooclass>
+ </classsynopsis>
+ <programlisting>struct PlayingPaused: euml_flag<PlayingPaused>{};</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>euml_action</title>
+ <para>The basic type for state or transition behaviors and guards with
+ eUML.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class AcionName> euml_action;</classname>
+ </ooclass>
+ </classsynopsis>
+ <programlisting>struct close_drawer : euml_action<close_drawer>
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ void operator()(Evt const& , Fsm&, SourceState& ,TargetState& ) {...}
+};</programlisting>
+ <para>Or, as state entry or exit behavior:</para>
+ <programlisting>struct Playing_Entry : euml_action<Playing_Entry>
+{
+ template <class Event,class Fsm,class State>
+ void operator()(Event const&,Fsm& fsm,State& ){...}
+};</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>euml_config</title>
+ <para>The basic type for configuration possibilities with eUML.</para>
+ <classsynopsis>
+ <ooclass>
+ <classname>template <class ConfigName> euml_config;</classname>
+ </ooclass>
+ </classsynopsis>
+ <para>You normally do not use this type directly but instead the instances
+ of predefined configuration:<itemizedlist>
+ <listitem>
+ <para>no_exception: disable catching exceptions</para>
+ </listitem>
+ <listitem>
+ <para>no_msg_queue: disable message queue. The message queue
+ allows you to send an event for procesing while in an event
+ processing.</para>
+ </listitem>
+ <listitem>
+ <para>deferred_events: manually enable handling of deferred
+ events</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>invalid_type</title>
+ <para>Type returned by grammar parsers if the grammar is invalid. Seeing
+ this type will result in a static assertion.</para>
+ </refsect3>
+ <refsect3>
+ <title>no_action</title>
+ <para>Placeholder type for use in entry/exit or transition behaviors, which
+ does absolutely nothing.</para>
+ </refsect3>
+ <refsect3>
+ <title>source_</title>
+ <para>Generic object or function for the source state of a given transition:<itemizedlist>
+ <listitem>
+ <para>as object: returns by reference the source state of a
+ transition, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</para>
+ <para>Example:
+ <programlisting>some_user_function_(source_)</programlisting></para>
+ </listitem>
+ <listitem>
+ <para>as function: returns by reference the attribute passed as
+ parameter.</para>
+ <para>Example:
+ <programlisting>source_(m_counter)++</programlisting></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>target_</title>
+ <para>Generic object or function for the target state of a given transition:<itemizedlist>
+ <listitem>
+ <para>as object: returns by reference the target state of a
+ transition, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</para>
+ <para>Example:
+ <programlisting>some_user_function_(target_)</programlisting></para>
+ </listitem>
+ <listitem>
+ <para>as function: returns by reference the attribute passed as
+ parameter.</para>
+ <para>Example:
+ <programlisting>target_(m_counter)++</programlisting></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>state_</title>
+ <para>Generic object or function for the state of a given entry / exit
+ behavior. state_ means source_ while in the context of an exit behavior
+ and target_ in the context of an entry behavior:<itemizedlist>
+ <listitem>
+ <para>as object: returns by reference the current state, usually
+ to be used by another function (usually one created by
+ MSM_EUML_METHOD or MSM_EUML_FUNCTION).</para>
+ <para>Example:
+ <programlisting>some_user_function_(state_) // calls some_user_function on the current state</programlisting></para>
+ </listitem>
+ <listitem>
+ <para>as function: returns by reference the attribute passed as
+ parameter.</para>
+ <para>Example:
+ <programlisting>state_(m_counter)++</programlisting></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>event_</title>
+ <para>Generic object or function for the event triggering a given transition
+ (valid in a transition behavior, as well as in state entry/exit behaviors):<itemizedlist>
+ <listitem>
+ <para>as object: returns by reference the event of a transition,
+ usually to be used by another function (usually one created
+ by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</para>
+ <para>Example:
+ <programlisting>some_user_function_(event_)</programlisting></para>
+ </listitem>
+ <listitem>
+ <para>as function: returns by reference the attribute passed as
+ parameter.</para>
+ <para>Example:
+ <programlisting>event_(m_counter)++</programlisting></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>fsm_</title>
+ <para>Generic object or function for the state machine containing a given transition:<itemizedlist>
+ <listitem>
+ <para>as object: returns by reference the event of a transition,
+ usually to be used by another function (usually one created
+ by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</para>
+ <para>Example:
+ <programlisting>some_user_function_(fsm_)</programlisting></para>
+ </listitem>
+ <listitem>
+ <para>as function: returns by reference the attribute passed as
+ parameter.</para>
+ <para>Example:
+ <programlisting>fsm_(m_counter)++</programlisting></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>substate_</title>
+ <para>Generic object or function returning a state of a given state machine:<itemizedlist>
+ <listitem>
+ <para>with 1 parameter: returns by reference the state passed as
+ parameter, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION).</para>
+ <para>Example:
+ <programlisting>some_user_function_(substate_(my_state))</programlisting></para>
+ </listitem>
+ <listitem>
+ <para>with 2 parameters: returns by reference the state passed
+ as first parameter from the state machine passed as second
+ parameter, usually to be used by another function (usually
+ one created by MSM_EUML_METHOD or MSM_EUML_FUNCTION). This
+ makes sense when used in combination with attribute_.</para>
+ <para>Example (equivalent to the previous example):
+ <programlisting>some_user_function_(substate_(my_state,fsm_))</programlisting></para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>attribute_</title>
+ <para>Generic object or function returning the attribute passed (by name) as
+ second parameter of the thing passed as first (a state, event or state
+ machine). Example: </para>
+ <para>
+ <programlisting>attribute_(substate_(my_state),cd_name_attribute)++</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>True_</title>
+ <para>Functor returning true for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Example:</para>
+ <para>
+ <programlisting>if_then_(True_(),/* some action always called*/)</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>False_</title>
+ <para>Functor returning false for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Example:</para>
+ <para>
+ <programlisting>if_then_(False_(),/* some action never called */)</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>Int_<int value></title>
+ <para>Functor returning an integer value for transition or state behaviors.
+ Like all constants, only the functor form exists, so parenthesis are
+ necessary. Example:</para>
+ <para>
+ <programlisting>target_(m_ringing_cpt) = Int_<RINGING_TIME>() // RINGING_TIME is a constant</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>Char_<char value></title>
+ <para>Functor returning a char value for transition or state behaviors. Like
+ all constants, only the functor form exists, so parenthesis are
+ necessary. Example:</para>
+ <para>
+ <programlisting>// look for 'S' in event.m_song
+[string_find_(event_(m_song),Char_<'S'>(),Size_t_<0>()) != Npos_<string>()]</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>Size_t_<size_t value></title>
+ <para>Functor returning a size_t value for transition or state behaviors.
+ Like all constants, only the functor form exists, so parenthesis are
+ necessary. Example:</para>
+ <para>
+ <programlisting>substr_(event_(m_song),Size_t_<1>()) // returns a substring of event.m_song</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>String_ < mpl::string ></title>
+ <para>Functor returning a string for transition or state behaviors. Like all
+ constants, only the functor form exists, so parenthesis are necessary.
+ Requires boost >= 1.40 for mpl::string.</para>
+ <para>Example:</para>
+ <para>
+ <programlisting>// adds "Let it be" to fsm.m_src_container
+push_back_(fsm_(m_src_container), String_<mpl::string<'Let','it ','be'> >())</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>Predicate_ < some_stl_compatible_functor ></title>
+ <para>This functor eUML-enables a STL functor (for use in an algorithm).
+ This is necessary because all what is in the transition table must be a
+ eUML terminal.</para>
+ <para>Example:</para>
+ <programlisting>//equivalent to:
+//std::accumulate(fsm.m_vec.begin(),fsm.m_vec.end(),1,std::plus<int>())== 1
+accumulate_(begin_(fsm_(m_vec)),end_(fsm_(m_vec)),Int_<1>(),
+ Predicate_<std::plus<int> >()) == Int_<1>())</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>process_</title>
+ <para>This function sends an event to up to 4 state machines by calling
+ <code>process_event</code> on them:<itemizedlist>
+ <listitem>
+ <para><code>process_(some_event)</code> : processes an event in
+ the current (containing) state machine.</para>
+ </listitem>
+ <listitem>
+ <para><code>process_(some_event [,fsm1...fsm4] )</code> :
+ processes the same event in the 1-4 state machines passed as
+ argument.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>process2_</title>
+ <para>This function sends an event to up to 3 state machines by calling
+ <code>process_event</code> on them and copy-constructing the event
+ from the data passed as second parameter:<itemizedlist>
+ <listitem>
+ <para><code>process2_(some_event, some_data)</code> : processes
+ an event in the current (containing) state machine.</para>
+ </listitem>
+ <listitem>
+ <para><code>process2_(some_event, some_data [,fsm1...fsm3]
+ )</code> : processes the same event in the 1-3 state
+ machines passed as argument.</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>Example: </para>
+ <para>
+ <programlisting>// processes NotFound on current state machine,
+// copy-constructed with event.m_song
+process2_(NotFound,event_(m_song))</programlisting>
+ </para>
+ <para>With the following definitions:</para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)//declaration of m_song
+NotFound (const string& data) // copy-constructor of NotFound</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>is_flag_</title>
+ <para>This function tells if a flag is active by calling
+ <code>is_flag_active</code> on the current state machine or one
+ passed as parameter:<itemizedlist>
+ <listitem>
+ <para><code>is_flag_(some_flag)</code> : calls
+ <code>is_flag_active</code> on the current (containing)
+ state machine.</para>
+ </listitem>
+ <listitem>
+ <para><code>is_flag_(some_flag, some_fsm)</code> :calls
+ <code>is_flag_active</code> on the state machine.passed
+ as argument.</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>defer_</title>
+ <para>This object defers the current event by calling
+ <code>defer_event</code> on the current state machine.
+ Example:</para>
+ <programlisting>Empty() + play() / defer_</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>explicit_(submachine-name,state-name)</title>
+ <para>Used as transition's target, causes an explicit entry into the given
+ state from the given submachine. Several explicit_ as targets, separated
+ by commas, means a fork. The state must have been declared as such using
+ BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE.</para>
+ </refsect3>
+ <refsect3>
+ <title>entry_pt_(submachine-name,state-name)</title>
+ <para>Used as transition's target from a containing state machine, causes
+ submachine-name to be entered using the given entry pseudo-state. This
+ state must have been declared as pseudo entry using
+ BOOST_MSM_EUML_ENTRY_STATE.</para>
+ </refsect3>
+ <refsect3>
+ <title>exit_pt_(submachine-name,state-name)</title>
+ <para>Used as transition's source from a containing state machine, causes
+ submachine-name to be left using the given exit pseudo-state. This state
+ must have been declared as pseudo exit using
+ BOOST_MSM_EUML_EXIT_STATE.</para>
+ </refsect3>
+ <refsect3>
+ <title>MSM_EUML_FUNCTION</title>
+ <para>This macro creates a eUML function and a functor for use with the
+ functor front-end, based on a free function:<itemizedlist>
+ <listitem>
+ <para>first parameter: the name of the functor</para>
+ </listitem>
+ <listitem>
+ <para>second parameter: the underlying function</para>
+ </listitem>
+ <listitem>
+ <para>third parameter: the eUML function name</para>
+ </listitem>
+ <listitem>
+ <para>fourth parameter: the return type if used in a transition
+ behavior</para>
+ </listitem>
+ <listitem>
+ <para>fifth parameter: the return type if used in a state
+ behavior (entry/exit)</para>
+ </listitem>
+ </itemizedlist> Note that the function itself can take up to 5
+ arguments.</para>
+ <para>Example:</para>
+ <para>
+ <programlisting>MSM_EUML_FUNCTION(BinarySearch_,std::binary_search,binary_search_,bool,bool)</programlisting>
+ </para>
+ <para>Can be used like:</para>
+ <para>
+ <programlisting>binary_search_(begin_(fsm_(m_var)),end_(fsm_(m_var)),Int_<9>())</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>MSM_EUML_METHOD</title>
+ <para>This macro creates a eUML function and a functor for use with the
+ functor front-end, based on a method:<itemizedlist>
+ <listitem>
+ <para>first parameter: the name of the functor</para>
+ </listitem>
+ <listitem>
+ <para>second parameter: the underlying function</para>
+ </listitem>
+ <listitem>
+ <para>third parameter: the eUML function name</para>
+ </listitem>
+ <listitem>
+ <para>fourth parameter: the return type if used in a transition
+ behavior</para>
+ </listitem>
+ <listitem>
+ <para>fifth parameter: the return type if used in a state
+ behavior (entry/exit)</para>
+ </listitem>
+ </itemizedlist> Note that the method itself can take up to 4 arguments
+ (5 like for a free function - 1 for the object on which the method is
+ called).</para>
+ <para>Example:</para>
+ <programlisting>struct Empty : public msm::front::state<> , public euml_state<Empty>
+{
+ void activate_empty() {std::cout << "switching to Empty " << std::endl;}
+...
+};
+MSM_EUML_METHOD(ActivateEmpty_,activate_empty,activate_empty_,void,void)</programlisting>
+ <para>Can be used like:</para>
+ <para>
+ <programlisting>Empty == Open + open_close / (close_drawer , activate_empty_(target_))</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_ACTION(action-instance-name)</title>
+ <para>This macro declares a behavior type and a const instance for use in
+ state or transition behaviors. The action implementation itself follows
+ the macro declaration, for example:</para>
+ <programlisting>BOOST_MSM_EUML_ACTION(good_disk_format)
+{
+ template <class Fsm,class Evt,class SourceState,class TargetState>
+ void/bool operator()(Evt const& evt,Fsm&,SourceState& ,TargetState& ){...}
+};</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_FLAG(flag-instance-name)</title>
+ <para>This macro declares a flag type and a const instance for use in
+ behaviors.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_FLAG_NAME(flag-instance-name)</title>
+ <para>This macro returns the name of the flag type generated by
+ BOOST_MSM_EUML_FLAG. You need this where the type is required (usually
+ with the back-end method is_flag_active). For example:</para>
+ <programlisting>fsm.is_flag_active<BOOST_MSM_EUML_FLAG_NAME(CDLoaded)>()</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_ATTRIBUTE(event-type,event-name)</title>
+ <para>This macro declares an attribute called event-name of type event-type.
+ This attribute can then be made part of an attribute list using
+ BOOST_MSM_EUML_ATTRIBUTES.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_ATTRIBUTES(attributes-expression,attributes-name)</title>
+ <para>This macro declares an attribute list called attributes-name based on
+ the expression as first argument. These attributes can then be made part
+ of an event using BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES, of a state as
+ 3rd parameter of BOOST_MSM_EUML_STATE or of a state machine as 5th
+ parameter of BOOST_MSM_EUML_DECLARE_STATE_MACHINE.</para>
+ <para>Attributes are added using left-shift, for example:</para>
+ <programlisting>// m_song is of type std::string
+BOOST_MSM_EUML_DECLARE_ATTRIBUTE(std::string,m_song)
+// contains one attribute, m_song
+BOOST_MSM_EUML_ATTRIBUTES((attributes_ << m_song ), FoundDef)</programlisting>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_EVENT(event-instance name)</title>
+ <para>This macro defines an event type (event-instance-name_helper) and
+ declares a const instance of this event type called event-instance-name
+ for use in a transition table or state behaviors.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(event-instance-name,attributes)</title>
+ <para>This macro defines an event type (event-instance-name_helper) and
+ declares a const instance of this event type called event-instance-name
+ for use in a transition table or state behaviors. The event will have as
+ attributes the ones passed by the second argument:</para>
+ <para><code>BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(Found,FoundDef)</code>
+ </para>
+ <para>The created event instance supports operator()(attributes) so that
+ <programlisting>my_back_end.process_event(Found(some_string))</programlisting>
+ is possible.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_EVENT_NAME(event-instance-name)</title>
+ <para>This macro returns the name of the event type generated by
+ BOOST_MSM_EUML_EVENT or BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES. You need
+ this where the type is required (usually inside a back-end definition).
+ For example:</para>
+ <para>
+ <programlisting>typedef msm::back::state_machine<Playing_,
+msm::back::ShallowHistory<mpl::vector<BOOST_MSM_EUML_EVENT_NAME(end_pause)
+> > > Playing_type;</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_STATE(build-expression,state-instance-name)</title>
+ <para>This macro defines a state type (state-instance-name_helper) and
+ declares a const instance of this state type called state-instance-name
+ for use in a transition table or state behaviors.</para>
+ <para>There are several possibilitites for the expression syntax:<itemizedlist>
+ <listitem>
+ <para>(): state without entry or exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1): state with entry but no exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2): state with entry and exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes): state with entry and exit
+ action, defining some attributes.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure): state with entry and
+ exit action, defining some attributes and flags (standard
+ MSM flags) or deferred events (standard MSM deferred
+ events).</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure,Base): state with entry
+ and exit action, defining some attributes, flags and
+ deferred events (plain msm deferred events) and a
+ non-default base state (as defined in standard MSM).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_INTERRUPT_STATE(build-expression,state-instance-name)</title>
+ <para>This macro defines an interrupt state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</para>
+ <para>There are several possibilitites for the expression syntax. In all of
+ them, the first argument is the name of the event (generated by one of
+ the previous macros) ending the interrupt:<itemizedlist>
+ <listitem>
+ <para>(end_interrupt_event): interrupt state without entry or
+ exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(end_interrupt_event,Expr1): interrupt state with entry
+ but no exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(end_interrupt_event,Expr1,Expr2): interrupt state with
+ entry and exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(end_interrupt_event,Expr1,Expr2,Attributes): interrupt
+ state with entry and exit action, defining some
+ attributes.</para>
+ </listitem>
+ <listitem>
+ <para>(end_interrupt_event,Expr1,Expr2,Attributes,Configure):
+ interrupt state with entry and exit action, defining some
+ attributes and flags (standard MSM flags) or deferred events
+ (standard MSM deferred events).</para>
+ </listitem>
+ <listitem>
+ <para>(end_interrupt_event,Expr1,Expr2,Attributes,Configure,Base):
+ interrupt state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_TERMINATE_STATE(build-expression,state-instance-name)</title>
+ <para>This macro defines a terminate pseudo-state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</para>
+ <para>There are several possibilitites for the expression syntax:<itemizedlist>
+ <listitem>
+ <para>(): terminate pseudo-state without entry or exit
+ action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1): terminate pseudo-state with entry but no exit
+ action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2): terminate pseudo-state with entry and exit
+ action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes): terminate pseudo-state with
+ entry and exit action, defining some attributes.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure): terminate pseudo-state
+ with entry and exit action, defining some attributes and
+ flags (standard MSM flags) or deferred events (standard MSM
+ deferred events).</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure,Base): terminate
+ pseudo-state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_EXIT_STATE(build-expression,state-instance-name)</title>
+ <para>This macro defines an exit pseudo-state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</para>
+ <para>There are several possibilitites for the expression syntax:<itemizedlist>
+ <listitem>
+ <para>(forwarded_event):exit pseudo-state without entry or exit
+ action.</para>
+ </listitem>
+ <listitem>
+ <para>(forwarded_event,Expr1): exit pseudo-state with entry but
+ no exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(forwarded_event,Expr1,Expr2): exit pseudo-state with
+ entry and exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(forwarded_event,Expr1,Expr2,Attributes): exit
+ pseudo-state with entry and exit action, defining some
+ attributes.</para>
+ </listitem>
+ <listitem>
+ <para>(forwarded_event,Expr1,Expr2,Attributes,Configure): exit
+ pseudo-state with entry and exit action, defining some
+ attributes and flags (standard MSM flags) or deferred events
+ (standard MSM deferred events).</para>
+ </listitem>
+ <listitem>
+ <para>(forwarded_event,Expr1,Expr2,Attributes,Configure,Base):
+ exit pseudo-state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</para>
+ </listitem>
+ </itemizedlist></para>
+ <para>Note that the forwarded_event must be constructible from the event
+ sent by the submachine containing the exit point.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</title>
+ <para>This macro defines an entry pseudo-state type
+ (state-instance-name_helper) and declares a const instance of this state
+ type called state-instance-name for use in a transition table or state
+ behaviors.</para>
+ <para>There are several possibilitites for the expression syntax:<itemizedlist>
+ <listitem>
+ <para>(): entry pseudo-state without entry or exit
+ action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1): entry pseudo-state with entry but no exit
+ action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2): entry pseudo-state with entry and exit
+ action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes): entry pseudo-state with entry
+ and exit action, defining some attributes.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure): entry pseudo-state
+ with entry and exit action, defining some attributes and
+ flags (standard MSM flags) or deferred events (standard MSM
+ deferred events).</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure,Base): entry
+ pseudo-state with entry and exit action, defining some
+ attributes, flags and deferred events (plain msm deferred
+ events) and a non-default base state (as defined in standard
+ MSM).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</title>
+ <para>This macro defines a submachine's substate type
+ (state-instance-name_helper), which can be explicitly entered and also
+ declares a const instance of this state type called state-instance-name
+ for use in a transition table or state behaviors.</para>
+ <para>There are several possibilitites for the expression syntax:<itemizedlist>
+ <listitem>
+ <para>(): state without entry or exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1): state with entry but no exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2): state with entry and exit action.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes): state with entry and exit
+ action, defining some attributes.</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure): state with entry and
+ exit action, defining some attributes and flags (standard
+ MSM flags) or deferred events (standard MSM deferred
+ events).</para>
+ </listitem>
+ <listitem>
+ <para>(Expr1,Expr2,Attributes,Configure,Base): state with entry
+ and exit action, defining some attributes, flags and
+ deferred events (plain msm deferred events) and a
+ non-default base state (as defined in standard MSM).</para>
+ </listitem>
+ </itemizedlist></para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_STATE_NAME(state-instance-name)</title>
+ <para>This macro returns the name of the state type generated by
+ BOOST_MSM_EUML_STATE or other state macros. You need this where the type
+ is required (usually using a backend function). For example:</para>
+ <para>
+ <programlisting>fsm.get_state<BOOST_MSM_EUML_STATE_NAME(StringFind)&>().some_state_function();</programlisting>
+ </para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_STATE(build-expression,state-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_STATE but does not provide an instance, simply a
+ type declaration.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_INTERRUPT_STATE(build-expression,state-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_INTERRUPT_STATE but does not provide an instance,
+ simply a type declaration.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_TERMINATE_STATE(build-expression,state-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_TERMINATE_STATE but does not provide an instance,
+ simply a type declaration.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_EXIT_STATE(build-expression,state-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_EXIT_STATE but does not provide an instance,
+ simply a type declaration.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_ENTRY_STATE but does not provide an instance,
+ simply a type declaration.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_EXPLICIT_ENTRY_STATE(int
+ region-index,build-expression,state-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_EXPLICIT_ENTRY_STATE but does not provide an
+ instance, simply a type declaration.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_TRANSITION_TABLE(expression,
+ table-instance-name)</title>
+ <para>This macro declares a transition table type and also declares a const
+ instance of the table which can then be used in a state machine
+ declaration (see BOOST_MSM_EUML_DECLARE_STATE_MACHINE).The expression
+ must follow the <command xlink:href="#reference-stt-grammar">transition
+ table grammar</command>.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE(iexpression,table-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_TRANSITION_TABLE but does not provide an instance,
+ simply a type declaration.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_INTERNAL_TRANSITION_TABLE(expression,
+ table-instance-name)</title>
+ <para>This macro declares a transition table type and also declares a const
+ instance of the table.The expression must follow the <command
+ xlink:href="#reference-stt-grammar">transition table
+ grammar</command>. For the moment, this macro is not used.</para>
+ </refsect3>
+ <refsect3>
+ <title>BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE(iexpression,table-instance-name)</title>
+ <para>Like BOOST_MSM_EUML_TRANSITION_TABLE but does not provide an instance,
+ simply a type declaration. This is currently the only way to declare an
+ internal transition table with eUML. For example:</para>
+ <programlisting>BOOST_MSM_EUML_DECLARE_STATE((Open_Entry,Open_Exit),Open_def)
+struct Open_impl : public Open_def
+{
+ BOOST_MSM_EUML_DECLARE_INTERNAL_TRANSITION_TABLE((
+ open_close [internal_guard1] / internal_action1 ,
+ open_close [internal_guard2] / internal_action2
+ ))
+}; </programlisting>
+ </refsect3>
+ </refsect2>
+ </refsect1>
+ </refentry>
+ </part>
+</book>
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk