diff --git a/doc/acknowledgments.html b/doc/acknowledgments.html index 85b9a9d..601fd20 100644 --- a/doc/acknowledgments.html +++ b/doc/acknowledgments.html @@ -37,20 +37,20 @@
Special thanks go to:
lightweight_mutex,
intrusive_ptr) boost::fsm is building onThanks for feedback and/or encouragement go to:
David Abrahams, Bohdan, Reece Dunn, Jeff Garland, Douglas Gregor, Gustavo -Guerra, Aleksey Gurtovoy, Chris Russell and Scott Woods.
+Guerra, Aleksey Gurtovoy, Chris Russell, Vincent N. Virgilio and Scott Woods.Revised -12 October, 2003
+17 November, 2003© Copyright Andreas Huber Dönni 2003. All Rights Reserved.
diff --git a/doc/configuration.html b/doc/configuration.html new file mode 100644 index 0000000..15defb6 --- /dev/null +++ b/doc/configuration.html @@ -0,0 +1,89 @@ + + + + + + + + +
+
+
+ |
+
+ The boost::fsm library+Configuration+ |
+
The library uses several configuration macros in +<boost/config.hpp>, +as well as one configuration macro meant to be supplied by the application. +Moreover, two commonly available compiler options also have an impact on the +available features.
+
+ state_cast<>() leads to a compile time error (state_downcast<>()
+ is still available). Moreover, BOOST_FSM_USE_NATIVE_RTTI must
+ not be defined simultaneouslyThe following macro may be defined by an application using the library:
+| Macro | +Meaning | +
BOOST_FSM_USE_NATIVE_RTTI |
+ When defined, the library no longer uses its own
+ speed-optimized RTTI implementation. Instead, native C++ RTTI is employed.
+ This has the following effects:
|
+
Revised + 30 November, 2003 +
+© Copyright Andreas Huber 2003.
+ + + + diff --git a/doc/definitions.html b/doc/definitions.html index d0c9c5a..5a9fe19 100644 --- a/doc/definitions.html +++ b/doc/definitions.html @@ -24,18 +24,49 @@The boost::fsm documentation uses a lot of terminology specific to state +machines. Most of it is equal to the one used in the UML specifications. This +document contains only definitions for terminology not used by UML.
+The direct context of a state is either its outer state or the state +machine. In the latter case the state is an outermost state.
+The innermost common outer state of two states is the first direct or +indirect outer state that both states have in common. Also known as Least +Common Ancestor (UML).
+An innermost state is a state that does not itself have inner states. Also
+known as leaf state or simple state (UML). Note that
+boost::fsm::simple_state is not a model of the UML simple state.
An in-state reaction is a reaction that neither +exits nor enters any states. Also known as inner transition or internal +transition (UML).
+An outermost state is a state that does not itself have outer states. Note +that an outermost state is different from a UML top state. A state machine can +have an arbitrary number of the former but only exactly one of the latter. +boost::fsm only supports outermost states.
An FSM library supports polymorphic events if events can inherit from - each other without restrictions and allows the definition of - reactions for leafs and nodes of the resulting event inheritance - tree.
-Example (using a hypothetical fsm library, as boost::fsm does not support - polymorphic events):
-struct EvButtonPressed : Event // node +An FSM library supports polymorphic events if events can inherit from each +other without restrictions and allows the definition of reactions for +leafs and nodes of the resulting event inheritance tree.
+Example (using a hypothetical fsm library, as boost::fsm does not support +polymorphic events):
+struct EvButtonPressed : Event // node { /* common button pressed properties */ }; @@ -43,14 +74,51 @@ struct EvPlayButtonPressed : EvButtonPressed {}; // leaf struct EvStopButtonPressed : EvButtonPressed {}; // leaf struct EvForwardButtonPressed : EvButtonPressed {}; // leaf-If a state machine needs to react whenever any button (including - the ones that may be added in the future) is pressed, a reaction for
- -- EvButtonPressedcan be defined.
If a state machine needs to react whenever any button (including the
+ones that may be added in the future) is pressed, a reaction for
+EvButtonPressed can be defined.
A reaction consists of all the side effects caused by the processing of one +event. Reactions can be categorized as follows:
+Note that it is possible to mix a reaction of type 1 with one of the other +types (the in-state reaction is always executed first) but it is not possible +to mix a reaction of type 2-4 with anything else but type 1.
+A reaction is always associated with exactly one state type and exactly one +event type.
+A state is unstable from the moment when it has been entered until just +before its last direct inner state is entered.
+A state machine is unstable if at least one of its currently active states +is unstable. This is the case during the following three operations:
+Under normal circumstances a state machine has Run-To-Completion semantics,
+that is, processing of an event is fully completed before the machine returns
+to the client or before the next event is dequeued. Therefore, a state machine
+is usually only unstable when it is busy processing an event and becomes
+stable again right before it has finished processing the event. However, this
+can not be guaranteed when either transition actions or entry actions fail
+(exit actions cannot fail). Such a failure is reported by an event, which must
+be processed while the state machine is unstable. However, exception event
+processing rules ensure that a state machine cannot be unstable when it
+returns to the client (see state_machine<>::process_event for
+details).
Revised - 12 October, 2003 + 09 December, 2003
© Copyright Andreas Huber Dönni 2003.
diff --git a/doc/faq.html b/doc/faq.html index 291215a..621ea8e 100644 --- a/doc/faq.html +++ b/doc/faq.html @@ -42,7 +42,8 @@No. Although events can be derived from each other to write common code -only once, reactions can only be defined for most-derived events.
+only once, reactions can only be +defined for most-derived events.Example:
template< class MostDerived > struct EvButtonPressed : fsm::event< MostDerived > @@ -249,7 +250,7 @@ destructors of additional bases are called before recursion employed by state base destructors can alter the order of destruction.
Revised -12 October, 2003
+01 December, 2003© Copyright Andreas Huber Dönni 2003. All Rights Reserved.
diff --git a/doc/index.html b/doc/index.html index 3c9ce59..b361a7a 100644 --- a/doc/index.html +++ b/doc/index.html @@ -53,14 +53,12 @@ include:
The library is almost functionally complete. However, the following is -still in the making:
+The library is functionally complete. However, the following is still in +the making:
state_machine class template to reduce
code size in projects with many different state machines12 December 2003:
+12 October 2003:
rtti_policy<> from the
@@ -111,7 +119,7 @@ still in the making:
Revised -12 October, 2003
+12 December, 2003© Copyright Andreas Huber Dönni 2003. All Rights Reserved.
diff --git a/doc/rationale.html b/doc/rationale.html index 9ec3acd..bc4c4e9 100644 --- a/doc/rationale.html +++ b/doc/rationale.html @@ -48,8 +48,8 @@ are the result of the following requirements.boost::fsm should ...
Consider the following state configuration:

