From 77c623d8b845b6fe5236140ed30bed6d6a9b71bd Mon Sep 17 00:00:00 2001 From: Christophe Henry Date: Mon, 10 Jan 2011 22:27:44 +0000 Subject: [PATCH] msm v2.20 [SVN r67936] --- doc/HTML/ch01.html | 2 +- doc/HTML/ch02.html | 2 +- doc/HTML/ch02s02.html | 2 +- doc/HTML/ch02s03.html | 2 +- doc/HTML/ch03.html | 11 +- doc/HTML/ch03s02.html | 98 ++++-- doc/HTML/ch03s03.html | 27 +- doc/HTML/ch03s04.html | 46 +-- doc/HTML/ch03s05.html | 69 ++++- doc/HTML/ch04.html | 4 +- doc/HTML/ch04s02.html | 2 +- doc/HTML/ch04s03.html | 2 +- doc/HTML/ch04s04.html | 2 +- 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 | 17 +- doc/HTML/ch08s02.html | 14 +- doc/HTML/ch08s03.html | 9 + doc/HTML/ch09.html | 4 +- doc/HTML/ch10.html | 20 +- .../examples/SimpleTutorialWithEumlTable.cpp | 158 ++++++++++ doc/HTML/examples/TestErrorOrthogonality.cpp | 119 ++++++++ doc/HTML/examples/iPod_distributed/iPod.cpp | 1 - doc/HTML/index.html | 17 +- doc/HTML/pr01.html | 4 +- doc/HTML/pt01.html | 15 +- doc/HTML/pt02.html | 4 +- doc/HTML/re01.html | 4 +- doc/HTML/re02.html | 76 ++--- doc/HTML/re03.html | 282 +++++++++--------- .../examples/SimpleTutorialWithEumlTable.cpp | 158 ++++++++++ doc/PDF/examples/TestErrorOrthogonality.cpp | 119 ++++++++ doc/PDF/examples/iPod_distributed/iPod.cpp | 1 - doc/PDF/msm.pdf | Bin 1077024 -> 1100732 bytes doc/src/msm.xml | 276 ++++++++++++++++- example/mpl_graph/Jamfile.v2 | 34 +++ example/mpl_graph/adjacency_list_graph.cpp | 82 +++++ example/mpl_graph/breadth_first_search.cpp | 211 +++++++++++++ example/mpl_graph/depth_first_search.cpp | 153 ++++++++++ example/mpl_graph/incidence_list_graph.cpp | 72 +++++ example/mpl_graph/msm_adaptor.cpp | 264 ++++++++++++++++ 47 files changed, 2082 insertions(+), 321 deletions(-) create mode 100644 doc/HTML/ch08s03.html create mode 100644 doc/HTML/examples/SimpleTutorialWithEumlTable.cpp create mode 100644 doc/HTML/examples/TestErrorOrthogonality.cpp create mode 100644 doc/PDF/examples/SimpleTutorialWithEumlTable.cpp create mode 100644 doc/PDF/examples/TestErrorOrthogonality.cpp create mode 100644 example/mpl_graph/Jamfile.v2 create mode 100755 example/mpl_graph/adjacency_list_graph.cpp create mode 100644 example/mpl_graph/breadth_first_search.cpp create mode 100644 example/mpl_graph/depth_first_search.cpp create mode 100755 example/mpl_graph/incidence_list_graph.cpp create mode 100644 example/mpl_graph/msm_adaptor.cpp diff --git a/doc/HTML/ch01.html b/doc/HTML/ch01.html index ac944f3..332648f 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 83d8967..7cf5bab 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 4e4e1fa..25352cc 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 f3ed042..b9719f3 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

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

@@ -399,7 +456,10 @@ g_row < Empty , play , Playing , &player_::condition2 >

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.

Note (also valid for forks): in + entry is desired.

Thanks to the mpl_graph library you can also omit to provide the region + index and let MSM find out for you. The are however two points to note:

  • MSM can only find out the region index if the explicit + entry state is somehow connected to an initial state through + a transition, no matter the direction.

  • There is a compile-time cost for this feature.

Note (also valid for forks): 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 @@ -411,7 +471,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:

@@ -424,7 +484,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 @@ -434,7 +494,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>

@@ -465,7 +525,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 @@ -497,7 +557,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 @@ -510,7 +570,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 @@ -536,7 +596,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 @@ -548,7 +608,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 91be570..f77b9a6 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,7 +11,7 @@ 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 + 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 
    @@ -66,7 +66,7 @@ Row  < Paused  , open_close ,  Open     , stop_and_open             , none
                             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 @@ -89,16 +89,31 @@ 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.

    What do you actually do inside actions / guards (Part 2)?

    Using the basic front-end, we saw how to pass data to actions through the + event, that data common to all states could be stored in the state machine, + state relevant data could be stored in the state and access as template + parameter in the entry / exit actions. What was however missing was the + capability to access relevant state data in the transition action. This is + possible with this front-end. A transition's source and target state are + also given as arguments. If the current calculation's state was to be found + in the transition's source state (whatever it is), we could access + it:

    struct send_rocket 
    +{ 
    +    template <class Fsm,class Evt,class SourceState,class TargetState> 
    +    void operator()(Evt const&, Fsm& fsm, SourceState& src,TargetState& ) 
    +    {
    +        fire_rocket(evt.direction, src.current_calculation);
    +    } 
    +}; 

    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 996e12b..62354b9 100644 --- a/doc/HTML/ch03s04.html +++ b/doc/HTML/ch03s04.html @@ -1,8 +1,9 @@ - eUML (experimental)

      eUML (experimental)

      Important note: eUML requires a compiler + 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 + some compilers will start crashing when a state machine becomes too big (usually + when you write huge actions).

      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 @@ -13,13 +14,13 @@ events, initial states.

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

      Examples will be provided in the next paragraphs. You need to include eUML + you will need a compiler where Typeof is supported (like VC9-10, g++ >= + 4.3).

      Examples will be provided in the next paragraphs. You need to include eUML basic features:

      #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

      @@ -46,7 +47,7 @@ Stopped == Empty + cd_detected [good_disk_format] / store_cd_info 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.

      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 + worry, eUML is based on typeof (or 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 @@ -55,7 +56,14 @@ Stopped == Empty + cd_detected [good_disk_format] / store_cd_info [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.

      A simple example: rewriting only our transition table

      As an introduction to eUML, we will rewrite our tutorial's transition + table using eUML. This will require two or three changes, depending on the compiler:

      • events must inherit from msm::front::euml::euml_event< + event_name >

      • states must inherit from msm::front::euml::euml_state< + state_name >

      • with VC, states must be declared before the front-end

      We now can write the transition table like just shown, using + BOOST_MSM_EUML_DECLARE_TRANSITION_TABLE instead of + BOOST_MSM_EUML_TRANSITION_TABLE. The implementation is pretty + straightforward.

      We now have a new, more readable transition table with few changes to our + example. eUML can do much more so please follow the guide.

      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)

      @@ -70,7 +78,7 @@ Stopped == Empty + cd_detected [good_disk_format] / store_cd_info 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)
      @@ -101,7 +109,7 @@ Stopped  == Empty   + cd_detected [good_disk_format] / store_cd_info
       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 +),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) @@ -142,7 +150,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). @@ -172,7 +180,7 @@ Empty_impl const Empty;

      Notice also that we defined a method named activ 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 @@ -183,7 +191,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 @@ -237,7 +245,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 ),
      @@ -289,7 +297,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 @@ -301,7 +309,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 @@ -309,7 +317,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 @@ -330,7 +338,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 @@ -370,7 +378,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 @@ -407,7 +415,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 1faaa55..8011c84 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,14 @@ 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.

    Serialization

    A common need is the ability to save a state machine and restore it at 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 @@ -106,7 +106,7 @@ std::ofstream ofs("fsm.txt"); serializing must be done in a stable state, when no event is being processed. You can serialize during event processing only if using no queue (deferred or event queue).

    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 + 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 @@ -129,7 +129,7 @@ std::ofstream ofs("fsm.txt");

    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 @@ -168,18 +168,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){…} 
    @@ -205,7 +205,7 @@ player p(boost::ref(data),3);
                             where some data is passed:

    player p( back::states_ << Playing(back::states_ << Song1(some_Song1_data)) , 
               boost::ref(data),3);

    It is also possible to replace a given state by a new instance at any time using set_states() and the same syntax, for example: -

    p.set_states( back::states_ << state_1 << ... << state_n );

    An example making intensive use of this capability is provided.

    Trading run-time speed for +

    p.set_states( back::states_ << state_1 << ... << state_n );

    An example making intensive use of this capability is provided.

    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 @@ -214,9 +214,9 @@ player p(boost::ref(data),3); 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:

    • many transition conflicts

    • submachines

    The back-end msm::back::state_machine has a third template - argument (first is the front-end, second is the history policy) defaulting - to favor_runtime_speed. To switch to + policy which will speed up compiling in two main cases:

    • many transition conflicts

    • submachines

    The back-end msm::back::state_machine has a policy argument + (first is the front-end, then the history policy) defaulting to + favor_runtime_speed. To switch to favor_compile_time, which is declared in <msm/back/favor_compile_time.hpp>, you need to:

    • switch the policy to favor_compile_time for the main state machine (and possibly submachines)

    • move the submachine declarations into their own header which @@ -236,4 +236,41 @@ BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(mysubmachine)

    -

    \ No newline at end of file +

    Compile-time state machine analysis

    A MSM state machine being a metaprogram, it is only logical that cheking + for the validity of a concrete state machine happens compile-time. To this + aim, using the compile-time graph library mpl_graph (delivered at the moment + with MSM) from Gordon Woodhull, MSM provides several compile-time checks:

    • Check that orthogonal regions ar truly orthogonal.

    • Check that all states are either reachable from the initial + states or are explicit entries / pseudo-entry states.

    To make use of this feature, the back-end provides a policy (default is no + analysis), msm::back::mpl_graph_fsm_check. For example:

     typedef msm::back::state_machine< player_,msm::back::mpl_graph_fsm_check> player;           

    As MSM is now using Boost.Parameter to declare policies, the policy choice + can be made at any position after the front-end type (in this case + player_).

    In case an error is detected, a compile-time assertion is provoked.

    This feature is not enabled by default because it has a non-neglectable + compile-time cost. The algorithm is linear if no explicit or pseudo entry + states are found in the state machine, unfortunately still O(number of + states * number of entry states) otherwise. This will be improved in future + versions of MSM.

    The same algorithm is also used in case you want to omit providing the + region index in the explicit entry / pseudo entry state declaration.

    The author's advice is to enable the checks after any state machine + structure change and disable it again after sucessful analysis.

    The following example provokes an assertion if one of the first two lines + of the transition table is used.

    Enqueueing events for later + processing

    Calling process_event(Event const&) will immediately + process the event with run-to-completion semantics. You can also enqueue the + events and delay their processing by calling enqueue_event(Event + const&) instead. Calling execute_queued_events() will then + process all enqueued events (in FIFO order).

    You can query the queue size by calling get_message_queue_size().

    Customizing the message queues

    MSM uses by default a std::deque for its queues (one message queue for + events generated during run-to-completion or with + enqueue_event, one for deferred events). Unfortunately, on some + STL implementations, it is a very expensive container in size and copying + time. Should this be a problem, MSM offers an alternative based on + boost::circular_buffer. The policy is msm::back::queue_container_circular. + To use it, you need to provide it to the back-end definition:

     typedef msm::back::state_machine< player_,msm::back::queue_container_circular> player;           

    You can access the queues with get_message_queue and get_deferred_queue, + both returning a reference or a const reference to the queues themselves. + Boost::circular_buffer is outside of the scope of this documentation. What + you will however need to define is the queue capacity (initially is 0) to + what you think your queue will at most grow, for example (size 1 is + common):

     fsm.get_message_queue().set_capacity(1);           

    Policy definition with Boost.Parameter

    MSM uses Boost.Parameter to allow easier definition of + back::state_machine<> policy arguments (all except the front-end). This + allows you to define policy arguments (history, compile-time / run-time, + state machine analysis, container for the queues) at any position, in any + number. For example:

     typedef msm::back::state_machine< player_,msm::back::mpl_graph_fsm_check> player;  
    + typedef msm::back::state_machine< player_,msm::back::AlwaysHistory> player;  
    + typedef msm::back::state_machine< player_,msm::back::mpl_graph_fsm_check,msm::back::AlwaysHistory> player; 
    + typedef msm::back::state_machine< player_,msm::back::AlwaysHistory,msm::back::mpl_graph_fsm_check> player;      
    \ No newline at end of file diff --git a/doc/HTML/ch04.html b/doc/HTML/ch04.html index 23d95f3..9adcb92 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 f8f0905..a89785d 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 3d583c6..c8fe9cb 100644 --- a/doc/HTML/ch04s03.html +++ b/doc/HTML/ch04s03.html @@ -1,6 +1,6 @@ - Supported compilers

    Supported compilers

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

    MSM was successfully tested with: