// Overview / Examples / API / FAQ / Resources
- Single header (https://raw.githubusercontent.com/qlibs/sml/main/sml) / C++20 module (https://raw.githubusercontent.com/qlibs/sml/main/sml.cppm)
- Verifies itself upon include (can be disabled with -DNTEST- see FAQ)
- Optimized run-time execution, binary size, compilation-times (see performance)
- Minimal API
- 
C++20 (Clang-15+, GCC-12+) - No dependencies (no #include/#import)
- No virtualused (-fno-rtti)
- No exceptionsrequired (-fno-exceptions)
 
- No dependencies (no 
State Machine (https://godbolt.org/z/s9a6EW5j9)
// events
struct connect {};
struct established {};
struct ping { bool valid{}; };
struct disconnect {};
struct timeout {};
int main() {
  // guards/actions
  auto establish = [] { std::puts("establish"); };
  auto close     = [] { std::puts("close"); };
  auto reset     = [] { std::puts("reset"); };
  // states
  struct Disconnected {};
  struct Connecting {};
  struct Connected {};
  // transitions
  sml::sm connection = sml::overload{
    [](Disconnected, connect)      -> Connecting   { establish(); },
    [](Connecting,   established)  -> Connected    { },
    [](Connected,    ping event)                   { if (event.valid) { reset(); } },
    [](Connected,    timeout)      -> Connecting   { establish(); },
    [](Connected,    disconnect)   -> Disconnected { close(); },
  };
  static_assert(sizeof(connection) == 1u);
  assert(connection.visit(is<Disconnected>));
  assert(connection.process_event(connect{}));
  assert(connection.visit(is<Connecting>));
  assert(connection.process_event(established{}));
  assert(connection.visit(is<Connected>));
  assert(connection.process_event(ping{.valid = true}));
  assert(connection.visit(is<Connected>));
  assert(connection.process_event(disconnect{}));
  assert(connection.visit(is<Disconnected>));
}main: // $CXX -O3 -fno-exceptions -fno-rtti
  push    rax
  lea     rdi, [rip + .L.str.8]
  call    puts@PLT
  lea     rdi, [rip + .L.str.9]
  call    puts@PLT
  lea     rdi, [rip + .L.str.10]
  call    puts@PLT
  xor     eax, eax
  pop     rcx
  ret
.L.str.8:  .asciz  "establish"
.L.str.9:  .asciz  "reset"
.L.str.10: .asciz  "close"template<class T>
  requires (requires (T t) { t(); })
struct sm {
  constexpr sm(T&&);
  template<class TEvent, auto dispatch = if_else>
    requires dispatchable<TEvent>
  constexpr auto process_event(const TEvent& event) -> bool ;
  constexpr auto visit(auto&& fn) const;
};template<class... Ts> struct overload;
inline constexpr auto if_else; // if_else dispatch policy
inline constexpr auto jmp_table; // jmp_table dispatch policy
struct X {}; // terminate state
How to disable running tests at compile-time?
When
-DNTESTis defined static_asserts tests wont be executed upon include. Note: Use with caution as disabling tests means that there are no gurantees upon include that given compiler/env combination works as expected.
Similar projects? boost.msm, boost.statechart, boost-ext.sml
- UML-2.5.1 - https://www.omg.org/spec/UML/2.5.1
- Rise of the State Machines - https://www.youtube.com/watch?v=Zb6xcd2as6o