# hsm
**Repository Path**: luozzy/hsm
## Basic Information
- **Project Name**: hsm
- **Description**: C++ 层次状态机 HSM
https://github.com/erikzenker/hsm.git
- **Primary Language**: C++
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 2
- **Created**: 2023-12-12
- **Last Updated**: 2023-12-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Hana State Machine (HSM)
  
[](https://codecov.io/gh/erikzenker/hsm) [](https://github.com/erikzenker/hsm/blob/master/LICENSE) [](https://GitHub.com/erikzenker/hsm/graphs/contributors/) [](https://GitHub.com/erikzenker/hsm/releases/) [](https://paypal.me/erikzenker) [](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).
## Compiletime Benchmark Results
## Compilememory Benchmark Results
## 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 [ ](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