#include "fsm.h" #include /** States */ struct Idle { }; struct Active { std::uint32_t session_id = 0; }; /** Events */ struct EvStart { std::uint32_t requested_session = 0; }; struct EvStop { }; /** Context */ struct Context { std::uint32_t starts = 0; }; /** Names (optional) */ template <> struct name_of { static constexpr const char *value = "Idle"; }; template <> struct name_of { static constexpr const char *value = "Active"; }; template <> struct name_of { static constexpr const char *value = "EvStart"; }; template <> struct name_of { static constexpr const char *value = "EvStop"; }; /** Logger */ struct MyLogger { void ignored_transition (const char *from_state, const char *event) noexcept { (void)from_state; (void)event; // printf("FSM ignored: %s + %s\n", from_state, event); } void unhandled_transition (const char *from_state, const char *event) noexcept { (void)from_state; (void)event; // printf("FSM UNHANDLED: %s + %s\n", from_state, event); } void guard_blocked (const char *from_state, const char *event) noexcept { (void)from_state; (void)event; // printf("FSM guard blocked: %s + %s\n", from_state, event); } }; /** Guard */ struct GuardStartAllowed { bool operator() (Context &ctx, const Idle &, const EvStart &) const noexcept { return ctx.starts < 10U; } }; /** Action */ struct ActionOnStart { void operator() (Context &ctx, const Idle &, const Active &, const EvStart &) const noexcept { ++ctx.starts; } }; /** Factory specialization (NOTE: now includes Context in template parameters) */ template <> struct state_factory { static Active make (Context &, const Idle &, const EvStart &ev) { Active a{}; a.session_id = ev.requested_session; return a; } }; /** Hooks (optional) */ template <> struct on_entry_state { static void call (Context &, const Active &) noexcept { // start timers, etc. } }; template <> struct on_exit_state { static void call (Context &, const Active &) noexcept { // stop timers, etc. } }; template <> struct on_entry_event { static void call (Context &, const Active &, const EvStart &) noexcept { // entered Active due to EvStart } }; /** Transitions */ template <> struct transition { using type = transition_to; }; template <> struct transition { using type = transition_to; }; /** * "Adult strictness": mark only required pairs strict. * Everything else is ignore by default. */ template <> struct missing_transition { static constexpr missing_transition_policy policy = missing_transition_policy::strict; }; template <> struct missing_transition { static constexpr missing_transition_policy policy = missing_transition_policy::strict; }; /** FSM type */ using MyFsm = fsm; static constexpr void validate_fsm_contract() { MyFsm::validate_events(); } int main() { validate_fsm_contract(); Context ctx{}; MyFsm f (ctx, Idle{}, MyLogger{}); f.dispatch (EvStart{42}); // Idle -> Active f.dispatch (EvStop{}); // Active -> Idle // Not required by strict contract => default ignore (logged via ignored_transition) f.dispatch (EvStop{}); // Idle + EvStop => ignored f.dispatch (EvStart{7}); // (if currently Active) Active + EvStart => ignored return 0; }