// Overview / Examples / API / FAQ
- Single header (https://raw.githubusercontent.com/qlibs/sml/main/sml - for integration see FAQ)
- 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
virtual
used (-fno-rtti
) - No
exceptions
required (-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 integrate with CMake.FetchContent?
include(FetchContent) FetchContent_Declare( qlibs.sml GIT_REPOSITORY https://github.com/qlibs/sml GIT_TAG v3.0.0 ) FetchContent_MakeAvailable(qlibs.sml)
target_link_libraries(${PROJECT_NAME} PUBLIC qlibs.sml);
-
Acknowledgments
-
Similar projects?