Template based fsm. Initial commit.
This commit is contained in:
148
templatefsm/main.cpp
Normal file
148
templatefsm/main.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user