Skip to content

Commit

Permalink
Added support for single dispatch of events in a state.
Browse files Browse the repository at this point in the history
When specifying an event handler in a state it is now possible to set
a flag to ignore multiple instances of the same event beyond the first one.
  • Loading branch information
laszlo-kiss committed Feb 7, 2017
1 parent c188555 commit bda098e
Showing 1 changed file with 62 additions and 6 deletions.
68 changes: 62 additions & 6 deletions FSM/FiniteStateMachine.hh
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ namespace Core
: entry_function()
, exit_function()
, dispatch_table()
, single_dispatch()
{ }


Expand Down Expand Up @@ -266,18 +267,24 @@ namespace Core
*
* @param event The event that is to be handled.
* @param handler The handler function object to set.
* @param single_dispatch_only If the handler can only be executed once.
* @return The reference to this State object.
*/
virtual State & SetEventHandler(
const Event & event,
const EventHandler & handler
const EventHandler & handler,
bool single_dispatch_only = false
)
{
// Indicates that the event has already been configured in this
// state. A single event can't have multiple functions.
//
assert( transition_table.find( event ) == transition_table.end() );
dispatch_table.insert( { event, handler } );
if ( single_dispatch_only )
{
single_dispatch.insert( { event, nullptr } );
}
return *this;
}

Expand All @@ -296,6 +303,16 @@ namespace Core
)
{
EventHandler old_handler{};
auto sit = single_dispatch.find( event );
if ( sit != single_dispatch.end() )
{
if ( sit->second != nullptr )
{
std::swap( sit->second, old_handler );
single_dispatch[event] = handler;
return std::move( old_handler );
}
}
auto dit = dispatch_table.find( event );
if ( dit != dispatch_table.end() )
{
Expand Down Expand Up @@ -326,6 +343,15 @@ namespace Core
{
handler = dit->second;
}
auto sit = single_dispatch.find( event );
if ( sit != single_dispatch.end() )
{
if ( sit->second == nullptr )
{
sit->second = dit->second;
dit->second = [this]( const Event & ) { /* NOOP */ };
}
}
return std::move( handler );
}

Expand All @@ -344,7 +370,7 @@ namespace Core
* taking place and the state is becoming the previous state.
* @return The ExitFunction of the state.
*/
inline ExitFunction Exit() const { return exit_function; }
inline ExitFunction Exit() const { RestoreDispatchTable(); return exit_function; }


private :
Expand All @@ -353,6 +379,13 @@ namespace Core
///
using DispatchTable = std::map< Event, EventHandler >;

/// Those events that should be handled only once in this state
/// are entered here. Just the fact that an entry exists in this
/// table assures that event is a single dispatch event. On exit
/// the event dispatch is restored.
///
using SingleDispatch = std::map< Event, EventHandler >;

/// Describes what state transition to take when an event arrives for
/// the state. Note that the DispatchTable and the TransitionTable
/// are mutually exclusive (the same event can't be in both).
Expand All @@ -361,10 +394,29 @@ namespace Core


private :
EntryFunction entry_function;
ExitFunction exit_function;
DispatchTable dispatch_table;
TransitionTable transition_table;
EntryFunction entry_function;
ExitFunction exit_function;
mutable DispatchTable dispatch_table;
mutable SingleDispatch single_dispatch;
TransitionTable transition_table;


private :
/**
* For those events that are to be dispatched only once it restores
* the dispatch table so that it may handle the event again.
*/
void RestoreDispatchTable() const
{
for ( auto sit : single_dispatch )
{
if ( sit.second != nullptr )
{
dispatch_table[sit.first] = sit.second;
sit.second = nullptr;
}
}
}
};


Expand All @@ -374,6 +426,10 @@ namespace Core
///
static const StateID SentinelStateID{ -1 };

/// Convenience value to descriptively set the similarly named function
/// argument in SetEventHandler().
///
static const bool SingleDispatchOnly{ true };

public :
/**
Expand Down

0 comments on commit bda098e

Please sign in to comment.