The hana state machine (hsm) is a finite state machine library based on the boost hana meta programming library. It follows the principles of the boost msm and boost sml libraries, but tries to reduce own complex meta programming code to a minimum.
The following table compares features among popular c++ state machine libraries. A click on a particular feature check mark will forward to the feature documentation.
Feature | Hsm | Sml | Msm | Statechart |
---|---|---|---|---|
External transition | ✓ | ✓ | ✓ | ✓ |
Anonymous transition (Completion) | ✓ | ✓ | ✓ | ✗ |
Internal transition | ✓ | ✓ | ✓ | ✓ |
Direct transition | ✓ | ✗ | ✓ | ✗ |
Guards / actions | ✓ | ✓ | ✓ | ✓ |
Entry / exit actions | ✓ | ✓ | ✓ | ✓ |
Orthogonal regions | ✓ | ✓ | ✓ | ✓ |
Hierachies / sub state machines | ✓ | ✓ | ✓ | ✓ |
Event defering | ✓ | ✓ | ✓ | ✓ |
Transition logging | ✓ | ✓ | ✓ | ? |
Initial pseudo state | ✓ | ✓ | ✓ | ✓ |
History pseudo state | ✓ | ✓ | ✓ | ✓ |
eUml postfix frontend | ✓ | ✓ | ✓ | ✗ |
eUml prefix frontend | ✓ | ✓ | ✓ | ✗ |
Entry / exit pseudo state | ✓ | ✗ | ✓ | ✗ |
State data members | ✓ | ✓ | ✓ | ✓ |
Unexpected event / no transition handler | ✓ | ✗ | ✓ | ✗ |
Dependency injection | ✓ | ✓ | ✗ | ✗ |
Single amalgamation header | ✓ | ✓ | ✗ | ✗ |
- Try it online: https://godbolt.org/z/5eMzfv
#include "hsm/hsm.h"
#include <cassert>
// States
struct Locked {
};
struct Unlocked {
};
// Events
struct Push {
};
struct Coin {
};
// Guards
const auto noError = [](auto /*event*/, auto /*source*/, auto /*target*/){return true;};
// Actions
const auto beep = [](auto /*event*/, auto /*source*/, auto /*target*/){
std::cout << "beep!" << std::endl;
};
const auto blink = [](auto /*event*/, auto /*source*/, auto /*target*/){
std::cout << "blink, blink, blink!" << std::endl;
};
struct Turnstile {
static constexpr auto make_transition_table()
{
// clang-format off
return hsm::transition_table(
// Source + Event [Guard] / Action = Target
// +----------------------+---------------------+---------+--------+------------------------+
* hsm::state<Locked> {} + hsm::event<Push> {} / beep = hsm::state<Locked> {} ,
hsm::state<Locked> {} + hsm::event<Coin> {} [noError] / blink = hsm::state<Unlocked> {},
// +----------------------+---------------------+---------+--------+------------------------+
hsm::state<Unlocked> {} + hsm::event<Push> {} [noError] = hsm::state<Locked> {} ,
hsm::state<Unlocked> {} + hsm::event<Coin> {} / blink = hsm::state<Unlocked> {}
// +----------------------+---------------------+---------+--------+------------------------+
);
// clang-format on
}
};
int main()
{
hsm::sm<Turnstile> turnstileSm;
// The turnstile is initially locked
assert(turnstileSm.is(hsm::state<Locked> {}));
// Inserting a coin unlocks it
turnstileSm.process_event(Coin {});
assert(turnstileSm.is(hsm::state<Unlocked> {}));
// Entering the turnstile will lock it again
turnstileSm.process_event(Push {});
assert(turnstileSm.is(hsm::state<Locked> {}));
return 0;
}
The benchmark result are taken from the state machine benchmark repository.
Benchmark | Hsm | Sml | Msm | Statechart |
---|---|---|---|---|
Simple state machine | 49 ms | 26 ms | 38 ms | 414ms |
Complex state machine | 526 ms | 528 ms | 541 ms | 877 ms |
Benchmark | Hsm | Sml | Msm | Statechart |
---|---|---|---|---|
Simple state machine | 10.010 s | 0.786 s | 5.380 s | 1.480 s |
Complex state machine | 77.120 s | 3.130 s | 26.820 s | 5.190 s |
- Boost 1.72
- C++17
- >= g++-8
- >= clang-8
- Follow the link to the compiler explorer: https://godbolt.org/z/P9b1dY
- Download amalgamation header and put it into your project src folder
- Include amalgamation header:
#include "path/to/amalgamation/header/hsm_gen.h"
mkdir src/build && cd src/build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/tmp/
cmake --build . --target install
mkdir src/build && cd src/build
conan install ../..
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/tmp/
cmake --build . --target install
conan remote add conan-erikzenker https://api.bintray.com/conan/erikzenker/conan-erikzenker
conan install hsm/1.0@erikzenker/testing --build missing
pacaur -S hsm-git
mkdir test/build/ && cd test/build/
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . --target hsmTests
ctest -VV
- erikzenker(at)hotmail.com