Files

149 lines
3.5 KiB
C++

#include "fsm.h"
#include <cstdint>
/** 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<Idle> {
static constexpr const char *value = "Idle";
};
template <> struct name_of<Active> {
static constexpr const char *value = "Active";
};
template <> struct name_of<EvStart> {
static constexpr const char *value = "EvStart";
};
template <> struct name_of<EvStop> {
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<Context, Idle, EvStart, Active> {
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<Active> {
static void call (Context &, const Active &) noexcept {
// start timers, etc.
}
};
template <>
struct on_exit_state<Active> {
static void call (Context &, const Active &) noexcept {
// stop timers, etc.
}
};
template <>
struct on_entry_event<Active, EvStart> {
static void call (Context &, const Active &, const EvStart &) noexcept {
// entered Active due to EvStart
}
};
/** Transitions */
template <>
struct transition<Idle, EvStart> {
using type = transition_to<Active, GuardStartAllowed, ActionOnStart>;
};
template <>
struct transition<Active, EvStop> {
using type = transition_to<Idle>;
};
/**
* "Adult strictness": mark only required pairs strict.
* Everything else is ignore by default.
*/
template <>
struct missing_transition<Idle, EvStart> {
static constexpr missing_transition_policy policy = missing_transition_policy::strict;
};
template <>
struct missing_transition<Active, EvStop> {
static constexpr missing_transition_policy policy = missing_transition_policy::strict;
};
/** FSM type */
using MyFsm = fsm<Context, MyLogger, Idle, Active>;
static constexpr void validate_fsm_contract() {
MyFsm::validate_events<EvStart, EvStop>();
}
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;
}