boost-ext / sml

C++14 State Machine library
https://boost-ext.github.io/sml
Boost Software License 1.0
1.16k stars 179 forks source link
design-patterns metaprogramming sml state-machine

Boost Licence Version Linux Codecov Try it online


SML (State Machine Language)

Your scalable C++14 one header only State Machine Library with no dependencies

Rise of the State Machines

https://www.youtube.com/watch?v=Zb6xcd2as6o



Let's release a TCP connection!

tcp release

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)

Compile

tcp_release.cpp Clang-3.8 GCC-6.3 MSVC-2015
Compilation Time 0.102s 0.118s 0.296s
Binary size (stripped) 6.2kb 6.2kb 105kb
ASM x86-64 -
https://godbolt.org/z/y99L50

main: # @main
  pushq %rax
  movl $.L.str, %edi
  xorl %esi, %esi
  xorl %eax, %eax
  callq printf
  movl $.L.str, %edi
  movl $42, %esi
  xorl %eax, %eax
  callq printf
  xorl %eax, %eax
  popq %rcx
  retq
.L.str:
  .asciz "send: %d\n"
      

#### Run > Output (https://wandbox.org/permlink/WbvV9HsIyiPkCFw7) ```sh send: 0 send: 42 ``` ### Benchmark > [Complex Test](https://github.com/boost-ext/sml/tree/master/benchmark/complex) | |[Enum/Switch](https://github.com/boost-ext/sml/blob/master/benchmark/complex/switch.cpp) | [Variant](https://github.com/boost-ext/sml/blob/master/benchmark/complex/variant.cpp) | [[Boost::ext].SML - 1.1.0](https://github.com/boost-ext/sml/blob/master/benchmark/complex/sml.cpp) | [Boost-1.65.MSM-eUML](https://github.com/boost-ext/sml/blob/master/benchmark/complex/euml.cpp) | [Boost-1.65.Statechart](https://github.com/boost-ext/sml/blob/master/benchmark/complex/sc.cpp) | |------------------|------------|---------|--------------|------------------|--------------------| | **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 * #### [Arduino](https://www.arduino.cc)

Arduino UML

Arduino Code

> https://godbolt.org/z/Y983h4

Arduino Board

> https://www.tinkercad.com/things/9epUrFrzKP3 --- * #### [AVR](https://www.arduino.cc)

AVR performance

> https://godbolt.org/z/qhx8Md --- * #### [Match3](https://github.com/modern-cpp-examples/match3)

match3

match3