Both states define entry actions (x() and y()). Whenever state A becomes -current, a call to x() will immediately be followed by a call to y(). y() -could depend on the side-effects of x(). Therefore, executing y() does not -make sense if x() fails. This is not an esoteric corner case but happens in +active, a call to x() will immediately be followed by a call to y(). y() could +depend on the side-effects of x(). Therefore, executing y() does not make +sense if x() fails. This is not an esoteric corner case but happens in every-day state machines all the time. For example, x() could acquire memory the contents of which is later modified by y(). There is a different but in terms of error handling equally critical situation in the Tutorial under @@ -229,11 +233,14 @@ code is simply boring and quite unnecessary.
react functions
- are sent to the current state.In the last two cases the state-machine is not in a stable state when the exception event is generated and leaving it there (e.g. by ignoring the @@ -245,25 +252,25 @@ code is simply boring and quite unnecessary.
rethrown.The design of the asynchronous_state_machine<> and
-worker<> class templates follow from the requirements:
The design of the asynchronous_state_machine and worker
+class templates follow from the requirements:
worker<> class template is not associated with a particular
+ The worker class template is not associated with a particular
thread. Instead, users can choose to either call worker<>::operator()
directly from the current thread or pass an appropriate function object to a
new thread.
- worker<> object. The state machines will then share the same
+ worker object. The state machines will then share the same
thread-safe queue and event loop.
- worker<>.BitMachine measurements with more states and with different levels of optimization:
-| Machine configuration - # states / # outgoing transitions per state |
- Event dispatch & transition time [nanoseconds] | +Machine configuration + # states / # outgoing transitions per state |
+ Event dispatch & transition time + [nanoseconds] | ||||
| Out of the box | Same as out of the box but with
- BOOST_FSM_USE_NATIVE_RTTI defined |
+
+ BOOST_FSM_USE_NATIVE_RTTI defined
Same as out of the box but with customized memory management | |||||
+
+
+ |
+
+ The boost::fsm library+Reference+ |
+
+ state_machineasynchronous_state_machineno_reactionshistory_modesimple_statestateAn ExceptionTranslator type defines how C++ exceptions occurring during
+state machine operation are translated to exception events. Every model of
+this concept must provide an operator() with the following
+signature:
template< class Action, class ExceptionEventHandler > +result operator()( + Action action, + ExceptionEventHandler eventHandler, + result handlerSuccessResult );+
For an ExceptionTranslator object e the following expression
+must be well-formed and have the indicated results:
| Expression | +Type | +Effects/Result | +
result action(); |
+ result |
+
+
|
+
A StateBase type is the common base of all states of a given state machine
+type. state_machine<>::state_base_type is a model of the
+StateBase concept.
For a StateBase type S and a const object
+cs of that type the following expressions must be well-formed and have
+the indicated results:
| Expression | +Type | +Result | +
cs.outer_state_ptr() |
+ const S * |
+ 0 if cs is an
+ outermost state, a pointer
+ to the outer state of cs otherwise |
+
cs.dynamic_type() |
+ S::id_type |
+ A value unambiguously identifying the most-derived type of
+ cs. S::id_type values are comparable with
+ operator== and operator!=. An unspecified collating
+ order can be established with std::less< S::id_type > |
+
cs.custom_dynamic_type_ptr< |
+ const Type * |
+ A pointer to the custom type identifier or 0.
+ If != 0, Type must match the type of the
+ previously set pointer. The result is undefined if this is not the case. |
+
todo
+state_machineThis is the base class template of all synchronous state machines.
+state_machine parameters| Template parameter | +Requirements | +Semantics | +Default | +
MostDerived |
+ The most-derived subclass of this class template | ++ | + |
InitialState |
+ A most-derived direct or indirect subclass of either the
+ simple_state or the state class template. The
+ type that this class passes as Context to its base class
+ template must be equal to MostDerived. That is,
+ InitialState must be an
+ outermost state of this state machine |
+ The state that is entered when state_machine<>:: is called |
+ + |
Allocator |
+ A model of the standard Allocator concept | ++ | std::allocator< void > |
+
ExceptionTranslator |
+ A model of the ExceptionTranslator concept | +see ExceptionTranslator + concept | +exception_translator<> |
+
state_machine synopsisnamespace boost
+{
+namespace fsm
+{
+ template<
+ class MostDerived,
+ class InitialState,
+ class Allocator = std::allocator< void >,
+ class ExceptionTranslator = exception_translator<> >
+ class state_machine : noncopyable
+ {
+ public:
+ typedef MostDerived outermost_context_type;
+
+ bool initiate();
+ void terminate();
+ bool terminated() const;
+
+ bool process_event( const event_base & );
+
+ template< class Target >
+ Target state_cast() const;
+ template< class Target >
+ Target state_downcast() const;
+
+ // a model of the StateBase concept
+ typedef implementation-defined state_base_type;
+ // a model of the standard Forward Iterator concept
+ typedef implementation-defined state_iterator;
+
+ state_iterator state_begin() const;
+ state_iterator state_end() const;
+
+ protected:
+ state_machine();
+ ~state_machine();
+ };
+}
+}
+state_machine constructor and destructorstate_machine();+
Effects: Constructs a non-running state machine
+Postcondition: terminated()
~state_machine();+
Effects: terminate();
state_machine modifier functionsbool initiate();+
Effects:
+terminate()action with a parameter-less
+ operator() returning result thatInitialState
+ template parameterInitialState depth firstexceptionEventHandler with an
+ operator() returning bool and accepting an
+ exception event parameter that processes the passed exception event, with
+ the following differences to the processing of normal events:
+ exceptionEventHandler function object (that is,
+ ExceptionTranslator is not used to process exception events)false
+ is returned from the exceptionEventHandler function object.
+ Otherwise, true is returnedaction, exceptionEventHandler and the
+ result value handlerSuccessResult to
+ ExceptionTranslator::operator(). If
+ ExceptionTranslator::operator() throws an exception,
+ terminate() is called and the exception is propagated to the caller.
+ Continues with step 5 otherwise (the return value is discarded)process_event)Returns: terminated()
+Throws: Any exceptions propagated from
+ExceptionTranslator::operator(). Exceptions never originate in the
+library itself but only in code supplied through template parameters. That is,
+std::bad_alloc thrown by Allocator::allocate as well
+as any exceptions thrown by user-supplied react functions,
+transition-actions and entry-actions
void terminate();+
Effects: The state machine exits (destructs) all currently active
+states. Innermost states are
+exited first. Other states are exited as soon as all their direct and indirect
+inner states have been exited
+Postcondition: terminated()
bool process_event( const event_base & );+
Effects:
+action with a parameter-less
+ operator() returning result that does the
+ following:simple_state::forward_event()
+ if no reaction has been found.simple_state::forward_event() then resumes
+ the reaction search (step a). Returns the reaction result otherwiseexceptionEventHandler with an
+ operator() accepting an exception event parameter and returning
+ bool that processes the passed exception event, with the
+ following differences to the processing of normal events:
+ exceptionEventHandler function object (that is,
+ ExceptionTranslator is not used to process exception events)false
+ is returned from the exceptionEventHandler function object.
+ Otherwise, true is returnedaction, an exceptionEventHandler
+ callback and the fsm::result value handlerSuccessResult
+ to ExceptionTranslator::operator(). If
+ ExceptionTranslator::operator() throws an exception then calls
+ terminate() and propagates the exception to the callerExceptionTranslator::operator() is
+ equal to the one of simple_state::forward_event() then
+ continues with step 3ExceptionTranslator::operator() is
+ equal to the one of simple_state::defer_event() then the
+ current event is stored in a state-specific queue. Continues with step 10ExceptionTranslator::operator() returns the previously
+ passed handlerSuccessResult or if the return value is equal to
+ the one of simple_state::discard_event() then continues with
+ step 10Returns: false, if the machine was terminated before
+processing the event. Returns terminated() otherwise
+Throws: Any exceptions propagated from
+ExceptionTranslator::operator(). Exceptions never originate in the
+library itself but only in code supplied through template parameters. That is,
+std::bad_alloc thrown by Allocator::allocate as well
+as any exceptions thrown by user-supplied reactions, transition-actions and
+entry-actions
state_machine observer functionsbool terminated() const;+
Returns: true, if the machine is terminated. Returns
+false otherwise
+Note: Is equivalent to state_begin() == state_end()
template< class Target > +Target state_cast() const;+
Returns: Depending on the form of Target either a
+reference or a pointer to const if at least one of the currently
+active states can successfully be dynamic_cast to Target.
+Returns 0 for pointer targets and throws std::bad_cast
+for reference targets otherwise. Target can take either of the
+following forms: const Class * or const Class &
+Throws: std::bad_cast if Target is a
+reference type and none of the active states can be dynamic_cast
+to Target
+Note: The search sequence is the same as for event dispatch
template< class Target > +Target state_downcast() const;+
Returns: Depending on the form of Target either a
+reference or a pointer to const if Target is equal
+to the most-derived type of a currently active state. Returns 0
+for pointer targets and throws std::bad_cast for reference
+targets otherwise. Target can take either of the following forms:
+const Class * or const Class &
+Throws: std::bad_cast if Target is a
+reference type and none of the active states has a most derived type equal to
+Target
+Note: The search sequence is the same as for event dispatch
state_iterator state_begin() const;+
state_iterator state_end() const;+
Return: Iterator objects, the range [state_begin(),
+state_end()) refers to all currently active
+innermost states. For an object
+i of type state_iterator, *i returns a
+const state_base_type & and i.operator->() returns a
+const state_base_type *
+Note: The position of individual innermost states in the range is
+undefined. Their position may change with each call to a modifier function.
+Moreover, all iterators are invalidated when a modifier function is called
+asynchronous_state_machineThis is the base class template of all asynchronous state machines.
+asynchronous_state_machine parameters| Template parameter | +Requirements | +Semantics | +Default | +
MostDerived |
+ The most-derived subclass of this class template | ++ | + |
InitialState |
+ A most-derived direct or indirect subclass of either the
+ simple_state or the state class template. The
+ type that this class passes as Context to its base class
+ template must be equal to MostDerived. That is,
+ InitialState must be an
+ outermost state of this state machine |
+ The state that is entered when Worker:: is called |
+ + |
Worker |
+ A model of the Worker concept | +see Worker concept | +worker<> |
+
Allocator |
+ A model of the standard Allocator concept | ++ | std::allocator< void > |
+
ExceptionTranslator |
+ A model of the ExceptionTranslator concept | +see ExceptionTranslator + concept | +exception_translator<> |
+
asynchronous_state_machine synopsistemplate<
+ class MostDerived,
+ class InitialState,
+ class Worker = worker<>,
+ class Allocator = std::allocator< void >,
+ class ExceptionTranslator = exception_translator<> >
+class asynchronous_state_machine : implementation-defined
+{
+ public:
+ void queue_event( const intrusive_ptr< event_base > & );
+
+ protected:
+ asynchronous_state_machine( Worker & myWorker );
+ ~asynchronous_state_machine();
+};
+asynchronous_state_machine constructor and
+destructorasynchronous_state_machine( Worker & myWorker );+
Precondition: No thread of control is currently inside
+myWorker.operator()
+Effects: Constructs a non-running asynchronous state machine and registers
+it with the passed worker
+Throws: Whatever Allocator::allocate (invoked by the
+worker) throws
~asynchronous_state_machine();+
Precondition: No thread of control is currently inside
+myWorker.operator(). The worker object passed to the constructor has
+not yet been destructed
+Effects: Terminates the state machine
asynchronous_state_machine modifier functionsvoid queue_event( const intrusive_ptr< event_base > & );+
Effects: Pushes the passed event into the queue of the worker object
+passed to the constructor
+Throws: Whatever Allocator::allocate (invoked by the
+worker) throws
no_reactionsThis is the default value for the Reactions parameter of the
+simple_state class template. Necessary for the rare cases when a
+state without reactions has inner states.
namespace boost
+{
+namespace fsm
+{
+ typedef implementation-defined no_reactions;
+}
+}
+history_modeDefines the history type of a state.
+namespace boost
+{
+namespace fsm
+{
+ enum history_mode
+ {
+ has_no_history,
+ has_shallow_history,
+ has_deep_history,
+ has_full_history // shallow & deep
+ };
+}
+}
+simple_stateThe base class template of all states that do not need to call any
+of the following simple_state member functions from their
+constructors:
void post_event( + const intrusive_ptr< const event_base > & ); + +outermost_context_type & outermost_context(); +const outermost_context_type & outermost_context() const; + +template< class OtherContext > +OtherContext & context(); +template< class OtherContext > +const OtherContext & context() const; + +template< class Target > +Target state_cast() const; +template< class Target > +Target state_downcast() const;+
States that need to call any of these functions from their constructors
+must derive from the state class template.
simple_state parameters| Template parameter | +Requirements | +Semantics | +Default | +
MostDerived |
+ The most-derived subclass of this class template | ++ | + |
Context |
+ A most-derived direct or indirect subclass of either the
+ state_machine, asynchronous_state_machine,
+ simple_state or state class templates or an
+ instantiation of the orthogonal class template nested in the
+ state base classes. Must be a complete type |
+ Defines the states' position in the state hierarchy | ++ |
Reactions |
+ An mpl::list containing instantiations of the
+ custom_reaction, deferral, termination
+ or transition class templates. If there is only a single
+ reaction then it can also be passed directly, without wrapping it into an
+ mpl::list |
+ Defines to which events a state can react | +no_reactions |
+
InnerInitial |
+ An mpl::list containing most-derived direct
+ or indirect subclasses of either the simple_state or the
+ state class template or instantiations of either the
+ shallow_history or deep_history class templates. If
+ there is only a single non-history inner initial state then it can also be
+ passed directly, without wrapping it into an mpl::list. The
+ type that each state in the list passes as Context to its
+ base class template must correspond to the orthogonal region it belongs
+ to. That is, the first state in the list must pass
+ MostDerived::orthogonal< 0 >, the second
+ MostDerived::orthogonal< 1 > and so forth.
+ MostDerived::orthogonal< 0 > and MostDerived are
+ synonymous |
+ Defines the inner initial state for each orthogonal + region. By default, a state does not have inner states | +unspecified |
+
historyMode |
+ One of the values defined in the history_mode
+ enumeration |
+ Defines whether the state saves shallow, deep or both + histories upon exit | +has_no_history |
+
simple_state synopsisnamespace boost
+{
+namespace fsm
+{
+ template<
+ class MostDerived,
+ class Context,
+ class Reactions = no_reactions,
+ class InnerInitial = unspecified,
+ history_mode historyMode = has_no_history >
+ class simple_state : implementation-defined
+ {
+ public:
+ // see template parameters
+ template< implementation-defined-unsigned-integer-type
+ innerOrthogonalPosition >
+ struct orthogonal
+ {
+ // implementation-defined
+ };
+
+ typedef typename Context::outermost_context_type
+ outermost_context_type;
+
+ outermost_context_type & outermost_context();
+ const outermost_context_type & outermost_context() const;
+
+ template< class OtherContext >
+ OtherContext & context();
+ template< class OtherContext >
+ const OtherContext & context() const;
+
+ template< class Target >
+ Target state_cast() const;
+ template< class Target >
+ Target state_downcast() const;
+
+ void post_event(
+ const intrusive_ptr< const event_base > & );
+
+ result discard_event();
+ result forward_event();
+ result defer_event();
+ template< class DestinationState >
+ result transit();
+ template<
+ class DestinationState,
+ class TransitionContext,
+ class Event >
+ result transit(
+ void ( TransitionContext::* )( const Event & ),
+ const Event & );
+ result terminate();
+
+ static id_type static_type();
+
+ template< class CustomId >
+ static const CustomId * custom_static_type_ptr();
+
+ template< class CustomId >
+ static void custom_static_type_ptr( const CustomId * );
+
+ protected:
+ simple_state();
+ virtual ~simple_state();
+ };
+}
+}
+simple_state constructor and destructorsimple_state();+
Effects: Depending on the historyMode parameter,
+reserves storage to store none, shallow, deep or both histories
+Throws: Any exceptions propagated from Allocator::allocate
+(the template parameter passed to the base class of
+outermost_context_type)
+Note: The constructors of all direct and indirect subclasses should be
+exception-neutral
virtual ~simple_state();+
Effects: Depending on the historyMode parameter, stores
+none, shallow, deep or both histories. Pushes all events deferred by the state
+into the posted events queue
simple_state modifier functionsvoid post_event( + const intrusive_ptr< const event_base > & );+
Effects: Pushes the passed event into the state machine's posted
+events queue
+Throws: Any exceptions propagated from Allocator::allocate
+(the template parameter passed to the base class of
+outermost_context_type)
+Note: Unless the direct subclass is the state class
+template, this function must not be called from the constructors of direct and
+indirect subclasses. All direct and indirect callers should be
+exception-neutral
result discard_event();+
Effects: Instructs the state machine to discard the current event
+and to continue with the processing of the remaining events (see
+state_machine::process_event for details)
+Returns: An unspecified value of the result enumeration.
+The user-supplied react member function must return this value to
+its caller
+Note: Must only be called from within react member
+functions, which are called by custom_reaction instantiations.
+All direct and indirect callers should be exception-neutral
result forward_event();+
Effects: Instructs the state machine to forward the current event to
+the next state (see
+state_machine::process_event for details)
+Returns: An unspecified value of the result enumeration.
+The user-supplied react member function must return this value to
+its caller
+Note: Must only be called from within react member
+functions, which are called by custom_reaction instantiations.
+All direct and indirect callers should be exception-neutral
result defer_event();+
Effects: Instructs the state machine to defer the current event and
+to continue with the processing of the remaining events (see
+state_machine::process_event for details)
+Returns: An unspecified value of the result enumeration.
+The user-supplied react member function must return this value to
+its caller
+Note: Must only be called from within react member
+functions, which are called by custom_reaction instantiations.
+All direct and indirect callers should be exception-neutral
template< class DestinationState > +result transit();+
Effects:
+DestinationState.
+ Innermost states are exited first. Other states are exited as soon as all
+ their direct and indirect inner states have been exitedDestinationState
+ itself or a direct or indirect outer state of DestinationState
+ DestinationState
+ depth firstDestinationState depth first
+ state_machine::process_event for
+ details)Returns: An unspecified value of the result
+enumeration. The user-supplied react member function must return
+this value to its caller
+Throws: Any exceptions propagated from operator new (used
+to allocate states), state constructors or Allocator::allocate
+(the template parameter passed to the base class of
+outermost_context_type)
+Note: Must only be called from within react member
+functions, which are called by custom_reaction instantiations.
+All direct and indirect callers should be exception-neutral
+Caution: Inevitably exits (destructs) this state before returning to
+the calling react member function, which must therefore not
+attempt to access anything except stack objects before returning to its caller
template< + class DestinationState, + class TransitionContext, + class Event > +result transit( + void ( TransitionContext::* )( const Event & ), + const Event & );+
Effects:
+DestinationState.
+ Innermost states are exited first. Other states are exited as soon as all
+ their direct and indirect inner states have been exitedDestinationState
+ itself or a direct or indirect outer state of DestinationState
+ DestinationState
+ depth firstDestinationState depth first
+ state_machine::process_event for
+ details)Returns: An unspecified value of the result
+enumeration. The user-supplied react member function must return
+this value to its caller
+Throws: Any exceptions propagated from operator new (used
+to allocate states), state constructors, the transition action or
+Allocator::allocate (the template parameter passed to the base class of
+outermost_context_type)
+Note: Must only be called from within react member
+functions, which are called by custom_reaction instantiations.
+All direct and indirect callers should be exception-neutral
+Caution: Inevitably exits (destructs) this state before returning to
+the calling react member function, which must therefore not
+attempt to access anything except stack objects before returning to its caller
result terminate();+
Effects: Terminates the state and instructs the state machine to
+discard the current event and to continue with the processing of the remaining
+events (see state_machine::process_event
+for details)
+Returns: An unspecified value of the result enumeration.
+The user-supplied react member function must return this value to
+its caller
+Note: Must only be called from within react member
+functions, which are called by custom_reaction instantiations.
+All direct and indirect callers should be exception-neutral
+Caution: Inevitably exits (destructs) this state before returning to
+the calling react member function, which must therefore not
+attempt to access anything except stack objects before returning to its caller
simple_state observer functionsoutermost_context_type & outermost_context();+
Returns: A reference to the outermost context, which is always the
+state machine this state belongs to
+Note: Unless the direct subclass is the state class
+template, this function must not be called from the constructors of direct and
+indirect subclasses
const outermost_context_type & outermost_context() const;+
Returns: A reference to the const outermost context, which is always
+the state machine this state belongs to
+Note: Unless the direct subclass is the state class
+template, this function must not be called from the constructors of direct and
+indirect subclasses
template< class OtherContext > +OtherContext & context();+
Returns: A reference to a direct or indirect context
+Note: Unless the direct subclass is the state class
+template, this function must not be called from the constructors of direct and
+indirect subclasses
template< class OtherContext > +const OtherContext & context() const;+
Returns: A reference to a const direct or indirect context
+Note: Unless the direct subclass is the state class
+template, this function must not be called from the constructors of direct and
+indirect subclasses
template< class Target > +Target state_cast() const;+
Returns: Has exactly the same semantics as
+state_machine::state_cast
+Note: Unless the direct subclass is the state class
+template, this function must not be called from the constructors of direct and
+indirect subclasses. The result is unspecified if this function is
+called when the machine is not stable
template< class Target > +Target state_downcast() const;+
Returns: Has exactly the same semantics as
+state_machine::state_downcast
+Note: Unless the direct subclass is the state class
+template, this function must not be called from the constructors of direct and
+indirect subclasses. The result is unspecified if this function is
+called when the machine is not stable
simple_state static functionsstatic id_type static_type();+
Returns: A value unambiguously identifying the type of
+MostDerived. id_type values are comparable with
+operator== and operator!=. An unspecified collating order
+can be established with std::less< S::id_type >
template< class CustomId > +static const CustomId * custom_static_type_ptr();+
Returns: The pointer to the custom type identifier for
+MostDerived or 0. If != 0, CustomId must
+match the type of the previously set pointer. The result is undefined if this
+is not the case
+Note: This function is not available if
+
+BOOST_FSM_USE_NATIVE_RTTI is defined
template< class CustomId > +static void custom_static_type_ptr( const CustomId * );+
Effects: Sets the pointer to the custom type identifier for
+MostDerived
+Note: This function is not available if
+
+BOOST_FSM_USE_NATIVE_RTTI is defined
stateThis is the base class template of all states that need to call any of the
+following simple_state member functions from their constructors:
void post_event( + const intrusive_ptr< const event_base > & ); + +outermost_context_type & outermost_context(); +const outermost_context_type & outermost_context() const; + +template< class OtherContext > +OtherContext & context(); +template< class OtherContext > +const OtherContext & context() const; + +template< class Target > +Target state_cast() const; +template< class Target > +Target state_downcast() const;+
States that do not need to call any of these functions from their
+constructors should rather derive from the simple_state class
+template, what saves the implementation of the forwarding constructor.
state synopsisnamespace boost
+{
+namespace fsm
+{
+ template<
+ class MostDerived,
+ class Context,
+ class Reactions = no_reactions,
+ class InnerInitial = unspecified,
+ history_mode historyMode = has_no_history >
+ class state : public simple_state<
+ MostDerived, Context, Reactions, InnerInitial, historyMode >
+ {
+ protected:
+ struct my_context
+ {
+ // implementation-defined
+ };
+
+ typedef state my_base;
+
+ state( my_context ctx );
+ virtual ~state();
+ };
+}
+}
+Direct and indirect subclasses of state must provide a
+constructor with the same signature as the state constructor,
+forwarding the context parameter.
Revised +12 December, 2003
+Copyright © 2003 Andreas Huber Dönni. +All Rights Reserved.
+ + + + diff --git a/doc/reference.pdf b/doc/reference.pdf new file mode 100644 index 0000000..3793ed4 Binary files /dev/null and b/doc/reference.pdf differ diff --git a/doc/tutorial.html b/doc/tutorial.html index f31b861..d6e415f 100644 --- a/doc/tutorial.html +++ b/doc/tutorial.html @@ -24,9 +24,14 @@The Japanese translation of this tutorial can be found at + +http://prdownloads.sourceforge.jp/jyugem/7127/fsm-tutorial-jp.pdf. Kindly +contributed by Mitsuo Fukasawa.
All examples have been tested with MSVC7.1 and boost distribution 1.30.2.
+This tutorial was designed to be read linearly. First time users should +start reading right at the beginning and stop as soon as they know enough for +the task at hand. Specifically:
+We follow the tradition and use the simplest possible program to make our first steps. We will implement the following state chart:
@@ -109,9 +134,15 @@ is destroyed what automatically exits theGreeting state.
class template.
initiate().Machine is passed as the second
- template parameter of Greeting's base.Machine
+ is passed as the second template parameter of Greeting's base.Greeting is passed as the
second template parameter of Machine's base. We have to forward
@@ -182,15 +213,16 @@ int main()
simple_state class template accepts up to four
parameters.
fsm::no_reactions,
- which is also the default.fsm::no_reactions, which is also the default.A reaction is anything that happens as the result of the processing of an -event. For the moment we will use only one type of reaction: transitions. We -insert the bold part of the following code:
+For the moment we will use only one type of reaction: transitions. We +insert the bold parts of the following code:
#include <boost/fsm/transition.hpp> // ... @@ -229,7 +260,7 @@ int main() return 0; }
A state can define an arbitrary number of reactions. That's why we have to
-put them into an mpl::list<> as soon as there is more than one of
+put them into an mpl::list as soon as there is more than one of
them (see Specifying
multiple reactions for a state).
Now we have all the states and all the transitions in place and a number of
@@ -397,7 +428,8 @@ limitations:
All these limitations can be overcome with custom reactions. Warning: It is easy to abuse custom reactions up to the point of invoking undefined @@ -450,8 +482,8 @@ struct EvConfig : fsm::event< EvConfig > {}; struct NotShooting; struct Camera : fsm::state_machine< Camera, NotShooting > { - bool IsMemoryAvailable() const { return true; } - bool IsBatteryLow() const { return false; } + bool IsMemoryAvailable() const { return true; } + bool IsBatteryLow() const { return false; } }; struct Idle; @@ -494,10 +526,10 @@ fsm::result Idle::react( const EvConfig & )
Caution: Any call to the
simple_state::transit<>() or simple_state::terminate()
(see Reaction function reference)
-member functions will inevitably destruct the current state object (similar to
-delete this;)! That is, code executed after any of these calls
-may invoke undefined behavior! That's why these functions should
-only be called as part of a return statement.
+delete this;)! That is, code executed after any of these calls may
+invoke undefined behavior! That's why these functions should only
+be called as part of a return statement.
The inner workings of the Shooting state could look as follows:

