# 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) ![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