From caa5bce0e2261ea31127d9ffa80ff73d6af8bc07 Mon Sep 17 00:00:00 2001 From: Christophe Henry Date: Fri, 8 Oct 2010 21:19:25 +0000 Subject: [PATCH] merged revisions 63705-65842 [SVN r65845] --- doc/HTML/ch01.html | 2 +- doc/HTML/ch02.html | 2 +- doc/HTML/ch02s02.html | 2 +- doc/HTML/ch02s03.html | 2 +- doc/HTML/ch03.html | 8 +- doc/HTML/ch03s02.html | 311 ++----- doc/HTML/ch03s03.html | 207 +---- doc/HTML/ch03s04.html | 148 ++-- doc/HTML/ch03s05.html | 88 +- doc/HTML/ch04.html | 4 +- doc/HTML/ch04s02.html | 2 +- doc/HTML/ch04s03.html | 6 +- doc/HTML/ch04s04.html | 10 +- doc/HTML/ch04s05.html | 2 +- doc/HTML/ch05.html | 2 +- doc/HTML/ch06.html | 4 +- doc/HTML/ch06s02.html | 4 +- doc/HTML/ch06s03.html | 2 +- doc/HTML/ch06s04.html | 2 +- doc/HTML/ch07.html | 2 +- doc/HTML/ch07s02.html | 2 +- doc/HTML/ch08.html | 12 +- doc/HTML/ch08s02.html | 9 + doc/HTML/ch09.html | 4 +- doc/HTML/ch10.html | 20 +- doc/HTML/examples/Serialize.cpp | 248 ++++++ .../examples/SerializeCompositeAndHistory.cpp | 266 ++++++ doc/HTML/index.html | 16 +- doc/HTML/pr01.html | 4 +- doc/HTML/pt01.html | 14 +- doc/HTML/pt02.html | 4 +- doc/HTML/re01.html | 4 +- doc/HTML/re02.html | 76 +- doc/HTML/re03.html | 282 +++--- doc/PDF/examples/Serialize.cpp | 248 ++++++ .../examples/SerializeCompositeAndHistory.cpp | 266 ++++++ doc/PDF/msm.pdf | Bin 1116500 -> 1075483 bytes doc/src/msm.xml | 816 +++++------------- test/Jamfile.v2 | 4 + test/Serialize.cpp | 309 +++++++ test/SerializeSimpleEuml.cpp | 214 +++++ test/SerializeWithHistory.cpp | 365 ++++++++ 42 files changed, 2600 insertions(+), 1393 deletions(-) create mode 100644 doc/HTML/ch08s02.html create mode 100644 doc/HTML/examples/Serialize.cpp create mode 100644 doc/HTML/examples/SerializeCompositeAndHistory.cpp create mode 100644 doc/PDF/examples/Serialize.cpp create mode 100644 doc/PDF/examples/SerializeCompositeAndHistory.cpp create mode 100644 test/Serialize.cpp create mode 100644 test/SerializeSimpleEuml.cpp create mode 100644 test/SerializeWithHistory.cpp diff --git a/doc/HTML/ch01.html b/doc/HTML/ch01.html index 56a73d5..ac944f3 100644 --- a/doc/HTML/ch01.html +++ b/doc/HTML/ch01.html @@ -1,6 +1,6 @@ - Chapter 1. Founding idea

Chapter 1. Founding idea

Let's start with an example taken from the C++ Template Metaprogramming + Chapter 1. Founding idea

Chapter 1. Founding idea

Let's start with an example taken from the C++ Template Metaprogramming book:

class player : public state_machine<player>

{

// The list of FSM states enum states { Empty, Open, Stopped, Playing, Paused , initial_state = Empty };

// transition actions void start_playback(play const&) { std::cout diff --git a/doc/HTML/ch02.html b/doc/HTML/ch02.html index ab38f5c..83d8967 100644 --- a/doc/HTML/ch02.html +++ b/doc/HTML/ch02.html @@ -1,6 +1,6 @@ - Chapter 2. UML Short Guide

Chapter 2. UML Short Guide

Table of Contents

What are state machines?
Concepts
State machine, state, transition, event
Submachines, orthogonal regions, pseudostates
+ Chapter 2. UML Short Guide

Chapter 2. UML Short Guide

What are state machines?

State machines are the description of a thing's lifeline. They describe the diff --git a/doc/HTML/ch02s02.html b/doc/HTML/ch02s02.html index 98bdb0a..4e4e1fa 100644 --- a/doc/HTML/ch02s02.html +++ b/doc/HTML/ch02s02.html @@ -1,6 +1,6 @@ - Concepts

Concepts

Thinking in terms of state machines is a bit surprising at first, so let us + Concepts

Concepts

Thinking in terms of state machines is a bit surprising at first, so let us have a quick glance at the concepts.

State machine, state, transition, event

A state machine is a concrete model describing the behavior of a system. It is composed of a finite number of states and transitions.

A simple state has no sub states. It can have data, entry and exit diff --git a/doc/HTML/ch02s03.html b/doc/HTML/ch02s03.html index b268dcb..f3ed042 100644 --- a/doc/HTML/ch02s03.html +++ b/doc/HTML/ch02s03.html @@ -1,6 +1,6 @@ - State machine glossary

State machine glossary

+ State machine glossary

State machine glossary

  • state machine: the life cycle of a thing. It is made of states, regions, transitions and processes incoming events.

  • state: a stage in the life cycle of a state machine. A state (like a submachine) can have an entry and exit behaviors.

  • event: an incident provoking (or not) a reaction of the state diff --git a/doc/HTML/ch03.html b/doc/HTML/ch03.html index b0f853e..8bfc1a3 100644 --- a/doc/HTML/ch03.html +++ b/doc/HTML/ch03.html @@ -1,10 +1,10 @@ - Chapter 3. Tutorial

    Chapter 3. Tutorial

    Table of Contents

    Design
    Basic front-end
    A simple example
    Transition table
    Defining states with entry/exit actions
    Defining a simple state machine
    Defining a submachine
    Orthogonal regions, terminate state, event deferring
    History
    Completion (anonymous) transitions
    Internal transitions
    more row types
    Explicit entry / entry and exit pseudo-state / fork
    Flags
    Event Hierarchy
    Customizing a state machine / Getting more speed
    Choosing the initial event
    Containing state machine (deprecated)
    Functor front-end
    Transition table
    Defining states with entry/exit actions
    Defining a simple state machine
    Anonymous transitions
    Internal - transitions
    eUML (experimental)
    Transition table
    Defining events, actions and states with entry/exit actions
    Defining a simple state machine
    Defining a submachine
    - Attributes / Function call
    Orthogonal regions, flags, event deferring
    + Chapter 3. Tutorial

    Chapter 3. Tutorial

    Table of Contents

    Design
    Basic front-end
    A simple example
    Transition table
    Defining states with entry/exit actions
    Defining a simple state machine
    Defining a submachine
    Orthogonal regions, terminate state, event deferring
    History
    Completion (anonymous) transitions
    Internal transitions
    more row types
    Explicit entry / entry and exit pseudo-state / fork
    Flags
    Event Hierarchy
    Customizing a state machine / Getting more speed
    Choosing the initial event
    Containing state machine (deprecated)
    Functor front-end
    Transition table
    Defining states with entry/exit actions
    Defining a simple state machine
    Anonymous transitions
    Internal + transitions
    eUML (experimental)
    Transition table
    Defining events, actions and states with entry/exit actions
    Defining a simple state machine
    Defining a submachine
    + Attributes / Function call
    Orthogonal regions, flags, event deferring
    Customizing a state machine / Getting - more speed
    Completion / Anonymous transitions
    Internal transitions
    Other state types
    Helper functions
    Phoenix-like STL support
    Back-end
    Creation
    Starting a state machine
    Event dispatching
    Active state(s)
    Base state type
    Visitor
    Flags
    Getting a state
    State machine constructor with arguments
    Trading run-time speed for + more speed
    Completion / Anonymous transitions
    Internal transitions
    Other state types
    Helper functions
    Phoenix-like STL support
    Back-end
    Creation
    Starting a state machine
    Event dispatching
    Active state(s)
    Serialization
    Base state type
    Visitor
    Flags
    Getting a state
    State machine constructor with arguments
    Trading run-time speed for better compile-time / multi-TU compilation

    Design

    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 diff --git a/doc/HTML/ch03s02.html b/doc/HTML/ch03s02.html index fdbd16e..1d03c74 100644 --- a/doc/HTML/ch03s02.html +++ b/doc/HTML/ch03s02.html @@ -1,183 +1,36 @@ - Basic front-end

    Basic front-end

    This is the historical front-end, inherited from the MPL book. It provides a + Basic front-end

    Basic front-end

    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.

    A simple example

    Let us have a look at a state machine diagram of the founding example:

    We are now going to build it with MSM's basic front-end. An implementation is also provided.

    Transition table

    As previously stated, MSM is based on the transition table, so let us - define one:

    struct transition_table : mpl::vector<

    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //StartEventNextActionGuard
    //+---------+-------------+---------+---------------------+----------------------+
    a_row <Stopped ,play,Playing,&player_::start_playback >,
    a_row <Stopped ,open_close,Open,&player_::open_drawer >,
    _row <Stopped ,stop,Stopped >,
    //+----------------------+---------+---------------------+----------------------+
    a_row <Open ,open_close ,Empty ,&player_::close_drawer >,
    //+---------+-------------+---------+---------------------+----------------------+
    a_row <Empty ,open_close ,Open ,&player_::open_drawer >,
    row <Empty ,cd_detected ,Stopped ,&player_::store_cd_info ,&player_::good_disk_format>,
    row <Empty ,cd_detected ,Playing ,&player_::store_cd_info ,&player_::auto_start>,
    //+---------+-------------+---------+---------------------+----------------------+
    a_row <Playing ,stop ,Stopped ,&player_::stop_playback >,
    a_row <Playing ,pause ,Paused ,&player_::pause_playback >,
    a_row <Playing ,open_close ,Open ,&player_::stop_and_open >,
    //+---------+-------------+---------+---------------------+----------------------+
    a_row < Paused ,end_pause ,Playing ,&player_::resume_playback >,
    a_row < Paused ,stop ,Stopped ,&player_::stop_playback >,
    a_row < Paused ,open_close ,Open ,&player_::stop_and_open >
    //+---------+-------------+---------+---------------------+----------------------+
    > {};

    -

    You will notice that this is almost exactly our founding example. The only + define one:

     
    +struct transition_table : mpl::vector<
    +//    Start     Event        Target      Action                      Guard 
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +a_row< Stopped , play       ,  Playing  , &player_::start_playback                               >,
    +a_row< Stopped , open_close ,  Open     , &player_::open_drawer                                  >,
    + _row< Stopped , stop       ,  Stopped                                                           >,
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +a_row< Open    , open_close ,  Empty    , &player_::close_drawer                                 >,
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +a_row< Empty   , open_close ,  Open     , &player_::open_drawer                                  >,
    +  row< Empty   , cd_detected,  Stopped  , &player_::store_cd_info   , &player_::good_disk_format >,
    +  row< Empty   , cd_detected,  Playing  , &player_::store_cd_info   , &player_::auto_start       >,
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +a_row< Playing , stop       ,  Stopped  , &player_::stop_playback                                >,
    +a_row< Playing , pause      ,  Paused   , &player_::pause_playback                               >,
    +a_row< Playing , open_close ,  Open     , &player_::stop_and_open                                >,
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +a_row< Paused  , end_pause  ,  Playing  , &player_::resume_playback                              >,
    +a_row< Paused  , stop       ,  Stopped  , &player_::stop_playback                                >,
    +a_row< Paused  , open_close ,  Open     , &player_::stop_and_open                                >
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +> {};
    +                        

    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:

