State Machine State Types#

A number of helper base classes for implementing states are provided. These are intended for simplifying typical obvious event processing cases and for allowing to easily implement the unique interface of event handlers always returning an Action.

template<typename Event, typename Action>
struct On#

Base type for states to facilitate implementation of handlers that simply return a default-constructed action of a certain type.

Example

  struct SpecialEvent {};
  struct SecondState : Will<ByDefault<DoNothing>> {};

  struct FirstState : Will<On<SpecialEvent, TransitionTo<SecondState>>> {};

  StateMachine<FirstState, SecondState> machine{FirstState{}, SecondState{}};

  machine.Handle(SpecialEvent{}); // TransitionTo AnotherState
  ASSERT_THAT(machine.IsIn<SecondState>(), IsTrue());
template<typename Action>
struct ByDefault#

Base type for states to facilitate specification of a default action.

States need to have handlers for all events that go through the state machine, even though they are really interested only in some specific events. For the rest of the events, either nothing is done or in some special cases a default action is returned. To make the implementation of states easier, this base type provides a straightforward way to express the default action for a state.

Example

  struct NotForMeEvent {};
  struct SpecialEvent {};
  struct SecondState : Will<ByDefault<DoNothing>> {};

  // If an event does not have a dedicated `Handle` overload, use the
  // `ByDefault` action (i.e. `DoNothing` in this case).
  struct FirstState : ByDefault<DoNothing> {
    // Bring in the `Handle` overloads from the `ByDefault` base type.
    using ByDefault::Handle;

    // A dedicated overload of `Handle` for the special event ensures
    // that it is not using the `ByDefault` action.
    static auto Handle(const SpecialEvent & /*event*/)
        -> TransitionTo<SecondState> {
      return TransitionTo<SecondState>{};
    }
  };

  StateMachine<FirstState, SecondState> machine{FirstState{}, SecondState{}};

  machine.Handle(NotForMeEvent{}); // DoNothing
  ASSERT_THAT(machine.IsIn<FirstState>(), IsTrue());

  machine.Handle(SpecialEvent{}); // TransitionTo AnotherState
  ASSERT_THAT(machine.IsIn<SecondState>(), IsTrue());
template<typename ...Handlers>
struct Will : public asap::fsm::Handlers#

Base type for states to automate pulling all handlers from all base classes.

Example

  struct EventOne {};
  struct EventTwo {};
  struct EventThree {};

  struct FirstState;
  struct SecondState;
  using Machine = StateMachine<FirstState, SecondState>;

  struct FirstState
      : Will<ByDefault<DoNothing>, On<EventOne, TransitionTo<SecondState>>> {};

  struct SpecialAction {
    static auto Execute(Machine & /*machine*/, SecondState & /*state*/,
        const EventTwo & /*event*/) -> Status {
      return Continue{};
    }
  };

  struct SecondState
      : Will<ByDefault<DoNothing>, On<EventThree, TransitionTo<FirstState>>> {
    using Will::Handle;

    // A dedicated overload of `Handle` for the special event ensures
    // that it is not using the `ByDefault` action.
    static auto Handle(const EventTwo & /*event*/) -> SpecialAction {
      return SpecialAction{};
    }
  };

  Machine machine{FirstState{}, SecondState{}};

  EXPECT_THAT(machine.IsIn<FirstState>(), IsTrue());
  machine.Handle(EventOne{});
  EXPECT_THAT(machine.IsIn<SecondState>(), IsTrue());
  machine.Handle(EventTwo{}); // SpecialAction `Execute` called
  EXPECT_THAT(machine.IsIn<SecondState>(), IsTrue());
  machine.Handle(EventThree{});
  EXPECT_THAT(machine.IsIn<FirstState>(), IsTrue());