yake::statemachine

:!: This document covers the use of yake::fsm2! It does not cover the deprecated code of Yake 0.4 and earlier!

Finite State Machine

Basics

yake::fsm implements a generic flexible state machine which allows runtime configuration. The latter is a requirement and therefore the reason that we did not take one of the existing compile-time state machine libraries (e.g. boost).

TODO Why didn't we choose a different runtime-configurable lib?

Tutorial

Getting started

Let's create a very simple state machine where states are identified by strings and events by integers.

typedef fsm::machine<std::string, int> machine_type;
 
machine_type m1;

Let's fill the machine with information: states and transitions. We keep it simple in this example so there'll be just a few of both types.

First, the states:

m1.addState("alive");
m1.addState("the_inevitable");

Now, the transitions in the form of (from, event, to):

const int kEvtAxe = 1; // We create a constant for easier reference later.
 
m1.addTransition("alive", kEvtAxe, "the_inevitable");

Initial state. Do we need to set it? By default, the machine sets the initial state to the 'null' state. For strings it's defined by a template specialization of fsm::get_null_state<state_type>() and is by default the string “null”.

We can either add the state to the machine and add a transition from “null” to “alive” or we simply set the initial state to “alive”. We do the latter in this example:

m1.setState("alive");

Let's make sure the current state is “alive”:

YAKE_ASSERT( m1.current() == "alive" ); // YAKE_ASSERT is a macro doing a check of the condition at runtime.
std::cout << m1.current(); // prints 'alive' to the console window.

Now let's transition between states by posting an event to the machine:

m1.processEvent( kEvtAxe );
 
std::cout << m1.current(); // now prints 'the_inevitable'

In the next part we discuss how to handle notifications of state changes.

Notifications / Callbacks

It is very easy to trigger callbacks when a state machine changes state.

Normally, you call the machine's member function processEvent(). If you want to do pre and/or post processing on successful state change, you can call processEventCb() with the 2nd and 3rd parameters being executable objects.

It can look like this:

typedef fsm::machine<std::string,int> machine_t; // state: string, event: int
 
void cout_op_enter(const machine_t&, const machine_t::state_type& state)
{
  std::cout << "enter state: " << state << "\n";
}
 
void cout_op_exit(const machine_t&, const machine_t::state_type& state)
{
  std::cout << "exit state: " << state << "\n";
}
 
m1.processEventCb( 12, cout_op_enter, cout_op_exit );

If event '12' results in a state change from “alive” to “dead” the output looks like this:

exit state: alive
enter state: dead

Or we could use a struct with operator():

typedef fsm::machine<std::string,int> machine_t; // state: string, event: int
 
struct cout_op
{
  cout_op( const std::string& prefix ) : prefix_(prefix) {}
  void operator(const machine_t&, const machine_t::state_type& state)
  {
    std::cout << prefix_ << ": " << state << "\n";
  }
private:
  std::string prefix_;
}
 
m1.processEventCb( 12, cout_op("enter state"), cout_op("exit state") );

If event '12' results in a state change from “alive” to “dead” the output looks like this:

exit state: alive
enter state: dead

The function machine::processEventCb<>() accepts any callbacks that implement operator()(…) (using the machine's types), e.g. it works with boost::function objects.

Complex types as states (e.g. structs)

Notification Provider

...

 
component/yappstatemachine.txt · Last modified: 2008/02/21 21:54 (external edit)
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki