Sml
C++14 State Machine library
Install / Use
/learn @boost-ext/SmlREADME
<a href="http://www.boost.org/LICENSE_1_0.txt" target="_blank"></a>
<a href="https://github.com/boost-ext/sml/releases" target="_blank">
</a>
<a href="https://github.com/boost-ext/sml/actions/workflows/build_matrix.yml" target="_blank">
</a>
<a href="https://codecov.io/gh/boost-ext/sml" target="_blank">
</a>
<a href="https://godbolt.org/z/y99L50">
</a>
SML (State Machine Language)
<p align="center"><a href="https://www.youtube.com/watch?v=Zb6xcd2as6o"><img src="doc/images/rise_of_the_state_machines.png" alt="Rise of the State Machines"/></a></p>Your scalable C++14 one header only State Machine Library with no dependencies
https://www.youtube.com/watch?v=Zb6xcd2as6o
<p align="center"> <br /> <b>Let's release a TCP connection!</b> <br /> </p> <p align="center"><img src="doc/images/tcp_release.png" alt="tcp release"/></p>
Quick start
Download
[Boost::ext].SML requires only one file. Get the latest header here!
Include
#include <boost/sml.hpp>
namespace sml = boost::sml;
Dependencies
struct sender {
template<class TMsg>
constexpr void send(const TMsg& msg) { std::printf("send: %d\n", msg.id); }
};
Events
struct ack { bool valid{}; };
struct fin { int id{}; bool valid{}; };
struct release {};
struct timeout {};
Guards
constexpr auto is_valid = [](const auto& event) { return event.valid; };
Actions
constexpr auto send_fin = [](sender& s) { s.send(fin{0}); };
constexpr auto send_ack = [](const auto& event, sender& s) { s.send(event); };
State Machine
struct tcp_release {
auto operator()() const {
using namespace sml;
/**
* Initial state: *initial_state
* Transition DSL: src_state + event [ guard ] / action = dst_state
*/
return make_transition_table(
*"established"_s + event<release> / send_fin = "fin wait 1"_s,
"fin wait 1"_s + event<ack> [ is_valid ] = "fin wait 2"_s,
"fin wait 2"_s + event<fin> [ is_valid ] / send_ack = "timed wait"_s,
"timed wait"_s + event<timeout> = X
);
}
};
Usage
int main() {
using namespace sml;
sender s{};
sm<tcp_release> sm{s}; // pass dependencies via ctor
assert(sm.is("established"_s));
sm.process_event(release{}); // complexity O(1)
assert(sm.is("fin wait 1"_s));
sm.process_event(ack{true}); // prints 'send: 0'
assert(sm.is("fin wait 2"_s));
sm.process_event(fin{42, true}); // prints 'send: 42'
assert(sm.is("timed wait"_s));
sm.process_event(timeout{});
assert(sm.is(X)); // terminated
}
MSVC-2015 (Example)
- use
state<class state_name>instead of"state_name"_s - expliclty state a lambda's result type
auto action = [] -> void {}
Compile
- GCC/Clang
$CXX -std=c++14 -O2 -fno-exceptions -Wall -Wextra -Werror -pedantic tcp_release.cpp - MSVC
cl /std:c++14 /Ox /W3 tcp_release.cpp
Run
Output (https://wandbox.org/permlink/WbvV9HsIyiPkCFw7)
send: 0
send: 42
Benchmark
| |Enum/Switch | Variant | [Boost::ext].SML - 1.1.0 | Boost-1.65.MSM-eUML | Boost-1.65.Statechart | |------------------|------------|---------|--------------|------------------|--------------------| | Compilation time | 0.132s | 15.321s | 0.582s | 1m15.935s | 5.671s | | Execution time | 679ms | 827ms | 622ms | 664ms | 2282ms | | Memory usage | 1b | 2b/8b | 1b | 120b | 224b | | Executable size | 15K | 187K | 34K | 611K | 211K |
Examples
<a name="arduino"></a>
<p align="center"><a href="http://www.plantuml.com/plantuml/uml/TP11Qy9048Nl-HNlPYnj4ZtcK4JheQtq4kX5HDRiRB9LTyFiXDH_twmM2WKl2n_xFjvZ5a4KIty-9PDaWfNlBcoRLf3MKyoBUO5tjW5lVR3gYFGOGGc-Rgozm95Ch-wB3SBsq0jfz4uJGrh2qliWgBoHGJ5XOsjoWHxnIHoiTvXbHJRAQKK4LTV-t2btiQw1iQSn_hfQVrJh_MnVPF8jy8nwd1Wdj29TcUV3C6I7s95vRl9_-JWCs3xiyFGCRqo2-5x10IMMuigoOmg1DBOtZ3yxvDYGZX0LXr__dcBCdn9h5kJqUD8V"><img src="doc/images/arduino/uml.png" alt="Arduino UML"/></a></p> <p align="center"><a href="https://godbolt.org/z/Y983h4"><img src="doc/images/arduino/code.png" alt="Arduino Code"/></a></p><p align="center"><a href="https://www.tinkercad.com/things/9epUrFrzKP3"><img src="doc/images/arduino/board.png" alt="Arduino Board"/></a></p>https://godbolt.org/z/Y983h4
https://www.tinkercad.com/things/9epUrFrzKP3
<a name="avr"></a>
<p align="center"><a href="https://godbolt.org/z/qhx8Md"><img src="doc/images/avr.png" alt="AVR performance"/></a></p>https://godbolt.org/z/qhx8Md
<a name="match3"></a>
<table> <tr> <td> <p align="center"><a href="https://www.youtube.com/watch?v=8gRHHIjx4oE"><img src="doc/images/match3.png" alt="match3"/></a></p> </td> <td> <p align="center"><a href="http://modern-cpp-examples.github.io/match3/"><img src="https://github.com/modern-cpp-examples/match3/raw/master/docs/images/match3.png" alt="match3"/></a></p> </td> </tr> </table>https://github.com/modern-cpp-examples/match3
Documentation
- Introduction
- Overview
- Features/Benchmarks
- Tutorial/Workshop
- 0. Read Boost.MSM - eUML documentation
- 1. Create events and states
- 2. Create guards and actions
- 3. Create a transition table
- 4. Set initial states
- [5. Create a state machine](https://boost-ext.github.io/sml/tutorial.html#5-c