> https://github.com/modern-cpp-examples/match3 --------------------------------------- ### Documentation [](GENERATE_TOC_BEGIN) * [Introduction](https://boost-ext.github.io/sml/index.html) * [UML State Machine](https://boost-ext.github.io/sml/index.html#uml-state-machine) * [Do I need a State Machine?](https://boost-ext.github.io/sml/index.html#do-i-need-a-state-machine) * [Real Life examples?](https://boost-ext.github.io/sml/index.html#real-life-examples) * [Why [Boost].SML?](https://boost-ext.github.io/sml/index.html#why-boostsml) * [Problems with Boost.MSM - eUML](https://boost-ext.github.io/sml/index.html#problems-with-boostmsm-euml) * [[Boost].SML design goals](https://boost-ext.github.io/sml/index.html#boostsml-design-goals) * [What 'lite' implies?](https://boost-ext.github.io/sml/index.html#what-lite-implies) * [*Supported* UML features](https://boost-ext.github.io/sml/index.html#supported-uml-features) * [*Additional* features](https://boost-ext.github.io/sml/index.html#additional-features) * [Related materials](https://boost-ext.github.io/sml/index.html#related-materials) * [Acknowledgements](https://boost-ext.github.io/sml/index.html#acknowledgements) * [Overview](https://boost-ext.github.io/sml/overview.html) * [Quick Start](https://boost-ext.github.io/sml/overview.html#quick-start) * [Dependencies](https://boost-ext.github.io/sml/overview.html#dependencies) * [Supported/Tested compilers](https://boost-ext.github.io/sml/overview.html#supportedtested-compilers) * [Configuration](https://boost-ext.github.io/sml/overview.html#configuration) * [Exception Safety](https://boost-ext.github.io/sml/overview.html#exception-safety) * [Thread Safety](https://boost-ext.github.io/sml/overview.html#thread-safety) * [Design](https://boost-ext.github.io/sml/overview.html#design) * [Error messages](https://boost-ext.github.io/sml/overview.html#error-messages) * [Features/Benchmarks](https://boost-ext.github.io/sml/benchmarks.html) * [Features](https://boost-ext.github.io/sml/benchmarks.html#features) * [Benchmarks](https://boost-ext.github.io/sml/benchmarks.html#benchmarks) * [Tutorial/Workshop](https://boost-ext.github.io/sml/tutorial.html) * [0. Read Boost.MSM - eUML documentation](https://boost-ext.github.io/sml/tutorial.html#0-read-boostmsm-euml-documentation) * [1. Create events and states](https://boost-ext.github.io/sml/tutorial.html#1-create-events-and-states) * [2. Create guards and actions](https://boost-ext.github.io/sml/tutorial.html#2-create-guards-and-actions) * [3. Create a transition table](https://boost-ext.github.io/sml/tutorial.html#3-create-a-transition-table) * [4. Set initial states](https://boost-ext.github.io/sml/tutorial.html#4-set-initial-states) * [5. Create a state machine](https://boost-ext.github.io/sml/tutorial.html#5-create-a-state-machine) * [6. Process events](https://boost-ext.github.io/sml/tutorial.html#6-process-events) * [8. Handle errors](https://boost-ext.github.io/sml/tutorial.html#8-handle-errors) * [9. Test it](https://boost-ext.github.io/sml/tutorial.html#9-test-it) * [10. Debug it](https://boost-ext.github.io/sml/tutorial.html#10-debug-it) * [UML vs SML](https://boost-ext.github.io/sml/uml_vs_sml.html) * [Unified Modeling Language™ (UML®) Version 2.5](https://boost-ext.github.io/sml/uml_vs_sml.html#unified-modeling-language-uml-version-25) * [Initial Pseudostate](https://boost-ext.github.io/sml/uml_vs_sml.html#initial-pseudostate) * [Terminate Pseudostate](https://boost-ext.github.io/sml/uml_vs_sml.html#terminate-pseudostate) * [External transition](https://boost-ext.github.io/sml/uml_vs_sml.html#external-transition) * [Anonymous transition](https://boost-ext.github.io/sml/uml_vs_sml.html#anonymous-transition) * [User Guide](https://boost-ext.github.io/sml/user_guide.html) * [transitional [concept]](https://boost-ext.github.io/sml/user_guide.html#transitional-concept) * [configurable [concept]](https://boost-ext.github.io/sml/user_guide.html#configurable-concept) * [callable [concept]](https://boost-ext.github.io/sml/user_guide.html#callable-concept) * [dispatchable [concept]](https://boost-ext.github.io/sml/user_guide.html#dispatchable-concept) * [state [core]](https://boost-ext.github.io/sml/user_guide.html#state-core) * [event [core]](https://boost-ext.github.io/sml/user_guide.html#event-core) * [make_transition_table [state machine]](https://boost-ext.github.io/sml/user_guide.html#make_transition_table-state-machine) * [sm [state machine]](https://boost-ext.github.io/sml/user_guide.html#sm-state-machine) * [policies [state machine]](https://boost-ext.github.io/sml/user_guide.html#policies-state-machine) * [testing::sm [testing]](https://boost-ext.github.io/sml/user_guide.html#testingsm-testing) * [make_dispatch_table [utility]](https://boost-ext.github.io/sml/user_guide.html#make_dispatch_table-utility) * [Examples](https://boost-ext.github.io/sml/examples.html) * [Hello World](https://boost-ext.github.io/sml/examples.html#hello-world) * [Events](https://boost-ext.github.io/sml/examples.html#events) * [States](https://boost-ext.github.io/sml/examples.html#states) * [Actions Guards](https://boost-ext.github.io/sml/examples.html#actions-guards) * [Transitions](https://boost-ext.github.io/sml/examples.html#transitions) * [Defer/Process](https://boost-ext.github.io/sml/examples.html#deferprocess) * [Orthogonal Regions](https://boost-ext.github.io/sml/examples.html#orthogonal-regions) * [Composite](https://boost-ext.github.io/sml/examples.html#composite) * [History](https://boost-ext.github.io/sml/examples.html#history) * [Error handling](https://boost-ext.github.io/sml/examples.html#error-handling) * [Logging](https://boost-ext.github.io/sml/examples.html#logging) * [Nested](https://boost-ext.github.io/sml/examples.html#nested) * [Testing](https://boost-ext.github.io/sml/examples.html#testing) * [Runtime Dispatcher](https://boost-ext.github.io/sml/examples.html#runtime-dispatcher) * [eUML Emulation](https://boost-ext.github.io/sml/examples.html#euml-emulation) * [Dependencies](https://boost-ext.github.io/sml/examples.html#dependencies) * [Data](https://boost-ext.github.io/sml/examples.html#data) * [In-Place](https://boost-ext.github.io/sml/examples.html#in-place) * [Dependency Injection](https://boost-ext.github.io/sml/examples.html#dependency-injection) * [Arduino Integration](https://boost-ext.github.io/sml/examples.html#arduino-integration) * [SDL2 Integration](https://boost-ext.github.io/sml/examples.html#sdl2-integration) * [Plant UML Integration](https://boost-ext.github.io/sml/examples.html#plant-uml-integration) * [FAQ](https://boost-ext.github.io/sml/faq.html) * [CHANGELOG](https://boost-ext.github.io/sml/CHANGELOG.html) * [[1.1.11] - 2024-03-09](https://boost-ext.github.io/sml/CHANGELOG.html#1111-2024-03-09) * [[1.1.10] - 2024-03-09](https://boost-ext.github.io/sml/CHANGELOG.html#1110-2024-03-09) * [[1.1.9] - 2023-09-13](https://boost-ext.github.io/sml/CHANGELOG.html#119-2023-09-13) * [[1.1.6] - 2022-09-07](https://boost-ext.github.io/sml/CHANGELOG.html#116-2022-09-07) * [[1.1.5] - 2022-03-23](https://boost-ext.github.io/sml/CHANGELOG.html#115-2022-03-23) * [[1.1.4] - 2021-02-16](https://boost-ext.github.io/sml/CHANGELOG.html#114-2021-02-16) * [[1.1.3] - 2020-08-02](https://boost-ext.github.io/sml/CHANGELOG.html#113-2020-08-02) * [[1.1.2] - 2020-06-14](https://boost-ext.github.io/sml/CHANGELOG.html#112-2020-06-14) * [[1.1.1] - 2020-05-17](https://boost-ext.github.io/sml/CHANGELOG.html#111-2020-05-17) * [[1.1.0] - 2019-01-08](https://boost-ext.github.io/sml/CHANGELOG.html#110-2019-01-08) * [[1.0.1] - 2016-05-06](https://boost-ext.github.io/sml/CHANGELOG.html#101-2016-05-06) * [[1.0.0] - 2016-01-28](https://boost-ext.github.io/sml/CHANGELOG.html#100-2016-01-28) [](GENERATE_TOC_END) --- **Disclaimer** `[Boost::ext].SML` is not an official Boost library.