Skip to content

Commit bda098e

Browse files
committed
Added support for single dispatch of events in a state.
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.
1 parent c188555 commit bda098e

File tree

1 file changed

+62
-6
lines changed

1 file changed

+62
-6
lines changed

FSM/FiniteStateMachine.hh

+62-6
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ namespace Core
129129
: entry_function()
130130
, exit_function()
131131
, dispatch_table()
132+
, single_dispatch()
132133
{ }
133134

134135

@@ -266,18 +267,24 @@ namespace Core
266267
*
267268
* @param event The event that is to be handled.
268269
* @param handler The handler function object to set.
270+
* @param single_dispatch_only If the handler can only be executed once.
269271
* @return The reference to this State object.
270272
*/
271273
virtual State & SetEventHandler(
272274
const Event & event,
273-
const EventHandler & handler
275+
const EventHandler & handler,
276+
bool single_dispatch_only = false
274277
)
275278
{
276279
// Indicates that the event has already been configured in this
277280
// state. A single event can't have multiple functions.
278281
//
279282
assert( transition_table.find( event ) == transition_table.end() );
280283
dispatch_table.insert( { event, handler } );
284+
if ( single_dispatch_only )
285+
{
286+
single_dispatch.insert( { event, nullptr } );
287+
}
281288
return *this;
282289
}
283290

@@ -296,6 +303,16 @@ namespace Core
296303
)
297304
{
298305
EventHandler old_handler{};
306+
auto sit = single_dispatch.find( event );
307+
if ( sit != single_dispatch.end() )
308+
{
309+
if ( sit->second != nullptr )
310+
{
311+
std::swap( sit->second, old_handler );
312+
single_dispatch[event] = handler;
313+
return std::move( old_handler );
314+
}
315+
}
299316
auto dit = dispatch_table.find( event );
300317
if ( dit != dispatch_table.end() )
301318
{
@@ -326,6 +343,15 @@ namespace Core
326343
{
327344
handler = dit->second;
328345
}
346+
auto sit = single_dispatch.find( event );
347+
if ( sit != single_dispatch.end() )
348+
{
349+
if ( sit->second == nullptr )
350+
{
351+
sit->second = dit->second;
352+
dit->second = [this]( const Event & ) { /* NOOP */ };
353+
}
354+
}
329355
return std::move( handler );
330356
}
331357

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

349375

350376
private :
@@ -353,6 +379,13 @@ namespace Core
353379
///
354380
using DispatchTable = std::map< Event, EventHandler >;
355381

382+
/// Those events that should be handled only once in this state
383+
/// are entered here. Just the fact that an entry exists in this
384+
/// table assures that event is a single dispatch event. On exit
385+
/// the event dispatch is restored.
386+
///
387+
using SingleDispatch = std::map< Event, EventHandler >;
388+
356389
/// Describes what state transition to take when an event arrives for
357390
/// the state. Note that the DispatchTable and the TransitionTable
358391
/// are mutually exclusive (the same event can't be in both).
@@ -361,10 +394,29 @@ namespace Core
361394

362395

363396
private :
364-
EntryFunction entry_function;
365-
ExitFunction exit_function;
366-
DispatchTable dispatch_table;
367-
TransitionTable transition_table;
397+
EntryFunction entry_function;
398+
ExitFunction exit_function;
399+
mutable DispatchTable dispatch_table;
400+
mutable SingleDispatch single_dispatch;
401+
TransitionTable transition_table;
402+
403+
404+
private :
405+
/**
406+
* For those events that are to be dispatched only once it restores
407+
* the dispatch table so that it may handle the event again.
408+
*/
409+
void RestoreDispatchTable() const
410+
{
411+
for ( auto sit : single_dispatch )
412+
{
413+
if ( sit.second != nullptr )
414+
{
415+
dispatch_table[sit.first] = sit.second;
416+
sit.second = nullptr;
417+
}
418+
}
419+
}
368420
};
369421

370422

@@ -374,6 +426,10 @@ namespace Core
374426
///
375427
static const StateID SentinelStateID{ -1 };
376428

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

378434
public :
379435
/**

0 commit comments

Comments
 (0)