From 27afa85171d4243098bf5bfe439750d41bc2e6de Mon Sep 17 00:00:00 2001 From: Christophe Henry Date: Fri, 25 May 2012 19:55:57 +0000 Subject: [PATCH] merged rev. 78506-78627 [SVN r78628] --- doc/HTML/ch01.html | 2 +- doc/HTML/ch02.html | 2 +- doc/HTML/ch02s02.html | 2 +- doc/HTML/ch02s03.html | 2 +- doc/HTML/ch03.html | 14 +- doc/HTML/ch03s02.html | 2 +- doc/HTML/ch03s03.html | 2 +- doc/HTML/ch03s04.html | 51 ++-- doc/HTML/ch03s05.html | 34 +-- 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 | 28 +- doc/HTML/ch08s02.html | 27 +- doc/HTML/ch08s03.html | 18 +- doc/HTML/ch08s04.html | 17 +- doc/HTML/ch08s05.html | 14 +- doc/HTML/ch08s06.html | 9 + doc/HTML/ch09.html | 4 +- doc/HTML/ch10.html | 20 +- .../CompositeTutorialWithEumlTable.cpp | 6 +- doc/HTML/index.html | 20 +- doc/HTML/pr01.html | 2 +- doc/HTML/pt01.html | 18 +- doc/HTML/pt02.html | 4 +- doc/HTML/re01.html | 4 +- doc/HTML/re02.html | 76 ++--- doc/HTML/re03.html | 282 +++++++++--------- .../CompositeTutorialWithEumlTable.cpp | 6 +- doc/PDF/msm.pdf | Bin 1119615 -> 1122479 bytes doc/images/Defer.jpg | Bin 0 -> 6129 bytes doc/src/msm.xml | 59 +++- 41 files changed, 393 insertions(+), 362 deletions(-) create mode 100644 doc/HTML/ch08s06.html create mode 100644 doc/images/Defer.jpg diff --git a/doc/HTML/ch01.html b/doc/HTML/ch01.html index 3509c7d..d26d28b 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 }; 
diff --git a/doc/HTML/ch02.html b/doc/HTML/ch02.html
index 52c1c20..a285ed2 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 805cabe..6a06000 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 9f82003..3aa8102 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

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) @@ -166,7 +163,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_))

Wrapping up a simple state machine and first complete examples

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

Wrapping up a simple state machine and first complete examples

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). @@ -197,7 +194,7 @@ Empty_impl const Empty;

Notice also that we defined a method named activ 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 @@ -208,7 +205,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 @@ -262,7 +259,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 ),
@@ -314,7 +311,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 @@ -326,7 +323,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 @@ -334,7 +331,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 @@ -355,7 +352,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 @@ -395,7 +392,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 @@ -433,7 +430,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 @@ -462,7 +459,7 @@ struct Open_impl : public Open_def current state has an attribute m_src_it (an iterator). If this iterator != fsm.m_src_container.end(), process OneSong on fsm, copy-constructed from state.m_src_it which we - post-increment

Writing actions with Boost.Phoenix (in development)

It is also possible to write actions, guards, state entry and exit + post-increment

Writing actions with Boost.Phoenix (in development)

It is also possible to write actions, guards, state entry and exit actions using a reduced set of Boost.Phoenix capabilities. This feature is still in development stage, so you might get here and there some surprise. Simple cases, however, should work well. What will not work diff --git a/doc/HTML/ch03s05.html b/doc/HTML/ch03s05.html index 1745ad1..5ba587a 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,11 +8,11 @@ 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 and stopping a state + describe what can be done with it.

Starting and stopping 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 @@ -23,7 +23,7 @@ the algorithm run once. The iPodSearch example uses this possibility.

The stop() method works the same way. It will cause the exit actions of the currently active states(s) to be called.

Both methods are actually not an absolute need. Not calling them will simply cause your first entry or your last exit action not to be - called.

Event dispatching

The main reason to exist for a state machine is to dispatch events. For + called.

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 @@ -34,14 +34,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 @@ -110,7 +110,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 @@ -133,7 +133,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 @@ -172,18 +172,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){…} 
@@ -209,7 +209,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 @@ -240,7 +240,7 @@ BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(mysubmachine)

-

Compile-time state machine analysis

A MSM state machine being a metaprogram, it is only logical that cheking +

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 @@ -254,12 +254,12 @@ BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(mysubmachine)

  • 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 + 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 + 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 @@ -270,14 +270,14 @@ BOOST_MSM_BACK_GENERATE_PROCESS_EVENT(mysubmachine)

  • fsm.get_message_queue().set_capacity(1);
  • Policy definition with Boost.Parameter

    MSM uses Boost.Parameter to allow easier definition of + 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;      

    Choosing when to switch active + typedef msm::back::state_machine< player_,msm::back::AlwaysHistory,msm::back::mpl_graph_fsm_check> player;

    Choosing when to switch active states

    The UML Standard is silent about a very important question: when a transition fires, at which exact point is the target state the new active state of a state machine? At the end of the transition? After the source diff --git a/doc/HTML/ch04.html b/doc/HTML/ch04.html index a0f93be..f23e9a6 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 f1a1cd0..06c40f8 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 b307f8f..f02336d 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: