Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/erikzenker/hsm

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.
https://github.com/erikzenker/hsm

boost-hana cpp17 finite-state-machine metaprogramming state-machine

Last synced: 3 months ago
JSON representation

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.

Awesome Lists containing this project

README

        

# Hana State Machine (HSM)
![Linux CI](https://github.com/erikzenker/hsm/workflows/Linux%20CI/badge.svg) ![MacOs CI](https://github.com/erikzenker/hsm/workflows/MacOs%20CI/badge.svg) ![Windows CI](https://github.com/erikzenker/hsm/workflows/Windows%20CI/badge.svg)

[![codecov](https://codecov.io/gh/erikzenker/hsm/branch/master/graph/badge.svg)](https://codecov.io/gh/erikzenker/hsm) [![GitHub license](https://img.shields.io/github/license/erikzenker/hsm.svg)](https://github.com/erikzenker/hsm/blob/master/LICENSE) [![GitHub contributors](https://img.shields.io/github/contributors/erikzenker/hsm.svg)](https://GitHub.com/erikzenker/hsm/graphs/contributors/) [![GitHub release](https://img.shields.io/github/release/erikzenker/hsm.svg)](https://GitHub.com/erikzenker/hsm/releases/) [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/erikzenker) [![Join the chat at https://gitter.im/hsm-gitter/community](https://badges.gitter.im/hsm-gitter/community.svg)](https://gitter.im/hsm-gitter/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
=

The **hana state machine** (hsm) is a [finite state machine](https://en.wikipedia.org/wiki/Finite-state_machine) library based on the [boost hana](https://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/index.html) meta programming library. It follows the principles of the [boost msm](https://www.boost.org/doc/libs/1_64_0/libs/msm/doc/HTML/index.html) and [boost sml](https://boost-ext.github.io/sml/index.html) 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






Custom target state construction






Chain actions



?

## Example ([Run](https://godbolt.org/z/1YYc9fo8a))
```c++
#include "hsm/hsm.h"

#include
#include

// States
struct Locked {
};
struct Unlocked {
};

// Events
struct Push {
};
struct Coin {
};

// Guards
const auto noError = [](auto /*event*/, auto /*source*/, auto /*target*/) { return true; };

// Actions
constexpr auto beep
= [](auto /*event*/, auto /*source*/, auto /*target*/) { std::cout << "beep!" << std::endl; };
constexpr 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 + hsm::event / beep = hsm::state ,
hsm::state + hsm::event [noError] / blink = hsm::state,
// +--------------------+---------------------+---------+--------+------------------------+
hsm::state + hsm::event [noError] = hsm::state ,
hsm::state + hsm::event / blink = hsm::state
// +--------------------+---------------------+---------+--------+------------------------+
);
// clang-format on
}
};

auto main() -> int
{
hsm::sm turnstileSm;

// The turnstile is initially locked
assert(turnstileSm.is(hsm::state));

// Inserting a coin unlocks it
turnstileSm.process_event(Coin {});
assert(turnstileSm.is(hsm::state));

// Entering the turnstile will lock it again
turnstileSm.process_event(Push {});
assert(turnstileSm.is(hsm::state));

return 0;
}
```

## Play with it Online
* Follow the link to the compiler explorer: [https://godbolt.org/z/r9sTrMfqE](https://godbolt.org/z/r9sTrMfqE)

## Runtime Benchmark Results

The benchmark result are taken from the [state machine benchmark repository](https://github.com/erikzenker/state-machine-benchmark).



Benchmark
Hsm
Sml
Msm
Statechart


Simple state machine
99 ms
17 ms
18 ms
443 ms


Complex state machine
818 ms
978 ms
881 ms
1374 ms

## Compiletime Benchmark Results



Benchmark
Hsm
Sml
Msm
Statechart


Simple state machine
6.41 s
0.62 s
5.17 s
1.52 s


Complex state machine
41.99 s
3.01 s
25.54 s
4.27 s

## Compilememory Benchmark Results



Benchmark
Hsm
Sml
Msm
Statechart


Simple state machine
174.649 MB
28.474 MB
404.621 MB
70.976 MB


Complex state machine
815.720 MB
188.333 MB
1323.477 MB
122.720 MB

## Dependencies
* Boost 1.72
* C++17
* \>= g++-8
* \>= clang-8
* Cmake 3.14

## Dev Dependencies
* Gtest

## Integration
### Usage as Single Header
* Download [amalgamation header](https://raw.githubusercontent.com/erikzenker/hsm/master/include/hsm/gen/hsm.h) and put it into your project src folder
* Include amalgamation header:
```c++
#include "path/to/amalgamation/header/hsm.h"
```

### CMake
To use this library from a CMake project, you can locate it directly with find_package() and use the namespaced imported target from the generated package configuration:

```cmake
# CMakeLists.txt
find_package(hsm 1.3.5 REQUIRED)
...
add_library(foo ...)
...
target_link_libraries(foo PRIVATE hsm::hsm)
```

Since CMake v3.11, [FetchContent](https://cmake.org/cmake/help/v3.11/module/FetchContent.html) can be used to automatically download the repository as a dependency at configure time. You can follow this [example](integration/fetch_content) and
implement the following snippet:

```cmake
include(FetchContent)

FetchContent_Declare(hsm
GIT_REPOSITORY https://github.com/erikzenker/hsm.git
GIT_TAG v1.4.7)

FetchContent_GetProperties(hsm)
if(NOT hsm_POPULATED)
FetchContent_Populate(hsm)
add_subdirectory(${hsm_SOURCE_DIR} ${hsm_BINARY_DIR} EXCLUDE_FROM_ALL)
endif()

target_link_libraries(foo PRIVATE hsm::hsm)
```

If you are using [CPM.cmake](https://github.com/cpm-cmake/CPM.cmake), you can follow this [example](integration/cpm). Implement the following snippet:

```cmake
include(cmake/CPM.cmake)

CPMAddPackage(
NAME hsm
GITHUB_REPOSITORY erikzenker/hsm
VERSION 1.4.7)

target_link_libraries(foo PRIVATE hsm::hsm)
```

### Package Managers

If you are using [Conan](https://conan.io/) to manage your dependencies, merely add hsm/x.y.z to your `conanfile`'s requires, where `x.y.z` is the release version you want to use. Please file issues here if you experience problems with the packages.

## Install

### CMake
``` bash
cmake -S . -B build
cmake --install build/ --prefix /tmp/
```

### Conan/Cmake
``` bash
mkdir -p build/dependencies/conan
conan install . -if build/dependencies/conan -s compiler.libcxx=libstdc++11 --build missing
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -D "CMAKE_PREFIX_PATH=${PWD}/build/dependencies/conan"
cmake --install build/ --prefix /tmp/
```
### Conan [![Download](https://api.bintray.com/packages/erikzenker/conan-erikzenker/hsm%3Aerikzenker/images/download.svg) ](https://bintray.com/erikzenker/conan-erikzenker/hsm%3Aerikzenker/_latestVersion)
``` bash
conan remote add conan-erikzenker https://api.bintray.com/conan/erikzenker/conan-erikzenker
conan install hsm/1.0@erikzenker/testing --build missing
```

### Install from Arch Linux AUR
``` bash
pacaur -S hsm-git
```

## Compile and Run the Tests Using the Installed Library
``` bash
cmake -S test -B build
cmake --build build/test
cd build/test
ctest --output-on-failure
```

## Compile and Run the Tests Using Conan
``` bash
mkdir -p build/dependencies/conan
conan install . -if build/dependencies/conan -s compiler.libcxx=libstdc++11 --build missing
cmake -S test/ -B build/test -DCMAKE_BUILD_TYPE=Release -D "CMAKE_PREFIX_PATH=${PWD}/build/dependencies/conan"
cmake --build build/test/
cd build/test
ctest --output-on-failure
```

## Author
* erikzenker(at)hotmail.com