    • row takes 5 arguments: start state, event, target @@ -194,7 +47,7 @@ #define BOOST_MPL_LIMIT_VECTOR_SIZE 30 //or whatever you need #define BOOST_MPL_LIMIT_MAP_SIZE 30 //or whatever you need

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

    Defining states with entry/exit actions

    While states were enums in the MPL book, they now are classes, which + to the MPL (luckily, this is not very complicated).

    Defining states with entry/exit actions

    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 @@ -212,7 +65,7 @@ struct Empty : public msm::front::state<> 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.

    Defining a simple state machine

    Declaring a state machine is straightforward and is done with a high + sections.

    Defining a simple state machine

    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:

    struct player_ : public msm::front::state_machine_def<player_>{
                                 /* see below */}

    This declares a state machine using the basic front-end. We now declare @@ -248,85 +101,33 @@ void no_transition(Event const& e, Fsm& ,int state){...}

    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 back-end part. After a call - to start, the state machine is ready to process events.

    Defining a submachine

    We now want to extend our last state machine by making the Playing state a + to start, the state machine is ready to process events.

    Defining a submachine

    We now want to extend our last state machine by making the Playing state a state machine itself (a submachine).

    Again, an example is also provided.

    A submachine really is a state machine itself, so we declare Playing as such, choosing a front-end and a back-end:

    struct Playing_ : public msm::front::state_machine_def<Playing_>{...} 
     typedef msm::back::state_machine<Playing_> Playing;

    Like for any state machine, one also needs a transition table and an - initial state:

    struct transition_table : mpl::vector<

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //StartEventNextActionGuard
    //+---------+-------------+---------+------------------------------+----------------------+
    a_row <Song1 ,NextSong,Song2,&Playing_::start_next_song >,
    a_row <Song2 ,PreviousSong,Song1,&Playing_::start_prev_song >,
    a_row <Song2 ,NextSong,Song3,&Playing_::start_next_song >,
    a_row <Song3 ,PreviousSong ,Song2 ,&Playing_::start_prev_song >
    //+---------+-------------+---------+------------------------------+----------------------+
    > {};

    + initial state:

    +

     
    +struct transition_table : mpl::vector<
    +//    Start    Event    Target    Action                      Guard 
    +//   +--------+---------+--------+---------------------------+------+ 
    +a_row< Song1  , NextSong, Song2  , &Playing_::start_next_song        >,
    +a_row< Song2  , NextSong, Song1  , &Playing_::start_prev_song        >,
    +a_row< Song2  , NextSong, Song3  , &Playing_::start_next_song        >,
    +a_row< Song3  , NextSong, Song2  , &Playing_::start_prev_song        >
    +//   +--------+---------+--------+---------------------------+------+ 
    +> {};
    +                        

    +

    typedef Song1 initial_state; 

    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.

    Orthogonal regions, terminate state, event deferring

    It is a very common problem in many state machines to have to handle + submachine or sometimes as an independent state machine.

    Orthogonal regions, terminate state, event deferring

    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 @@ -402,7 +203,7 @@ typedef msm::back::state_machine<Playing_> Playing;

    (condition1) defer play event":

    Row   < Empty , play , none    , Defer , condition1   >,
     g_row < Empty , play , Playing , &player_::condition2 >

    -

    Please have a look at this possible implementation.

    History

    UML defines two types of history, Shallow History and Deep History. In the +

    Please have a look at this possible implementation.

    History

    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 @@ -449,7 +250,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

    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 example is also provided.

    Completion (anonymous) transitions

    The following diagram shows an + Deep History for itself. An example is also provided.

    Completion (anonymous) transitions

    The following diagram shows an example making use of this feature:

    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 @@ -476,7 +277,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

    for example:

    row < State3 , none , State4 , &p::State3ToState4 , &p::always_true >

    An implementation - of the state machine diagram is also provided.

    Internal transitions

    Internal transitions are transitions executing in the scope of the active + of the state machine diagram is also provided.

    Internal transitions

    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 @@ -541,7 +342,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

    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.

    more row types

    It is also possible to write transitions using actions and guards not just + with eUML, the same is also possible with any front-end.

    more row types

    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, row2. @@ -558,7 +359,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

    sections.

    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 example of these new - rows is also provided.

    Explicit entry / entry and exit pseudo-state / fork

    MSM (almost) fully supports these features, described in the small UML tutorial. Almost because + rows is also provided.

    Explicit entry / entry and exit pseudo-state / fork

    MSM (almost) fully supports these features, described in the small UML tutorial. Almost because there are currently two limitations:

    • it is only possible to explicitly enter a sub- state of the target but not a sub-sub state.

    • it is not possible to explicitly exit. Exit points must be used.

    Let us see a concrete example:

    We find in this diagram:

    • A “normal” activation of SubFsm2, triggered by event1. In each @@ -578,7 +379,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

      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.

    The example is also fully implemented.

    This sounds complicated but the syntax is simple.

    Explicit entry