The self-transition of the Focused state could also be implemented as an -in-state reaction, which has the same effect as long as Focused does not have -any entry or exit actions:
+The self-transition of the Focused state could also be implemented as an +in-state reaction, which has +the same effect as long as Focused does not have any entry or exit actions:
Shooting.cpp:
// ...
fsm::result Focused::react( const EvShutterFull & )
@@ -577,7 +608,8 @@ fsm::result Focused::react( const EvShutterFull & )
{
std::cout << "Cache memory full. Please wait...\n";
// Indicate that the event can be discarded. So, the
- // dispatch algorithm will stop looking for a reaction.
+ // dispatch algorithm will stop looking for a reaction
+ // and the machine remains in the Focused state.
return discard_event();
}
}
@@ -586,8 +618,9 @@ fsm::result Focused::react( const EvShutterFull & )
As an effect of every transition, actions are executed in the following
order:
- - Starting from the innermost current state, all exit actions up to but
- excluding the innermost common outer state (aka LCA, least common ancestor).
+ - Starting from the innermost active state, all exit actions up to but
+ excluding the
+ innermost common outer state.
- The transition action (if present).
- Starting from the innermost common outer state, all entry actions down
to the target state followed by the entry actions of the initial states.
@@ -653,7 +686,7 @@ member functions, which must return by calling exactly one function
define a reaction for the event.
simple_state::discard_event(): The dispatch algorithm stops
searching for a reaction and the current event is discarded. Useful to
- implement in-state reactions.
+ implement in-state reactions.
simple_state::defer_event(): The current event is pushed
into a separate queue and the dispatch algorithm stops searching for a
reaction. When the state is exited later, the separate queue is emptied into
@@ -717,7 +750,7 @@ example of how to do this:
with new. The events in the queue are processed as soon as the
current reaction is completed. Events can be posted from inside react
functions, entry-, exit- and transition actions. However, posting from inside
-entry actions is a bit more complicated (see e.g. Focusing::Focusing
+entry actions is a bit more complicated (see e.g. Focusing::Focusing()
in Shooting.cpp in the Camera example):
struct Pumping : fsm::state< Pumping, Purifier >
{
@@ -746,7 +779,7 @@ so this workaround should not uglify user code too much.
Deferring events
To avoid a number of overheads, event deferral has one limitation: Only
events allocated with new and pointed to by a
-boost::intrusive_ptr<> can be deferred. Any attempt to defer a
+boost::intrusive_ptr can be deferred. Any attempt to defer a
differently allocated event will result in a failing runtime assert. Example:
struct Event : fsm::event< Event > {};
struct Initial;
@@ -782,8 +815,9 @@ chart as follows:

As mentioned earlier, the Configuring state contains a fairly complex and
deeply nested inner machine. Naturally, we'd like to restore the previous
-state down to the innermost state(s) in Configuring, that's why we use a deep
-history pseudo state. The associated code looks as follows:
+state down to the innermost state(s)
+in Configuring, that's why we use a deep history pseudo state. The associated
+code looks as follows:
// not part of the Camera example
struct NotShooting : fsm::simple_state< NotShooting, Camera,
/* ... */, Idle, fsm::has_deep_history > //
@@ -809,11 +843,11 @@ and the appropriate states entered. The former is expressed by passing either
fsm::has_full_history (which combines shallow and deep history)
as the last parameter to the simple_state and state
templates. The latter is expressed by specifying either
-fsm::shallow_history<> or fsm::deep_history<> as a
-transition destination or, as we'll see in an instant, as an inner initial
-state. Because it is possible that a state containing a history pseudo state
-has never been entered before a transition to history is made, both templates
-demand a parameter specifying the default state to enter in such situations.
+fsm::shallow_history or fsm::deep_history as a transition
+destination or, as we'll see in an instant, as an inner initial state. Because
+it is possible that a state containing a history pseudo state has never been
+entered before a transition to history is made, both class templates demand a
+parameter specifying the default state to enter in such situations.
The redundancy necessary for using history is checked for consistency at
compile time. That is, the state machine wouldn't have compiled had we
forgotten to pass fsm::has_deep_history to the base of
@@ -835,10 +869,10 @@ struct NotShooting : fsm::simple_state< NotShooting, Camera,
// ...
Unfortunately, there is a small inconvenience due to some template-related
implementation details. When the inner initial state is a class template
-instantiation we always have to put it into an mpl::list<>,
+instantiation we always have to put it into an mpl::list,
although there is only one inner initial state. Moreover, the current deep
-history implementation has some limitations. Please have a look at the
-Limitations chapter in the Rationale.
+history implementation has some
+limitations.
Orthogonal states

To implement this state chart you simply specify more than one inner
@@ -904,17 +938,19 @@ struct CapsLockOn : fsm::simple_state<
struct CapsLockOff : fsm::simple_state<
CapsLockOff, Active::orthogonal< 2 >,
fsm::transition< EvCapsLockPressed, CapsLockOn > > {};
-State queries
-Often reactions in a state machine depend on the current state in one or
+
State queries
+Often reactions in a state machine depend on the active state in one or
more orthogonal regions. This is because orthogonal regions are not completely
orthogonal or a certain reaction in an outer state can only take place if the
-inner orthogonal regions are in particular states. For this purpose, the
-previously introduced state_cast<>() function is also available
-within states.
-As a somewhat far-fetched example, let's assume that our keyboard above
-also accepts EvRequestShutdown events, the reception of which
-makes the keyboard terminate only if all lock keys are in the off state. We
-would then modify the Active state as follows:
+inner orthogonal regions are in particular states. For this purpose, the
+state_cast<>() function introduced under
+Getting state
+information out of the machine is also available within states.
+As a somewhat far-fetched example, let's assume that our
+keyboard also accepts EvRequestShutdown
+events, the reception of which makes the keyboard terminate only if all lock
+keys are in the off state. We would then modify the Keyboard state machine as
+follows:
struct EvRequestShutdown : fsm::event< EvRequestShutdown > {};
struct NumLockOff;
@@ -938,16 +974,107 @@ struct Active: fsm::simple_state<
}
}
};
-Just like dynamic_cast, passing a pointer type instead of
-reference type results in 0 pointers being returned when the cast fails. Note
-also the use of state_downcast instead of state_cast.
-Similar to the differences between boost::polymorphic_downcast
-and dynamic_cast, state_downcast is a much faster
-variant of state_cast and can only be used when the passed type
-is a most-derived type. state_cast should only be used if you
-want to query an additional base, as under
-Getting state
-information out of the machine.
+Passing a pointer type instead of reference type results in 0 pointers
+being returned instead of std::bad_cast being thrown when the
+cast fails. Note also the use of state_downcast<>() instead of
+state_cast<>(). Similar to the differences between
+boost::polymorphic_downcast<>() and dynamic_cast,
+state_downcast<>() is a much faster variant of state_cast<>()
+and can only be used when the passed type is a most-derived type.
+state_cast<>() should only be used if you want to query an additional
+base.
+Custom state queries
+It is often desirable to find out exactly which state(s) a machine
+currently resides in. To some extent this is already possible with
+state_cast<>() and state_downcast<>() but their utility is
+rather limited because both only return a yes/no answer to the question "Are
+you in state X?". It is possible to ask more sophisticated questions when you
+pass an additional base class rather than a state class to state_cast<>()
+but this involves more work (all states need to derive from and implement the
+additional base), is slow (under the hood state_cast<>() uses
+dynamic_cast), forces projects to compile with C++ RTTI turned on
+and has a negative impact on state entry/exit speed.
+Especially for debugging it would be so much more useful being able to ask
+"In which state(s) are you?". For this purpose it is possible to iterate over
+all active innermost states with state_machine::state_begin()
+and state_machine::state_end(). Dereferencing the returned
+iterator returns a reference to const state_machine::state_base_type,
+the common base of all states. We can thus print the currently active state
+configuration as follows (see the Keyboard example for the complete code):
+void DisplayStateConfiguration( const Keyboard & kbd )
+{
+ char region = 'a';
+
+ for (
+ Keyboard::state_iterator pLeafState = kbd.state_begin();
+ pLeafState != kbd.state_end(); ++pLeafState )
+ {
+ std::cout << "Orthogonal region " << region << ": ";
+ std::cout << typeid( *pLeafState ).name() << "\n";
+ ++region;
+ }
+}
+If necessary, the outer states can be accessed with
+state_machine::state_base_type::outer_state_ptr(), which returns a
+pointer to const state_machine::state_base_type. When called on
+an outermost state this function simply returns 0.
+State type information
+To cut down on executable size some applications must be compiled with C++
+RTTI turned off. This would render the ability to iterate over all active
+states pretty much useless if it weren't for the following two functions:
+
+ static unspecified_type simple_state::static_type()
+ unspecified_type
+ state_machine::state_base_type::dynamic_type() const
+
+Both return a value that is comparable via operator==() and
+std::less. This alone would be enough to implement the
+DisplayStateConfiguration() function above without the help of
+typeid but it is still somewhat cumbersome as a map must be used to
+associate the type information values with the state names.
+Custom state type information
+That's why the following functions are also provided (only available when
+
+BOOST_FSM_USE_NATIVE_RTTI is not defined):
+
+ template< class T >
+ static void simple_state::custom_static_type_ptr( const T * );
+ template< class T >
+ static const T * simple_state::custom_static_type_ptr();
+ template< class T >
+ const T * state_machine::
+ state_base_type::custom_dynamic_type_ptr() const;
+
+These allow us to directly associate arbitrary state type information with
+each state ...
+// ...
+
+int main()
+{
+ NumLockOn::custom_static_type_ptr( "NumLockOn" );
+ NumLockOff::custom_static_type_ptr( "NumLockOff" );
+ CapsLockOn::custom_static_type_ptr( "CapsLockOn" );
+ CapsLockOff::custom_static_type_ptr( "CapsLockOff" );
+ ScrollLockOn::custom_static_type_ptr( "ScrollLockOn" );
+ ScrollLockOff::custom_static_type_ptr( "ScrollLockOff" );
+
+ // ...
+}
+... and rewrite the display function as follows:
+void DisplayStateConfiguration( const Keyboard & kbd )
+{
+ char region = 'a';
+
+ for (
+ Keyboard::state_iterator pLeafState = kbd.state_begin();
+ pLeafState != kbd.state_end(); ++pLeafState )
+ {
+ std::cout << "Orthogonal region " << region << ": ";
+ std::cout <<
+ pLeafState->custom_dynamic_type_ptr< char >() << "\n";
+ ++region;
+ }
+}
Exception handling
Exceptions can be propagated from all user code except from state exit
actions (mapped to destructors and destructors should virtually never throw in
@@ -1115,12 +1242,12 @@ struct Off : fsm::simple_state<
Asynchronous state machines
Why asynchronous state machines are necessary
As the name suggests, a synchronous state machine processes each event
-synchronously. This behavior is implemented by the state_machine<>
+synchronously. This behavior is implemented by the state_machine
class template, whose process_event() only returns after having
executed all reactions (including the ones provoked by internal events that
actions might have posted). Moreover, this function is also strictly
-non-reentrant (just like all other member functions, so state_machine<>
-is not thread-safe). This makes it difficult for two state_machine<>
+non-reentrant (just like all other member functions, so state_machine
+is not thread-safe). This makes it difficult for two state_machine
subclasses to communicate via events in a bi-directional fashion correctly,
even in a single-threaded program. For example, state machine A
is in the middle of processing an external event. Inside an action, it decides
@@ -1134,20 +1261,20 @@ external event and as soon as B answers via the call-back,
A::process_event is unavoidably reentered. This all really
happens in a single thread, that's why "wait" is in quotes.
How it works
-In contrast to state_machine<>,
-asynchronous_state_machine<> does not have a member function
-process_event(). Instead, there is only queue_event(),
-which returns immediately after pushing the event into a queue. A worker
-thread will later pop the event out of the queue to have it processed. For
-applications using the boost::thread library, the necessary locking, unlocking
-and waiting logic is readily available in class worker<>.
-Applications will usually first create a worker<> object and
-then create one or more asynchronous_state_machine<> subclass
+
In contrast to state_machine, asynchronous_state_machine
+does not have a member function process_event(). Instead, there
+is only queue_event(), which returns immediately after pushing
+the event into a queue. A worker thread will later pop the event out of the
+queue to have it processed. For applications using the boost::thread library,
+the necessary locking, unlocking and waiting logic is readily available in
+class worker.
+Applications will usually first create a worker object and
+then create one or more asynchronous_state_machine subclass
objects, passing the worker object to the constructor(s). Finally,
worker<>::operator()() is either called directly to let the machine(s)
run in the current thread, or, a boost::function object
referencing operator() is passed to a new boost::thread.
-I the following code, we are running one state machine in a new boost::thread
+In the following code, we are running one state machine in a new boost::thread
and the other in the main thread (see the PingPong example for the full source
code):
// ...
@@ -1231,9 +1358,9 @@ exceptions that machines fail to handle. In this case all machines are
terminated before the exception is propagated.
Caution:
- asynchronous_state_machine<> subclass objects must not
- be destructed before worker::operator()() returns. Moreover,
- the worker<> object may be destructed only after all of the
+ asynchronous_state_machine subclass objects must not be
+ destructed before worker::operator()() returns. Moreover, the
+ worker object may be destructed only after all of the
registered state machines have been destructed. Violations of these rules
will result in failing runtime asserts.
- The interface of
asynchronous_state_machine consists of
@@ -1241,13 +1368,13 @@ terminated before the exception is propagated.
other functions like initiate(), process_event(),
etc. are nevertheless also publicly available, but it is not safe to call
these functions from any other thread than the worker (over which most users
- have no control). asynchronous_state_machine<>::queue_event()
- is the only function than can safely be called simultaneously from multiple
- threads.
+ have no control).
+ asynchronous_state_machine<>::queue_event() is the only function than
+ can safely be called simultaneously from multiple threads.
Revised
-12 October, 2003
+12 December, 2003
Copyright © 2003 Andreas Huber Dönni.
All Rights Reserved.
diff --git a/doc/tutorial.pdf b/doc/tutorial.pdf
index 373f1e6..e3cc896 100644
Binary files a/doc/tutorial.pdf and b/doc/tutorial.pdf differ
diff --git a/example/BitMachine/BitMachine.cpp b/example/BitMachine/BitMachine.cpp
index da70a69..ea1565e 100644
--- a/example/BitMachine/BitMachine.cpp
+++ b/example/BitMachine/BitMachine.cpp
@@ -10,7 +10,7 @@
//////////////////////////////////////////////////////////////////////////////
const unsigned int noOfBits = 6;
-// #define CUSTOMIZE_MEMORY_MANAGEMENT
+#define CUSTOMIZE_MEMORY_MANAGEMENT
// #define BOOST_FSM_USE_NATIVE_RTTI
//////////////////////////////////////////////////////////////////////////////
// This program demonstrates the fact that measures must be taken to hide some
diff --git a/example/BitMachine/BitMachine.vcproj b/example/BitMachine/BitMachine.vcproj
index b0f4c03..72b85c7 100644
--- a/example/BitMachine/BitMachine.vcproj
+++ b/example/BitMachine/BitMachine.vcproj
@@ -81,6 +81,7 @@
AdditionalIncludeDirectories=""..\..\..\..\..\boost-sandbox";"..\..\..\..\..\boost-1.30.2""
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
StringPooling="TRUE"
+ ExceptionHandling="TRUE"
RuntimeLibrary="4"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="TRUE"
diff --git a/example/Keyboard/Keyboard.cpp b/example/Keyboard/Keyboard.cpp
index c6072bb..87349ab 100644
--- a/example/Keyboard/Keyboard.cpp
+++ b/example/Keyboard/Keyboard.cpp
@@ -11,8 +11,9 @@
//////////////////////////////////////////////////////////////////////////////
// The following example program demonstrates the use of orthogonal states and
// state_downcast to query the state of orthogonal regions.
+// Moreover, the use of the state type information interface is also shown.
//////////////////////////////////////////////////////////////////////////////
-
+// #define BOOST_FSM_USE_NATIVE_RTTI
#include
@@ -24,6 +25,7 @@
#include
#include
+#include
namespace fsm = boost::fsm;
namespace mpl = boost::mpl;
@@ -45,16 +47,6 @@ struct Active: fsm::simple_state<
Active, Keyboard, fsm::custom_reaction< EvRequestShutdown >,
mpl::list< NumLockOff, CapsLockOff, ScrollLockOff > >
{
- Active()
- {
- std::cout << "Entering Active\n";
- }
-
- ~Active()
- {
- std::cout << "Exiting Active\n";
- }
-
fsm::result react( const EvRequestShutdown & )
{
if ( ( state_downcast< const NumLockOff * >() != 0 ) &&
@@ -66,7 +58,7 @@ struct Active: fsm::simple_state<
}
else
{
- std::cout << "Ignoring shutdown request\n";
+ std::cout << "Ignoring shutdown request\n\n";
return discard_event();
}
}
@@ -74,82 +66,99 @@ struct Active: fsm::simple_state<
struct NumLockOn : fsm::simple_state<
NumLockOn, Active::orthogonal< 0 >,
- fsm::transition< EvNumLockPressed, NumLockOff > >
-{
- NumLockOn()
- {
- std::cout << "NumLockOn\n";
- }
-};
+ fsm::transition< EvNumLockPressed, NumLockOff > > {};
struct NumLockOff : fsm::simple_state<
NumLockOff, Active::orthogonal< 0 >,
- fsm::transition< EvNumLockPressed, NumLockOn > >
-{
- NumLockOff()
- {
- std::cout << "NumLockOff\n";
- }
-};
+ fsm::transition< EvNumLockPressed, NumLockOn > > {};
struct CapsLockOn : fsm::simple_state<
CapsLockOn, Active::orthogonal< 1 >,
- fsm::transition< EvCapsLockPressed, CapsLockOff > >
-{
- CapsLockOn()
- {
- std::cout << "CapsLockOn\n";
- }
-};
+ fsm::transition< EvCapsLockPressed, CapsLockOff > > {};
struct CapsLockOff : fsm::simple_state<
CapsLockOff, Active::orthogonal< 1 >,
- fsm::transition< EvCapsLockPressed, CapsLockOn > >
-{
- CapsLockOff()
- {
- std::cout << "CapsLockOff\n";
- }
-};
+ fsm::transition< EvCapsLockPressed, CapsLockOn > > {};
struct ScrollLockOn : fsm::simple_state<
ScrollLockOn, Active::orthogonal< 2 >,
- fsm::transition< EvScrollLockPressed, ScrollLockOff > >
-{
- ScrollLockOn()
- {
- std::cout << "ScrollLockOn\n";
- }
-};
+ fsm::transition< EvScrollLockPressed, ScrollLockOff > > {};
struct ScrollLockOff : fsm::simple_state<
ScrollLockOff, Active::orthogonal< 2 >,
- fsm::transition< EvScrollLockPressed, ScrollLockOn > >
+ fsm::transition< EvScrollLockPressed, ScrollLockOn > > {};
+
+
+void DisplayStateConfiguration( const Keyboard & keyboard )
{
- ScrollLockOff()
+ char orthogonalRegion = 'a';
+
+ for ( Keyboard::state_iterator pLeafState = keyboard.state_begin();
+ pLeafState != keyboard.state_end(); ++pLeafState )
{
- std::cout << "ScrollLockOff\n";
+ std::cout << "Orthogonal region " << orthogonalRegion << ": ";
+
+ const Keyboard::state_base_type * pState = &*pLeafState;
+
+ while ( pState != 0 )
+ {
+ if ( pState != &*pLeafState )
+ {
+ std::cout << " -> ";
+ }
+
+ #ifdef BOOST_FSM_USE_NATIVE_RTTI
+ std::cout << std::setw( 15 ) << typeid( *pState ).name();
+ #else
+ std::cout << std::setw( 15 ) <<
+ pState->custom_dynamic_type_ptr< char >();
+ #endif
+ pState = pState->outer_state_ptr();
+ }
+
+ std::cout << "\n";
+ ++orthogonalRegion;
}
-};
+
+ std::cout << "\n";
+}
+
int main()
{
+ #ifndef BOOST_FSM_USE_NATIVE_RTTI
+ Active::custom_static_type_ptr( "Active" );
+ NumLockOn::custom_static_type_ptr( "NumLockOn" );
+ NumLockOff::custom_static_type_ptr( "NumLockOff" );
+ CapsLockOn::custom_static_type_ptr( "CapsLockOn" );
+ CapsLockOff::custom_static_type_ptr( "CapsLockOff" );
+ ScrollLockOn::custom_static_type_ptr( "ScrollLockOn" );
+ ScrollLockOff::custom_static_type_ptr( "ScrollLockOff" );
+ #endif
+
std::cout << "boost::fsm Keyboard example\n\n";
Keyboard keyboard;
keyboard.initiate();
+ DisplayStateConfiguration( keyboard );
keyboard.process_event( EvNumLockPressed() );
+ DisplayStateConfiguration( keyboard );
keyboard.process_event( EvRequestShutdown() );
keyboard.process_event( EvCapsLockPressed() );
+ DisplayStateConfiguration( keyboard );
keyboard.process_event( EvRequestShutdown() );
keyboard.process_event( EvScrollLockPressed() );
+ DisplayStateConfiguration( keyboard );
keyboard.process_event( EvRequestShutdown() );
keyboard.process_event( EvNumLockPressed() );
+ DisplayStateConfiguration( keyboard );
keyboard.process_event( EvRequestShutdown() );
keyboard.process_event( EvCapsLockPressed() );
+ DisplayStateConfiguration( keyboard );
keyboard.process_event( EvRequestShutdown() );
keyboard.process_event( EvScrollLockPressed() );
+ DisplayStateConfiguration( keyboard );
keyboard.process_event( EvRequestShutdown() );
return 0;
diff --git a/example/Keyboard/Keyboard.vcproj b/example/Keyboard/Keyboard.vcproj
index 0477573..5cc7efb 100644
--- a/example/Keyboard/Keyboard.vcproj
+++ b/example/Keyboard/Keyboard.vcproj
@@ -87,6 +87,7 @@
DisableLanguageExtensions="TRUE"
TreatWChar_tAsBuiltInType="TRUE"
ForceConformanceInForLoopScope="TRUE"
+ RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="TRUE"
@@ -151,6 +152,9 @@
+
+
diff --git a/example/PingPong/PingPong.vcproj b/example/PingPong/PingPong.vcproj
index 7e9e52c..4844aef 100644
--- a/example/PingPong/PingPong.vcproj
+++ b/example/PingPong/PingPong.vcproj
@@ -160,9 +160,6 @@
-
-
diff --git a/example/StopWatch/StopWatch.vcproj b/example/StopWatch/StopWatch.vcproj
index fda40c8..7eb8a05 100644
--- a/example/StopWatch/StopWatch.vcproj
+++ b/example/StopWatch/StopWatch.vcproj
@@ -158,9 +158,6 @@
-
-
diff --git a/include/boost/statechart/asynchronous_state_machine.hpp b/include/boost/statechart/asynchronous_state_machine.hpp
index fc84011..3188e04 100644
--- a/include/boost/statechart/asynchronous_state_machine.hpp
+++ b/include/boost/statechart/asynchronous_state_machine.hpp
@@ -38,13 +38,15 @@ class asynchronous_state_machine : public state_machine<
typedef state_machine< MostDerived,
InitialState, Allocator, ExceptionTranslator > machine_base;
typedef detail::event_processor< Worker > processor_base;
- public:
+ protected:
//////////////////////////////////////////////////////////////////////////
asynchronous_state_machine( Worker & myWorker ) :
processor_base( myWorker )
{
}
+ virtual ~asynchronous_state_machine() {}
+
public:
//////////////////////////////////////////////////////////////////////////
// The following declarations should be private.
diff --git a/include/boost/statechart/detail/counted_base.hpp b/include/boost/statechart/detail/counted_base.hpp
index 5209434..89f6d1b 100644
--- a/include/boost/statechart/detail/counted_base.hpp
+++ b/include/boost/statechart/detail/counted_base.hpp
@@ -48,8 +48,6 @@ class counted_base : private locked_base< NeedsLocking >
typedef locked_base< NeedsLocking > base_type;
public:
//////////////////////////////////////////////////////////////////////////
- virtual ~counted_base() {}
-
bool ref_counted() const
{
return count_ != 0;
@@ -58,6 +56,7 @@ class counted_base : private locked_base< NeedsLocking >
protected:
//////////////////////////////////////////////////////////////////////////
counted_base() : count_( 0 ) {}
+ virtual ~counted_base() {}
// do nothing copy implementation is intentional (the number of
// referencing pointers of the source and the destination is not changed
diff --git a/include/boost/statechart/detail/leaf_state.hpp b/include/boost/statechart/detail/leaf_state.hpp
index 97ef4fd..da8f83d 100644
--- a/include/boost/statechart/detail/leaf_state.hpp
+++ b/include/boost/statechart/detail/leaf_state.hpp
@@ -30,7 +30,14 @@ class leaf_state : public state_base< Allocator, RttiPolicy >
typedef state_base< Allocator, RttiPolicy > base_type;
protected:
//////////////////////////////////////////////////////////////////////////
- leaf_state( typename RttiPolicy::id_type id ) : base_type( id ) {}
+ leaf_state(
+ typename RttiPolicy::id_provider_type idProvider
+ ) :
+ base_type( idProvider )
+ {
+ }
+
+ virtual ~leaf_state() {}
public:
//////////////////////////////////////////////////////////////////////////
diff --git a/include/boost/statechart/detail/node_state.hpp b/include/boost/statechart/detail/node_state.hpp
index f477f51..c4a1b9b 100644
--- a/include/boost/statechart/detail/node_state.hpp
+++ b/include/boost/statechart/detail/node_state.hpp
@@ -33,7 +33,10 @@ class node_state : public state_base< Allocator, RttiPolicy >
typedef state_base< Allocator, RttiPolicy > base_type;
protected:
//////////////////////////////////////////////////////////////////////////
- node_state( typename RttiPolicy::id_type id ) : base_type( id )
+ node_state(
+ typename RttiPolicy::id_provider_type idProvider
+ ) :
+ base_type( idProvider )
{
for ( orthogonal_position_type pos = 0;
pos < noOfOrthogonalRegions; ++pos )
@@ -42,6 +45,8 @@ class node_state : public state_base< Allocator, RttiPolicy >
}
}
+ virtual ~node_state() {}
+
public:
//////////////////////////////////////////////////////////////////////////
// The following declarations should be private.
diff --git a/include/boost/statechart/detail/rtti_policy.hpp b/include/boost/statechart/detail/rtti_policy.hpp
index 9ae1b81..915ca9d 100644
--- a/include/boost/statechart/detail/rtti_policy.hpp
+++ b/include/boost/statechart/detail/rtti_policy.hpp
@@ -11,6 +11,7 @@
#include
+#include
#include // std::type_info
@@ -34,28 +35,24 @@ namespace detail
-// #define BOOST_FSM_USE_NATIVE_RTTI
-
-#ifndef BOOST_FSM_USE_NATIVE_RTTI
//////////////////////////////////////////////////////////////////////////////
-template< class MostDerived >
struct id_provider
{
- static bool dummy_;
+ const void * pCustomId_;
+ #if defined( BOOST_ENABLE_ASSERT_HANDLER ) || defined( _DEBUG )
+ const std::type_info * pCustomIdType_;
+ #endif
};
-template< class MostDerived >
-bool id_provider< MostDerived >::dummy_;
-
template< class MostDerived >
struct id_holder
{
- static void * pId_;
+ static id_provider idProvider_;
};
template< class MostDerived >
-void * id_holder< MostDerived >::pId_ = &id_provider< MostDerived >::dummy_;
-#endif
+id_provider id_holder< MostDerived >::idProvider_;
+
//////////////////////////////////////////////////////////////////////////////
@@ -66,40 +63,31 @@ struct rtti_policy
{
public:
////////////////////////////////////////////////////////////////////////
- id_type( const std::type_info & id ) : id_( id ) {}
+ explicit id_type( const std::type_info & id ) : id_( id ) {}
- friend bool operator==( id_type left, id_type right )
+ bool operator==( id_type right ) const
{
- return left.id_ == right.id_ != 0;
- }
- friend bool operator!=( id_type left, id_type right )
- {
- return !( left == right );
+ return id_ == right.id_ != 0;
}
+ bool operator!=( id_type right ) const { return !( *this == right ); }
- friend bool operator<( id_type left, id_type right )
+ bool operator<( id_type right ) const
{
- return left.id_.before( right.id_ ) != 0;
- }
- friend bool operator>( id_type left, id_type right )
- {
- return right < left;
- }
- friend bool operator>=( id_type left, id_type right )
- {
- return !( left < right );
- }
- friend bool operator<=( id_type left, id_type right )
- {
- return !( right < left );
+ return id_.before( right.id_ ) != 0;
}
+ bool operator>( id_type right ) const { return right < *this; }
+ bool operator>=( id_type right ) const { return !( *this < right ); }
+ bool operator<=( id_type right ) const { return !( right < *this ); }
private:
////////////////////////////////////////////////////////////////////////
const std::type_info & id_;
};
+
+ typedef bool id_provider_type; // dummy
#else
- typedef void * id_type;
+ typedef const void * id_type;
+ typedef const id_provider & id_provider_type;
#endif
////////////////////////////////////////////////////////////////////////////
@@ -111,22 +99,40 @@ struct rtti_policy
id_type dynamic_type() const
{
#ifdef BOOST_FSM_USE_NATIVE_RTTI
- return typeid( *this );
+ return id_type( typeid( *this ) );
#else
- return id_;
+ return &idProvider_;
#endif
}
+ #ifndef BOOST_FSM_USE_NATIVE_RTTI
+ template< typename CustomId >
+ const CustomId * custom_dynamic_type_ptr() const
+ {
+ BOOST_ASSERT(
+ ( idProvider_.pCustomIdType_ == 0 ) ||
+ ( *idProvider_.pCustomIdType_ == typeid( CustomId ) ) );
+ return static_cast< const CustomId * >( idProvider_.pCustomId_ );
+ }
+ #endif
+
protected:
////////////////////////////////////////////////////////////////////////
+ virtual ~base_type() {}
+
#ifdef BOOST_FSM_USE_NATIVE_RTTI
- base_type( id_type ) {}
+ base_type( id_provider_type ) {}
#else
- base_type( id_type id ) : id_( id ) {}
+ base_type(
+ id_provider_type idProvider
+ ) :
+ idProvider_( idProvider )
+ {
+ }
private:
////////////////////////////////////////////////////////////////////////
- const id_type id_;
+ id_provider_type idProvider_;
#endif
};
@@ -139,15 +145,44 @@ struct rtti_policy
static id_type static_type()
{
#ifdef BOOST_FSM_USE_NATIVE_RTTI
- return typeid( const MostDerived );
+ return id_type( typeid( const MostDerived ) );
#else
- return id_holder< MostDerived >::pId_;
+ return &id_holder< MostDerived >::idProvider_;
#endif
}
+ #ifndef BOOST_FSM_USE_NATIVE_RTTI
+ template< class CustomId >
+ static const CustomId * custom_static_type_ptr()
+ {
+ BOOST_ASSERT(
+ ( id_holder< MostDerived >::idProvider_.pCustomIdType_ == 0 ) ||
+ ( *id_holder< MostDerived >::idProvider_.pCustomIdType_ ==
+ typeid( CustomId ) ) );
+ return static_cast< const CustomId * >(
+ id_holder< MostDerived >::idProvider_.pCustomId_ );
+ }
+
+ template< class CustomId >
+ static void custom_static_type_ptr( const CustomId * pCustomId )
+ {
+ #if defined( BOOST_ENABLE_ASSERT_HANDLER ) || defined( _DEBUG )
+ id_holder< MostDerived >::idProvider_.pCustomIdType_ =
+ &typeid( CustomId );
+ #endif
+ id_holder< MostDerived >::idProvider_.pCustomId_ = pCustomId;
+ }
+ #endif
+
protected:
////////////////////////////////////////////////////////////////////////
- derived_type() : Base( static_type() ) {}
+ virtual ~derived_type() {}
+
+ #ifdef BOOST_FSM_USE_NATIVE_RTTI
+ derived_type() : Base( false ) {}
+ #else
+ derived_type() : Base( id_holder< MostDerived >::idProvider_ ) {}
+ #endif
};
};
diff --git a/include/boost/statechart/detail/state_base.hpp b/include/boost/statechart/detail/state_base.hpp
index a091cc9..ba9674f 100644
--- a/include/boost/statechart/detail/state_base.hpp
+++ b/include/boost/statechart/detail/state_base.hpp
@@ -64,19 +64,30 @@ class state_base : private noncopyable, public RttiPolicy::base_type<
{
typedef typename RttiPolicy::base_type<
counted_base< orthogonal_position_type, false > > base_type;
+
+ public:
+ //////////////////////////////////////////////////////////////////////////
+ // Returns a pointer to the immediate outer state _if_ there is one,
+ // returns 0 otherwise (this is the outermost state then)
+ virtual const state_base * outer_state_ptr() const = 0;
+
protected:
//////////////////////////////////////////////////////////////////////////
- // The following declarations should be private.
- // They are only protected because many compilers lack template friends.
- //////////////////////////////////////////////////////////////////////////
- state_base( typename RttiPolicy::id_type id ) :
- base_type( id ),
+ state_base( typename RttiPolicy::id_provider_type idProvider ) :
+ base_type( idProvider ),
reactionEnabled_( false ),
deferredEvents_( false ),
terminationState_( false )
{
}
+ virtual ~state_base() {}
+
+ protected:
+ //////////////////////////////////////////////////////////////////////////
+ // The following declarations should be private.
+ // They are only protected because many compilers lack template friends.
+ //////////////////////////////////////////////////////////////////////////
void enable_reaction()
{
reactionEnabled_ = true;
@@ -129,10 +140,6 @@ class state_base : private noncopyable, public RttiPolicy::base_type<
const event_base & evt,
typename RttiPolicy::id_type eventType ) = 0;
- // returns a pointer to the immediate outer state _if_ there is one,
- // returns 0 otherwise (this is the outermost state then)
- virtual state_base * outer_state_ptr() const = 0;
-
typedef intrusive_ptr< state_base > state_base_ptr_type;
typedef std::list<
state_base_ptr_type,
diff --git a/include/boost/statechart/event.hpp b/include/boost/statechart/event.hpp
index a2b0ab1..865a4fd 100644
--- a/include/boost/statechart/event.hpp
+++ b/include/boost/statechart/event.hpp
@@ -10,12 +10,8 @@
+#include
#include
-#include
-
-#include
-#include
-#include
@@ -26,29 +22,6 @@ namespace fsm
-//////////////////////////////////////////////////////////////////////////////
-class event_base : public detail::rtti_policy::base_type<
- detail::counted_base< unsigned int > >
-{
- typedef detail::rtti_policy::base_type<
- detail::counted_base< unsigned int > > base_type;
- public:
- //////////////////////////////////////////////////////////////////////////
- intrusive_ptr< const event_base > clone() const
- {
- BOOST_ASSERT( base_type::ref_counted() );
- return intrusive_ptr< const event_base >( this );
- }
-
- protected:
- //////////////////////////////////////////////////////////////////////////
- event_base( detail::rtti_policy::id_type id ) :
- base_type( id )
- {
- }
-};
-
-
//////////////////////////////////////////////////////////////////////////////
template< class MostDerived >
class event : public detail::rtti_policy::derived_type<
diff --git a/include/boost/statechart/event_base.hpp b/include/boost/statechart/event_base.hpp
new file mode 100644
index 0000000..1391a36
--- /dev/null
+++ b/include/boost/statechart/event_base.hpp
@@ -0,0 +1,57 @@
+#ifndef BOOST_FSM_EVENT_BASE_HPP_INCLUDED
+#define BOOST_FSM_EVENT_BASE_HPP_INCLUDED
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2002-2003 Andreas Huber Doenni, Switzerland
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+#include
+#include
+
+#include
+#include
+
+
+
+namespace boost
+{
+namespace fsm
+{
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+class event_base : public detail::rtti_policy::base_type<
+ detail::counted_base< unsigned int > >
+{
+ typedef detail::rtti_policy::base_type<
+ detail::counted_base< unsigned int > > base_type;
+ public:
+ //////////////////////////////////////////////////////////////////////////
+ intrusive_ptr< const event_base > clone() const
+ {
+ BOOST_ASSERT( base_type::ref_counted() );
+ return intrusive_ptr< const event_base >( this );
+ }
+
+ protected:
+ //////////////////////////////////////////////////////////////////////////
+ event_base( detail::rtti_policy::id_provider_type idProvider ) :
+ base_type( idProvider )
+ {
+ }
+};
+
+
+
+} // namespace fsm
+} // namespace boost
+
+
+
+#endif
diff --git a/include/boost/statechart/simple_state.hpp b/include/boost/statechart/simple_state.hpp
index 076c599..1b104c3 100644
--- a/include/boost/statechart/simple_state.hpp
+++ b/include/boost/statechart/simple_state.hpp
@@ -174,9 +174,9 @@ enum history_mode
//////////////////////////////////////////////////////////////////////////////
template< class MostDerived,
- class Context, // either an outer state or a state_machine
+ class Context,
class Reactions = no_reactions,
- class InnerInitial = detail::empty_list, // initial inner state
+ class InnerInitial = detail::empty_list,
history_mode historyMode = has_no_history >
class simple_state : public detail::simple_state_base_type< MostDerived,
typename Context::inner_context_type, InnerInitial >::type
@@ -188,19 +188,6 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
public:
//////////////////////////////////////////////////////////////////////////
typedef typename Context::inner_context_type context_type;
- BOOST_STATIC_CONSTANT(
- detail::orthogonal_position_type,
- orthogonal_position = Context::inner_orthogonal_position );
- typedef typename context_type::event_base_ptr_type event_base_ptr_type;
-
- // If you receive a
- // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE'" or similar
- // compiler error here then this state resides in a non-existent
- // orthogonal region of the outer state.
- BOOST_STATIC_ASSERT(
- orthogonal_position < context_type::no_of_orthogonal_regions );
-
- typedef simple_state my_base;
template< detail::orthogonal_position_type innerOrthogonalPosition >
struct orthogonal
@@ -211,10 +198,21 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
typedef MostDerived inner_context_type;
};
+ typedef typename context_type::outermost_context_type
+ outermost_context_type;
+
+ outermost_context_type & outermost_context()
+ {
+ BOOST_ASSERT( get_pointer( pContext_ ) != 0 );
+ return pContext_->outermost_context();
+ }
+
+ const outermost_context_type & outermost_context() const
+ {
+ BOOST_ASSERT( get_pointer( pContext_ ) != 0 );
+ return pContext_->outermost_context();
+ }
- // Returns a reference to the context identified by the template
- // parameter. This can either be _this_ object or one of its
- // direct or indirect contexts
template< class OtherContext >
OtherContext & context()
{
@@ -227,19 +225,12 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
return context_impl( static_cast< OtherContext * >( 0 ) );
}
- void post_event( const event_base_ptr_type & pEvent )
- {
- outermost_context().post_event( pEvent );
- }
-
- // see state_machine class for documentation
template< class Target >
Target state_cast() const
{
return outermost_context().template state_cast< Target >();
}
- // see state_machine class for documentation
template< class Target >
Target state_downcast() const
{
@@ -247,6 +238,13 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
}
+ typedef typename context_type::event_base_ptr_type event_base_ptr_type;
+
+ void post_event( const event_base_ptr_type & pEvent )
+ {
+ outermost_context().post_event( pEvent );
+ }
+
result discard_event()
{
state_base_type::reaction_initiated();
@@ -266,7 +264,6 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
return do_defer_event;
}
- // Initiates a transition to DestinationState (without transition action).
template< class DestinationState >
result transit()
{
@@ -274,9 +271,6 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
detail::no_transition_function() );
}
- // Initiates a transition to DestinationState with a transition action.
- // The transition action must be a member of the innermost common context
- // or of one of its contexts.
template< class DestinationState, class TransitionContext, class Event >
result transit(
void ( TransitionContext::*pTransitionAction )( const Event & ),
@@ -287,9 +281,6 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
pTransitionAction, evt ) );
}
- // Terminates this state. Depending on whether there are other orthogonal
- // states present this may or may not lead to the whole statemachine being
- // terminated.
result terminate()
{
state_base_type::reaction_initiated();
@@ -324,6 +315,17 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
// The following declarations should be private.
// They are only public because many compilers lack template friends.
//////////////////////////////////////////////////////////////////////////
+ BOOST_STATIC_CONSTANT(
+ detail::orthogonal_position_type,
+ orthogonal_position = Context::inner_orthogonal_position );
+
+ // If you receive a
+ // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE'" or similar
+ // compiler error here then this state resides in a non-existent
+ // orthogonal region of the outer state.
+ BOOST_STATIC_ASSERT(
+ orthogonal_position < context_type::no_of_orthogonal_regions );
+
typedef MostDerived inner_context_type;
BOOST_STATIC_CONSTANT(
detail::orthogonal_position_type,
@@ -393,29 +395,13 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
return reactionResult;
}
- virtual state_base_type * outer_state_ptr() const
+ virtual const state_base_type * outer_state_ptr() const
{
return outer_state_ptr_impl<
is_same< outermost_context_type, context_type >::value >();
}
- outermost_context_type & outermost_context()
- {
- BOOST_ASSERT( get_pointer( pContext_ ) != 0 );
- return pContext_->outermost_context();
- }
-
- const outermost_context_type & outermost_context() const
- {
- BOOST_ASSERT( get_pointer( pContext_ ) != 0 );
- return pContext_->outermost_context();
- }
-
-
- // Returns a pointer to the direct or indirect context identified by the
- // template parameter. In contrast to context(), this function cannot
- // return a pointer to this object.
template< class OtherContext >
const typename OtherContext::inner_context_ptr_type & context_ptr() const
{
@@ -423,20 +409,12 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
}
- // Given a outermost context (i.e. a state machine), constructs this state
- // with all its outer and inner initial states. Used for initial
- // construction only.
- // After each successful (non-throwing) construction the current state is
- // reported back to the state machine.
static void initial_deep_construct(
outermost_context_type & outermostContext )
{
deep_construct( &outermostContext, outermostContext );
}
- // Constructs this state with all its inner initial states.
- // After each successful (non-throwing) construction the current state is
- // reported back to the state machine.
static void deep_construct(
const context_ptr_type & pContext,
outermost_context_type & outermostContext )
@@ -593,9 +571,9 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
common_context_type, DestinationState >::type context_list_type;
// If you receive a
- // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE'" or similar
- // compiler error here then you tried to make an invalid transition
- // between different orthogonal regions.
+ // "use of undefined type 'boost::STATIC_ASSERTION_FAILURE'" or
+ // similar compiler error here then you tried to make an invalid
+ // transition between different orthogonal regions.
BOOST_STATIC_ASSERT(
termination_state_type::orthogonal_position ==
mpl::front< context_list_type >::type::orthogonal_position );
@@ -633,13 +611,13 @@ class simple_state : public detail::simple_state_base_type< MostDerived,
}
template< bool isOutermost >
- state_base_type * outer_state_ptr_impl() const
+ const state_base_type * outer_state_ptr_impl() const
{
return get_pointer( pContext_ );
}
template<>
- state_base_type * outer_state_ptr_impl< true >() const
+ const state_base_type * outer_state_ptr_impl< true >() const
{
return 0;
}
diff --git a/include/boost/statechart/state.hpp b/include/boost/statechart/state.hpp
index 7e1fbb3..1dd953a 100644
--- a/include/boost/statechart/state.hpp
+++ b/include/boost/statechart/state.hpp
@@ -22,9 +22,9 @@ namespace fsm
template< class MostDerived,
- class Context, // either an outer state or a state_machine
+ class Context,
class Reactions = no_reactions,
- class InnerInitial = detail::empty_list, // initial inner state
+ class InnerInitial = detail::empty_list,
history_mode historyMode = has_no_history >
class state : public simple_state<
MostDerived, Context, Reactions, InnerInitial, historyMode >
@@ -50,6 +50,8 @@ class state : public simple_state<
base_type::set_context( ctx.pContext_ );
}
+ virtual ~state() {}
+
public:
//////////////////////////////////////////////////////////////////////////
// The following declarations should be private.
diff --git a/include/boost/statechart/state_machine.hpp b/include/boost/statechart/state_machine.hpp
index b334358..e2809bd 100644
--- a/include/boost/statechart/state_machine.hpp
+++ b/include/boost/statechart/state_machine.hpp
@@ -42,6 +42,7 @@
#include // std::allocator
#include // std::bad_cast
#include // std::less
+#include
@@ -223,8 +224,6 @@ class history_key
//////////////////////////////////////////////////////////////////////////////
-// Base class for all state machines
-// Some function names were derived from a state machine by Aleksey Gurtovoy.
template< class MostDerived,
class InitialState,
class Allocator = std::allocator< void >,
@@ -238,9 +237,6 @@ class state_machine : noncopyable
typedef event_base event_base_type;
typedef intrusive_ptr< const event_base_type > event_base_ptr_type;
- // Initiates the state machine.
- // Returns true if the state machine terminated as a direct or indirect
- // result of entering the initial state.
bool initiate()
{
terminate();
@@ -263,9 +259,6 @@ class state_machine : noncopyable
return currentStates_.size() == 0;
}
- // Processes the passed event.
- // Returns true if the state machine was running before and terminated
- // after processing the event.
bool process_event( const event_base_type & evt )
{
const bool running = !terminated();
@@ -274,16 +267,6 @@ class state_machine : noncopyable
return terminated() && running;
}
- // Has semantics similar to dynamic_cast. Returns a pointer or a reference
- // to a state with the specified type _if_ the machine is currently in
- // such a state. Can _cross_ inheritance trees, e.g. if the machine is in
- // state A, which derives from simple_state _and_ B then
- // state_cast< const B & >() will return a reference to B and
- // state_cast< const A & >() will return a reference to A.
- // Target can take either of the following forms:
- // - const X &: throws std::bad_cast if the machine is not currently in
- // state X
- // - const X *: returns 0 if the machine is not currently in state X
template< class Target >
Target state_cast() const
{
@@ -324,18 +307,6 @@ class state_machine : noncopyable
return impl::not_found< Target >();
}
- // Typically much faster variant of state_cast. Returns a pointer or a
- // reference to a state with the specified type _if_ the machine is
- // currently in such a state.
- // Does _not_ cross inheritance trees, i.e. Target must be a most-derived
- // type, e.g. if the machine is in state A, which derives from
- // simple_state _and_ B then state_downcast< const B & >() will not
- // compile while state_downcast< const A & >() will return a reference to
- // A.
- // Target can take either of the following forms:
- // - const X &: throws std::bad_cast if the machine is not currently in
- // state X
- // - const X *: returns 0 if the machine is not currently in state X
template< class Target >
Target state_downcast() const
{
@@ -368,6 +339,55 @@ class state_machine : noncopyable
return impl::not_found< Target >();
}
+ typedef detail::state_base< allocator_type, rtti_policy_type >
+ state_base_type;
+
+ class state_iterator : public std::iterator<
+ std::forward_iterator_tag,
+ state_base_type, std::ptrdiff_t,
+ const state_base_type *, const state_base_type & >
+ {
+ public:
+ //////////////////////////////////////////////////////////////////////
+ explicit state_iterator(
+ state_base_type::state_list_type::const_iterator baseIterator
+ ) : baseIterator_( baseIterator ) {}
+
+ const state_base_type & operator*() const { return **baseIterator_; }
+ const state_base_type * operator->() const
+ {
+ return &**baseIterator_;
+ }
+
+ state_iterator & operator++() { ++baseIterator_; return *this; }
+ state_iterator operator++( int )
+ {
+ return state_iterator( baseIterator_++ );
+ }
+
+ bool operator==( const state_iterator & right ) const
+ {
+ return baseIterator_ == right.baseIterator_;
+ }
+ bool operator!=( const state_iterator & right ) const
+ {
+ return !( *this == right );
+ }
+
+ private:
+ state_base_type::state_list_type::const_iterator baseIterator_;
+ };
+
+ state_iterator state_begin() const
+ {
+ return state_iterator( currentStates_.begin() );
+ }
+
+ state_iterator state_end() const
+ {
+ return state_iterator( currentStates_.end() );
+ }
+
protected:
//////////////////////////////////////////////////////////////////////////
state_machine() :
@@ -375,7 +395,7 @@ class state_machine : noncopyable
{
}
- // This destructor was only made virtual, so that that
+ // This destructor was only made virtual so that that
// polymorphic_downcast can be used to cast to MostDerived.
virtual ~state_machine() {}
@@ -384,9 +404,6 @@ class state_machine : noncopyable
// The following declarations should be private.
// They are only public because many compilers lack template friends.
//////////////////////////////////////////////////////////////////////////
- typedef detail::state_base< allocator_type, rtti_policy_type >
- state_base_type;
-
typedef MostDerived inner_context_type;
BOOST_STATIC_CONSTANT(
detail::orthogonal_position_type,
diff --git a/include/boost/statechart/worker.hpp b/include/boost/statechart/worker.hpp
index bfae64e..b9c21f2 100644
--- a/include/boost/statechart/worker.hpp
+++ b/include/boost/statechart/worker.hpp
@@ -121,8 +121,7 @@ class worker : noncopyable
typedef detail::event_processor< worker > processor_type;
typedef std::list< processor_type *, Allocator > processor_list_type;
- typedef intrusive_ptr< const event_base >
- event_ptr_type;
+ typedef intrusive_ptr< const event_base > event_ptr_type;
typedef std::pair< processor_type *, event_ptr_type > queue_element;
typedef std::list< queue_element, Allocator > event_queue_type;