    First, to define that a state is an explicit entry, you have to make + detected and no_transition called.

The example is also fully implemented.

This sounds complicated but the syntax is simple.

Explicit entry

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

@@ -610,7 +411,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

Note (also valid for forks): At the moment, it is not possible to use a submachine as the target of an explicit entry. Please use entry pseudo states for an almost identical - effect.

Fork

Need a fork instead of an explicit entry? As a fork is an explicit + effect.

Fork

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:

@@ -623,7 +424,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

correct):

struct SubState2b : public msm::front::state<> , 
                     public msm::front::explicit_entry<1>

-

Entry pseudo states

To define an entry pseudo state, you need derive from the +

Entry pseudo states

To define an entry pseudo state, you need derive from the corresponding class and give the region id:

struct PseudoEntry1 : public msm::front::entry_pseudo_state<0>

And add the corresponding transition in the top-level state machine's @@ -633,7 +434,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

defines an entry point as a connection between two transitions), for example this time with an action method:

_row < PseudoEntry1, Event4, SubState3,&SubFsm2_::entry_action >

-

Exit pseudo states

And finally, exit pseudo states are to be used almost the same way, +

Exit pseudo states

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):

struct PseudoExit1 : public exit_pseudo_state<event6>

@@ -664,7 +465,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

template <class Event> event6(Event const&){} }; //convertible from any event

-

Flags

This tutorial is devoted to a +

Flags

This tutorial 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 @@ -696,7 +497,7 @@ g_row < Empty , play , Playing , &player_::condition2 >

all of the active states are flagged for the state to be active. You can also AND the active states:

if (p.is_flag_active<CDLoaded,player::Flag_AND>()) ...

-

The following diagram displays the flag situation in the tutorial.

Event Hierarchy

There are cases where one needs transitions based on categories of events. +

The following diagram displays the flag situation in the tutorial.

Event Hierarchy

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 @@ -709,7 +510,7 @@ struct char_0 : public digit {};

And to the same for other digits, we c and this will cause a transition with "digit" as trigger to be taken.

An example 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).

Customizing a state machine / Getting more speed

MSM is offering many UML features at a high-speed, but sometimes, you just + very good (in this case even better).

Customizing a state machine / Getting more speed

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:

  • checking for terminate/interrupt states

  • handling the message queue (for entry/exit/transition actions generating themselves events)

  • handling deferred events

  • catching exceptions (or not)

  • handling the state switching and action calls

Of these tasks, only the last one is absolutely necessary to @@ -735,7 +536,7 @@ struct char_0 : public digit {};

And to the same for other digits, we c };

Important note: As exit pseudo states are using the message queue to forward events out of a submachine, the no_message_queue option cannot be used with state machines - containing an exit pseudo state.

Choosing the initial event

A state machine is started using the start method. This + containing an exit pseudo state.

Choosing the initial event

A state machine is started using the start 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 @@ -747,7 +548,7 @@ struct char_0 : public digit {};

And to the same for other digits, we c struct player_ : public msm::front::state_machine_def<player_>{ ... typedef my_initial_event initial_event; -};

Containing state machine (deprecated)

This feature is still supported in MSM for backward compatibility but made +};

Containing state machine (deprecated)

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.

All of the states defined in the state machine are created upon state diff --git a/doc/HTML/ch03s03.html b/doc/HTML/ch03s03.html index 8f20b5b..91be570 100644 --- a/doc/HTML/ch03s03.html +++ b/doc/HTML/ch03s03.html @@ -1,6 +1,6 @@ - Functor front-end

Functor front-end

The functor front-end is the preferred front-end at the moment. It is more + Functor front-end

Functor front-end

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 eUML, it also comes with a good deal of predefined actions. Actually, eUML generates a functor front-end through @@ -11,178 +11,31 @@ means syntactic noise and more to learn.

  • Function pointers are weird in C++.

  • The action/guard signature is limited and does not allow for more variations of parameters (source state, target state, current state machine, etc.)

  • It is not easy to reuse action code from a state machine to - another.

  • Transition table

    We can change the definition of the simple tutorial's transition table - to:

    -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //StartEventNextActionGuard
    //+---------+-------------+---------+---------------------+----------------------+
    Row <Stopped ,play,Playing,start_playback >,
    Row <Stopped ,open_close,Open,open_drawer, none>,
    Row <Stopped ,stop,Stopped, none>,
    //+----------------------+---------+---------------------+----------------------+
    Row <Open ,open_close ,Empty ,close_drawer, none>,
    //+---------+-------------+---------+---------------------+----------------------+
    Row <Empty ,open_close ,Open ,open_drawer >,
    Row <Empty ,cd_detected ,Stopped ,store_cd_info ,good_disk_format>,
    g_row <Empty ,cd_detected ,Playing ,store_cd_info ,&player_::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>
    //+---------+-------------+---------+---------------------+----------------------+
    > {};

    -

    Transitions are now of type "Row" with exactly 5 template arguments: + another.

    Transition table

    We can change the definition of the simple tutorial's transition table + to:

     
    +struct transition_table : mpl::vector<
    +//    Start     Event        Target      Action                      Guard 
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +Row  < Stopped , play       ,  Playing  , start_playback            , none                       >,
    +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             , good_disk_format           >,
    +g_row< Empty   , cd_detected,  Playing  , &player_::store_cd_info   , &player_::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                       >
    +//   +---------+------------+-----------+---------------------------+----------------------------+ 
    +> {};
    +                        

    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, @@ -213,7 +66,7 @@ can achieve this using And_ and Or_ functors:

    And_<good_disk_format,Or_< some_condition , some_other_condition> >

    It even starts looking like functional programming. MSM ships with functors for - operators, state machine usage, STL algorithms or container methods.

    Defining states with entry/exit actions

    You probably noticed that we just showed a different transition table and + operators, state machine usage, STL algorithms or container methods.

    Defining states with entry/exit actions

    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 @@ -236,16 +89,16 @@ struct Empty : public msm::front::euml::func_state<Empty_Entry,Empty_Exit> rewritten.

    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.

    Defining a simple state machine

    Like states, state machines can be defined using the previous front-end, + programming.

    Defining a simple state machine

    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 this - example.

    Anonymous transitions

    Anonymous (completion) transitions are transitions without a named event. + example.

    Anonymous transitions

    Anonymous (completion) transitions are transitions without a named event. We saw how this front-end uses none when no action or guard is required. We can also use none instead of an event to mark an anonymous transition. For example, the following transition makes an immediate transition from State1 to State2:

    Row < State1 , none , State2 >

    The following transition does the same but calling an action in the - process:

    Row < State1 , none , State2 , State1ToState2, none >

    The following diagram shows an example and its implementation:

    Internal + process:

    Row < State1 , none , State2 , State1ToState2, none >

    The following diagram shows an example and its implementation:

    Internal transitions

    The following example uses internal transitions with the functor front-end. As for the simple standard front-end, both methods of defining internal transitions are supported:

    • providing a Row in the state machine's transition diff --git a/doc/HTML/ch03s04.html b/doc/HTML/ch03s04.html index 4538182..996e12b 100644 --- a/doc/HTML/ch03s04.html +++ b/doc/HTML/ch03s04.html @@ -1,11 +1,8 @@ - eUML (experimental)

      eUML (experimental)

      Important note: 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.

      The previous front-ends are simple to write but still force an amount of + eUML (experimental)

      eUML (experimental)

      Important note: eUML requires a compiler + supporting Boost.Typeof. More generally, eUML has experimental status because + most compilers will start crashing when a state machine becomes too big.

      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 @@ -22,80 +19,27 @@

      #include <msm/front/euml/euml.hpp>

      To add STL support (at possible cost of longer compilation times), include:

      #include <msm/front/euml/stl.hpp>

      -

      eUML is defined in the namespace msm::front::euml.

      Transition table

      A transition can be defined using eUML as:

      +

      eUML is defined in the namespace msm::front::euml.

      Transition table

      A transition can be defined using eUML as:

      source + event [guard] / action == target

      or as

      target == source + event [guard] / action

      The first version looks like a drawn transition in a diagram, the second - one seems natural to a C++ developer.

      The simple transition table written with the previous front-end can now be - written as:

      -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      BOOST_MSM_EUML_TRANSITION_TABLE((
      Stopped +play [DummyGuard] / (TestFct,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] / store_cd_info == Stopped
      ),transition_table)

      -

      Or, using the alternative notation, it can be:

      -

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      BOOST_MSM_EUML_TRANSITION_TABLE((
      Playing == Stopped +play [DummyGuard] / (TestFct,start_playback)
      Open ==Stopped +open_close/ open_drawer
      Stopped ==Stopped +stop
      Empty ==Open +open_close / close_drawer
      Open ==Empty +open_close / open_drawer
      Stopped ==Empty +cd_detected [good_disk_format] / store_cd_info
      ),transition_table)

      -

      The transition table now looks like a list of (readable) rules with little + one seems natural to a C++ developer.

      The simple transition table written with the functor front-end can now be + written as:

      BOOST_MSM_EUML_TRANSITION_TABLE(( 
      +Stopped + play [some_guard] / (some_action , 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] / store_cd_info      == Stopped
      +),transition_table)                       

      Or, using the alternative notation, it can be:

      BOOST_MSM_EUML_TRANSITION_TABLE(( 
      +Playing  == Stopped + play [some_guard] / (some_action , start_playback) ,
      +Open     == Stopped + open_close/ open_drawer                            ,
      +Stopped  == Stopped + stop                                               ,
      +Empty    == Open    + open_close / close_drawer                          ,
      +Open     == Empty   + open_close / open_drawer                           ,
      +Stopped  == Empty   + cd_detected [good_disk_format] / store_cd_info
      +),transition_table)           

      The transition table now looks like a list of (readable) rules with little noise.

      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_) @@ -111,7 +55,7 @@ [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.

      Defining events, actions and states with entry/exit actions

      Events

      Events must be proto-enabled. To achieve this, they must inherit from + without any syntactic noise at all.

      Defining events, actions and states with entry/exit actions

      Events

      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:

      BOOST_MSM_EUML_EVENT(play)

      @@ -126,7 +70,7 @@ fsm.process_event(play()); or do we have to write: fsm.process_event(play);

      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.

      Actions

      Actions (returning void) and guards (returning a bool) are defined + event on the fly.

      Actions

      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:

      BOOST_MSM_EUML_ACTION(some_condition)
      @@ -144,7 +88,20 @@
       {
           template <class Evt,class Fsm,class State>
           void operator()(Evt const& ,Fsm& ,State& ) { ... }                           
      -}; 

      States

      There is also a macro for states. This macro has 2 arguments, first + };

      It is also possible to reuse the functors from the functor front-end. + The syntax is however slightly less comfortable as we need to pretend + creating one on the fly for typeof. For example:

      struct start_playback 
      +{
      +        template <class Fsm,class Evt,class SourceState,class TargetState>
      +        void operator()(Evt const& ,Fsm&,SourceState& ,TargetState& )
      +        {
      +         ...            
      +        }
      +};
      +BOOST_MSM_EUML_TRANSITION_TABLE((
      +Playing   == Stopped  + play        / start_playback() ,
      +...
      +),transition_table)

      States

      There is also a macro for states. This macro has 2 arguments, first the expression defining the state, then the state (instance) name:

      BOOST_MSM_EUML_STATE((),Paused)

      This defines a simple state without entry or exit action. You can provide in the expression parameter the state behaviors (entry and exit) @@ -185,7 +142,7 @@ Empty_impl const Empty;

      Notice also that we defined a method named activ 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:

      Empty == Open + open_close / (close_drawer,activate_empty_(target_))

      Defining a simple state machine

      You can reuse the state machine definition method from the standard + now use this inside a transition:

      Empty == Open + open_close / (close_drawer,activate_empty_(target_))

      Defining a simple state machine

      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). @@ -209,22 +166,13 @@ Empty_impl const Empty;

      Notice also that we defined a method named activ capabilities (no message queue / no exception catching) are added and a non-default base state (see the back-end description) is defined.

    For example, a minimum state machine could be defined - as:

    -

    - - - - - - - -
    BOOST_MSM_EUML_TRANSITION_TABLE((
    ),transition_table)

    -

    BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,init_ << Empty ),
    +                        as:

    BOOST_MSM_EUML_TRANSITION_TABLE(( 
    +),transition_table)                       
    BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,init_ << Empty ),
                                          player_)

    Please have a look at the player tutorial written using eUML's first and second 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 attribute - syntax.

    Defining a submachine

    Defining a submachine (see tutorial) with + syntax.

    Defining a submachine

    Defining a submachine (see tutorial) 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 @@ -235,7 +183,7 @@ Empty_impl const Empty;

    Notice also that we defined a method named activ machine, for example:

    BOOST_MSM_EUML_DECLARE_STATE_MACHINE(...,Playing_)
     typedef msm::back::state_machine<Playing_> Playing_type;
     Playing_type const Playing;

    We can now use this instance inside the transition table of the containing - state machine:

    Paused == Playing + pause / pause_playback

    + state machine:

    Paused == Playing + pause / pause_playback

    Attributes / Function call

    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 @@ -289,7 +237,7 @@ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)

    This declares two This method could also have an (or several) argument(s), for example the event, we could then call activate_empty_(target_ , event_).

    More examples can be found in the terrible compiler stress test, the timer example or in the iPodSearch with eUML - (for String_ and more).

    Orthogonal regions, flags, event deferring

    Defining orthogonal regions really means providing more initial states. To + (for String_ and more).

    Orthogonal regions, flags, event deferring

    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 :

    BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
                                          init_ << Empty << AllOk ),
    @@ -341,7 +289,7 @@ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)

    This declares two attributes_ << no_attributes_, configure_<< deferred_events ), player_)

    A tutorial - illustrates this possibility.

    + illustrates this possibility.

    Customizing a state machine / Getting more speed

    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:

    • configure_ << no_exception: disables @@ -353,7 +301,7 @@ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)

      This declares two with eUML does this for the best performance.

      Important note: As exit pseudo states are using the message queue to forward events out of a submachine, the no_message_queue option cannot be used with state machines - containing an exit pseudo state.

    Completion / Anonymous transitions

    Anonymous transitions (See UML + containing an exit pseudo state.

    Completion / Anonymous transitions

    Anonymous transitions (See UML tutorial) 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 @@ -361,7 +309,7 @@ BOOST_MSM_EUML_DECLARE_ATTRIBUTE(DiskTypeEnum,cd_type)

    This declares two example:

    State3 == State4 [always_true] / State3ToState4
     State4 [always_true] / State3ToState4 == State3

    Please have a look at this example, which implements the previously - defined state machine with eUML.

    Internal transitions

    Like both other front-ends, eUML supports two ways of defining internal transitions:

    • in the state machine's transition table. In this case, you + defined state machine with eUML.

    Internal transitions

    Like both other front-ends, eUML supports two ways of defining internal transitions:

    • 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 @@ -382,7 +330,7 @@ struct Open_impl : public Open_def 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).

    Other state types

    We saw the build_state + instead of O(number of regions).

    Other state types

    We saw the build_state function, which creates a simple state. Likewise, eUML provides other state-building macros for other types of states:

    • BOOST_MSM_EUML_TERMINATE_STATE takes the same arguments as BOOST_MSM_EUML_STATE and defines, well, a terminate @@ -422,7 +370,7 @@ struct Open_impl : public Open_def

      entry_pt_(SubFsm2,PseudoEntry1) == State1 + event4

      For exit points, it is again the same syntax except that exit points are used as source of the transition:

      State2 == exit_pt_(SubFsm2,PseudoExit1) + event6 

      The entry tutorial - is also available with eUML.

    Helper functions

    We saw a few helpers but there are more, so let us have a more complete description:

    • event_ : used inside any action, the event triggering the + is also available with eUML.

    Helper functions

    We saw a few helpers but there are more, so let us have a more complete description:

    • event_ : used inside any action, the event triggering the transition

    • state_: used inside entry and exit actions, the entered / exited state

    • source_: used inside a transition action, the source state

    • target_: used inside a transition action, the target @@ -459,7 +407,7 @@ struct Open_impl : public Open_def 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, except, for the - moment, with the while_, if_then_, if_then_else_ functions.

    Phoenix-like STL support

    eUML supports most C++ operators (except address-of). For example it is + moment, with the while_, if_then_, if_then_else_ functions.

    Phoenix-like STL support

    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 diff --git a/doc/HTML/ch03s05.html b/doc/HTML/ch03s05.html index ce4d4ce..f795e1a 100644 --- a/doc/HTML/ch03s05.html +++ b/doc/HTML/ch03s05.html @@ -1,6 +1,6 @@ - Back-end

    Back-end

    There is, at the moment, one back-end. This back-end contains the library + Back-end

    Back-end

    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 @@ -8,18 +8,18 @@ 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.

    Creation

    MSM being divided between front and back-end, one needs to first define a + run-to-completion algorithm.

    Creation

    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:

    typedef msm::back::state_machine<my_front_end> my_fsm;

    We now have a fully functional state machine type. The next sections will - describe what can be done with it.

    Starting a state machine

    The start method starts the state machine, meaning it will + describe what can be done with it.

    Starting a state machine

    The start 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 iPodSearch example uses this possibility.

    Event dispatching

    The main reason to exist for a state machine is to dispatch events. For + the algorithm run once. The iPodSearch example uses this possibility.

    Event dispatching

    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 @@ -30,14 +30,80 @@ an event of type some_event, you can simply create one on the fly or instantiate if before processing:

    my_fsm fsm; fsm.process_event(some_event());
     some_event e1; fsm.process_event(e1)

    Creating an event on the fly will be optimized by the compiler so the - performance will not degrade.

    Active state(s)

    The backend also offers a way to know which state is active, though you + performance will not degrade.

    Active state(s)

    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, internal transitions or visitors 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 internals section to - know how state ids are generated.

    Base state type

    Sometimes, one needs to customize states to avoid repetition and provide a + know how state ids are generated.

    Serialization

    A common need is the ability to save a state machine and restore it at a + different time. MSM supports this feature for the basic and functor + front-ends, and in a more limited manner for eUML. MSM supports + boost::serialization out of the box (by offering a serialize + function). Actually, for basic serialization, you need not do much, a MSM + state machine is serializable almost like any other type. Without any + special work, you can make a state machine remember its state, for + example:

    +

    MyFsm fsm;
    +// write to archive
    +std::ofstream ofs("fsm.txt");
    +// save fsm to archive
    +{
    +    boost::archive::text_oarchive oa(ofs);
    +    // write class instance to archive
    +    oa << fsm;
    +}                                                  

    +

    Loading back is very similar:

    +

    MyFsm fsm;
    +{
    +    // create and open an archive for input
    +    std::ifstream ifs("fsm.txt");
    +    boost::archive::text_iarchive ia(ifs);
    +    // read class state from archive
    +    ia >> fsm;
    +}                                          

    +

    This will (de)serialize the state machine itself but not the concrete + states' data. This can be done on a per-state basis to reduce the amount of + typing necessary. To allow serialization of a concrete state, provide a + do_serialize typedef and implement the serialize function:

    +

    struct Empty : public msm::front::state<> 
    +{
    +    // we want Empty to be serialized. First provide the typedef
    +    typedef int do_serialize;
    +    // then implement serialize
    +    template<class Archive>
    +    void serialize(Archive & ar, const unsigned int /* version */)
    +    {
    +        ar & some_dummy_data;
    +    }
    +    Empty():some_dummy_data(0){}           
    +    int some_dummy_data;
    +};                        

    +

    You can also serialize data contained in the front-end class. Again, you + need to provide the typedef and implement serialize:

    +

    struct player_ : public msm::front::state_machine_def<player_>
    +{
    +    //we might want to serialize some data contained by the front-end
    +    int front_end_data;
    +    player_():front_end_data(0){}
    +    // to achieve this, provide the typedef
    +    typedef int do_serialize;
    +    // and implement serialize
    +    template<class Archive>
    +    void serialize(Archive & ar, const unsigned int )
    +    {
    +        ar & front_end_data;
    +    }  
    +...
    +};                                               

    +

    The saving of the back-end data (the current state(s)) is valid for all + front-ends, so a front-end written using eUML can be serialized. However, to + serialize a concrete state, the macros like + BOOST_MSM_EUML_STATE cannot be used, so the state will have + to be implemented by directly inheriting from + front::euml::euml_state.

    This example shows a state machine which we serialize after processing an + event. The Empty state also has some data to serialize.

    Base state type

    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 @@ -60,7 +126,7 @@ some_event e1; fsm.process_event(e1)

    Creating an event on the fly will b

    struct player_ : public msm::front::state_machine<player_,my_base_state>             

    You can also ask for a state with a given id (which you might have gotten from current_state()) using const base_state* get_state_by_id(int id) const where base_state is the one you just defined. You can now - do something polymorphically.

    Visitor

    In some cases, having a pointer-to-base of the currently active states is + do something polymorphically.

    Visitor

    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!

    To achieve this goal, MSM provides its own variation of a visitor pattern @@ -99,18 +165,18 @@ struct my_visitable_state 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:

    SomeVisitor vis; sm.visit_current_states(boost::ref(vis));

    This example uses a - visiting function with 2 arguments.

    Flags

    Flags is a MSM-only concept, supported by all front-ends, which base + visiting function with 2 arguments.

    Flags

    Flags is a MSM-only concept, supported by all front-ends, which base themselves on the functions:

    template <class Flag> bool is_flag_active()
     template <class Flag,class BinaryOp> bool is_flag_active()

    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:

    my_fsm.is_flag_active<MyFlag>()
    -my_fsm.is_flag_active<MyFlag,my_fsm_type::Flag_OR>()

    Please refer to the front-ends sections for usage examples.

    Getting a state

    It is sometimes necessary to have the client code get access to the +my_fsm.is_flag_active<MyFlag,my_fsm_type::Flag_OR>()

    Please refer to the front-ends sections for usage examples.

    Getting a state

    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:

    player::Stopped* tempstate = p.get_state<player::Stopped*>();

    or

    player::Stopped& tempstate2 = p.get_state<player::Stopped&>();

    depending on your personal taste.

    State machine constructor with arguments

    You might want to define a state machine with a non-default constructor. + name, for example:

    player::Stopped* tempstate = p.get_state<player::Stopped*>();

    or

    player::Stopped& tempstate2 = p.get_state<player::Stopped&>();

    depending on your personal taste.

    State machine constructor with arguments

    You might want to define a state machine with a non-default constructor. For example, you might want to write:

    struct player_ : public msm::front::state_machine_def<player_> 
     { 
         player_(int some_value){…} 
    @@ -126,7 +192,7 @@ my_fsm.is_flag_active<MyFlag,my_fsm_type::Flag_OR>()

    Please refer typedef msm::back::state_machine<player_ > player; SomeType data; player p(boost::ref(data),3); -

    Trading run-time speed for +

    Trading run-time speed for better compile-time / multi-TU compilation

    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 diff --git a/doc/HTML/ch04.html b/doc/HTML/ch04.html index 3ca0b64..0a5c49e 100644 --- a/doc/HTML/ch04.html +++ b/doc/HTML/ch04.html @@ -1,6 +1,6 @@ - Chapter 4.  Performance / Compilers

    Chapter 4.  Performance / Compilers

    Tests were made on different PCs running Windows XP and Vista and compiled with + Chapter 4.  Performance / Compilers

    Chapter 4.  Performance / Compilers

    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 state machine with only simple states and as a state machine with a composite @@ -9,5 +9,5 @@ the simple one also with functors and with eUML. 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.

    Speed

    VC9:

    • The simple test completes 90 times faster with MSM than with + 64.

      Speed

      VC9:

      • The simple test completes 90 times faster with MSM than with Boost.Statechart

      • The composite test completes 25 times faster with MSM

      gcc 4.2.3 (Ubuntu 8.04 in VMWare, same PC):

      • The simple test completes 46 times faster with MSM

      • The composite test completes 19 times faster with Msm

    \ No newline at end of file diff --git a/doc/HTML/ch04s02.html b/doc/HTML/ch04s02.html index b1fa02a..6e55664 100644 --- a/doc/HTML/ch04s02.html +++ b/doc/HTML/ch04s02.html @@ -1,6 +1,6 @@ - Executable size

    Executable size

    There are some worries that MSM generates huge code. Is it true? The 2 + Executable size

    Executable size

    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. diff --git a/doc/HTML/ch04s03.html b/doc/HTML/ch04s03.html index 2ca1f80..a6175f0 100644 --- a/doc/HTML/ch04s03.html +++ b/doc/HTML/ch04s03.html @@ -1,9 +1,7 @@ - Supported compilers

    Supported compilers

    MSM was successfully tested with:

    • VC8 (please read further), VC9SP1, VC10 Beta 1 and 2

    • g++ 4.1 and higher

    • Green Hills Software MULTI for ARM v5.0.5 patch 4416 (Simple and - Composite tutorials)

    eUML will only work with:

    • VC8 (partly). You cannot, however use any overloaded function - (like splice) and compile times and RAM consumption explode

    • VC9SP1, VC10 Beta1-2

    • g++ 4.3 and higher (previous versions lack native typeof - support)

    VC8 and to some lesser extent VC9 suffer from a bug. Enabling the option + Supported compilers

    Supported compilers

    For a current status, have a look at the regression tests.

    MSM was successfully tested with:

    • VC8 (partly), VC9, VC10

    • g++ 4.0.1 and higher

    • Intel 10.1 and higher

    • Clang 2.9

    • Green Hills Software MULTI for ARM v5.0.5 patch 4416 (Simple and + Composite tutorials)

    • Partial support for IBM compiler

    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.

    \ No newline at end of file diff --git a/doc/HTML/ch04s04.html b/doc/HTML/ch04s04.html index 8eb48c4..823a489 100644 --- a/doc/HTML/ch04s04.html +++ b/doc/HTML/ch04s04.html @@ -1,15 +1,15 @@ - Limitations

    Limitations

    + Limitations

    Limitations

    • 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).

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

    • Need to overwrite the mpl::vector/list default-size-limit of 20 + your compile time on some compilers (VC9, VC10) 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.

    • 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

    \ No newline at end of file diff --git a/doc/HTML/ch04s05.html b/doc/HTML/ch04s05.html index 232b9f8..551ddf8 100644 --- a/doc/HTML/ch04s05.html +++ b/doc/HTML/ch04s05.html @@ -1,6 +1,6 @@ - Compilers corner

    Compilers corner

    Compilers are sometimes full of surprises and such strange errors happened in + Compilers corner

    Compilers corner

    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.

    VC8:

    template <class StateType>
     typename ::boost::enable_if<
    diff --git a/doc/HTML/ch05.html b/doc/HTML/ch05.html
    index 27986d7..dcff80f 100644
    --- a/doc/HTML/ch05.html
    +++ b/doc/HTML/ch05.html
    @@ -1,6 +1,6 @@
     
           
    -   Chapter 5. Questions & Answers

    Chapter 5. Questions & Answers

    Question: on_entry gets as argument, the + Chapter 5. Questions & Answers

    Chapter 5. Questions & Answers

    Question: 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)?

    Answer: To allow you to know that the state diff --git a/doc/HTML/ch06.html b/doc/HTML/ch06.html index 2698ee1..83d5b3c 100644 --- a/doc/HTML/ch06.html +++ b/doc/HTML/ch06.html @@ -1,9 +1,9 @@ - Chapter 6. Internals

    Chapter 6. Internals

    Table of Contents

    Backend: Run To Completion
    Frontend / Backend + Chapter 6. Internals

    Chapter 6. Internals

    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.

    Backend: Run To Completion

    The back-end implements the following run-to completion algorithm: