{"id":20355908,"url":"https://github.com/hedzr/fsm-cxx","last_synced_at":"2025-10-05T18:12:35.628Z","repository":{"id":96617392,"uuid":"411538795","full_name":"hedzr/fsm-cxx","owner":"hedzr","description":"a finite state machine within c++17","archived":false,"fork":false,"pushed_at":"2024-12-31T22:41:49.000Z","size":133,"stargazers_count":13,"open_issues_count":0,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-25T22:35:16.748Z","etag":null,"topics":["cpp","cpp17","cpp17-library","design-patterns","finite-state-machine","fsm","fsm-engine","fsm-library","memento-pattern","state-machine","state-management","statemachine"],"latest_commit_sha":null,"homepage":"https://hedzr.com/c++/algorithm/cxx17-state-pattern/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hedzr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":"https://paypal.me/hezr/5"}},"created_at":"2021-09-29T05:13:44.000Z","updated_at":"2025-01-16T01:48:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"92996624-f73a-4c01-9c9b-8557ac94b759","html_url":"https://github.com/hedzr/fsm-cxx","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Ffsm-cxx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Ffsm-cxx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Ffsm-cxx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hedzr%2Ffsm-cxx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hedzr","download_url":"https://codeload.github.com/hedzr/fsm-cxx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248509209,"owners_count":21115963,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","cpp17","cpp17-library","design-patterns","finite-state-machine","fsm","fsm-engine","fsm-library","memento-pattern","state-machine","state-management","statemachine"],"created_at":"2024-11-14T23:14:26.954Z","updated_at":"2025-10-05T18:12:30.578Z","avatar_url":"https://github.com/hedzr.png","language":"C++","funding_links":["https://paypal.me/hezr/5"],"categories":[],"sub_categories":[],"readme":"# fsm-cxx\n\n![CMake Build Matrix](https://github.com/hedzr/fsm-cxx/workflows/CMake%20Build%20Matrix/badge.svg) \u003c!--\n![CMake Build Matrix](https://github.com/hedzr/fsm-cxx/workflows/CMake%20Build%20Matrix/badge.svg?event=release)\n--\u003e [![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/hedzr/fsm-cxx.svg?label=release)](https://github.com/hedzr/fsm-cxx/releases)\n\n`fsm-cxx` is a finite state machina library for C++17/C++20.\nIt is header-only, light-weight but full-featured.\nIt is designed for easy binding and friendly programmatic interface.\n\n## Features\n\n- Entry/exit actions\n- Event actions, guards\n- Transition actions\n- Transition conditions (input action)\n- Event payload (classes)\n- Thread Safe (`safe_machine_t\u003c\u003e`)\n- ~~[ ] Inheritance of states and action functions~~\n- ~~[ ] Documentations (NOT YET)~~\n- ~~[ ] Examples (NOT YET)~~\n\n---\n\n[See CHANGELOG](https://github.com/hedzr/fsm-cxx/blob/master/CHANGELOG)\n\n\u003c!--\nStatechart features\nHierarchical states\nEntry and exit actions\nInternal transitions\nTransition actions\nTransition guards (conditions)\nState history\nEvent deferring\nOrthogonal regions\nStatechart extensions\nOptional event priority\nOptional common base for states and easy definition of dispatching common interface calls to current state\nPushdown automaton\nCompile-time checks\nThread safety\nException safety\nNo vtables (unless common base feature is used)\nHeader only\nRelatively fast compile time\nNo external dependencies except STL\n--\u003e\n\n## Usages\n\nHere is a simple state machine:\n\n```cpp\n#include \u003cfsm_cxx.hh\u003e\nnamespace fsm_cxx { namespace test {\n\n    // states\n\n    AWESOME_MAKE_ENUM(my_state,\n                      Empty,\n                      Error,\n                      Initial,\n                      Terminated,\n                      Opened,\n                      Closed)\n\n    // event\n\n    // Or:\n    // FSM_DEFINE_EVENT_BEGIN(begin)\n    //     int val{9}\n    // FSM_DEFINE_EVENT_END()\n    struct begin : public fsm_cxx::event_type\u003cbegin\u003e {\n        virtual ~begin() {}\n        int val{9};\n    };\n    struct end : public fsm_cxx::event_type\u003cend\u003e {\n        virtual ~end() {}\n    };\n    struct open : public fsm_cxx::event_type\u003copen\u003e {\n        virtual ~open() {}\n    };\n    // Or:\n    // FSM_DEFINE_EVENT(close)\n    struct close : public fsm_cxx::event_type\u003cclose\u003e {\n        virtual ~close() {}\n    };\n\n    void test_state_meta() {\n        fsm_cxx::machine_t\u003cmy_state\u003e m;\n        using M = decltype(m);\n\n        // @formatter:off\n        // states\n        m.state().set(my_state::Initial).as_initial().build();\n        m.state().set(my_state::Terminated).as_terminated().build();\n        m.state().set(my_state::Error).as_error()\n                .entry_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cerr \u003c\u003c \"          .. \u003cerror\u003e entering\" \u003c\u003c '\\n'; })\n                .build();\n        m.state().set(my_state::Opened)\n                .guard([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) -\u003e bool { return true; })\n                .guard([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026p) -\u003e bool { return p._ok; })\n                .entry_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cout \u003c\u003c \"          .. \u003copened\u003e entering\" \u003c\u003c '\\n'; })\n                .exit_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cout \u003c\u003c \"          .. \u003copened\u003e exiting\" \u003c\u003c '\\n'; })\n                .build();\n        m.state().set(my_state::Closed)\n                .entry_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cout \u003c\u003c \"          .. \u003cclosed\u003e entering\" \u003c\u003c '\\n'; })\n                .exit_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cout \u003c\u003c \"          .. \u003cclosed\u003e exiting\" \u003c\u003c '\\n'; })\n                .build();\n\n        // transitions\n        m.transition().set(my_state::Initial, begin{}, my_state::Closed).build();\n        m.transition()\n                .set(my_state::Closed, open{}, my_state::Opened)\n                .guard([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026p) -\u003e bool { return p._ok; })\n                .entry_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cout \u003c\u003c \"          .. \u003cclosed -\u003e opened\u003e entering\" \u003c\u003c '\\n'; })\n                .exit_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cout \u003c\u003c \"          .. \u003cclosed -\u003e opened\u003e exiting\" \u003c\u003c '\\n'; })\n                .build();\n        m.transition().set(my_state::Opened, close{}, my_state::Closed).build()\n                .transition().set(my_state::Closed, end{}, my_state::Terminated).build();\n        m.transition().set(my_state::Opened, end{}, my_state::Terminated)\n                .entry_action([](M::Event const \u0026, M::Context \u0026, M::State const \u0026, M::Payload const \u0026) { std::cout \u003c\u003c \"          .. \u003cT\u003e\u003cEND\u003e\" \u003c\u003c '\\n'; })\n                .build();\n        // @formatter:on\n\n        m.on_error([](fsm_cxx::Reason reason, M::State const \u0026, M::Context \u0026, M::Event const \u0026, M::Payload const \u0026) {\n            std::cout \u003c\u003c \"          Error: reason = \" \u003c\u003c reason \u003c\u003c '\\n';\n        });\n\n        // debug log\n        m.on_transition([\u0026m](auto const \u0026from, fsm_cxx::event_t const \u0026ev, auto const \u0026to, auto const \u0026actions, auto const \u0026payload) {\n            std::printf(\"        [%s] -- %s --\u003e [%s] (payload = %s)\\n\", m.state_to_sting(from).c_str(), ev.to_string().c_str(), m.state_to_sting(to).c_str(), to_string(payload).c_str());\n            UNUSED(actions);\n        });\n\n        // processing\n\n        m.step_by(begin{});\n        if (!m.step_by(open{}, fsm_cxx::payload_t{false}))\n            std::cout \u003c\u003c \"          E. cannot step to next with a false payload\\n\";\n        m.step_by(open{});\n        m.step_by(close{});\n        m.step_by(open{});\n        m.step_by(end{});\n\n        std::printf(\"---- END OF test_state_meta()\\n\\n\\n\");\n    }\n}\n\nint main() {\n    fsm_cxx::test::test_state_meta();\n    return 0;\n}\n```\n\n## Build Options\n\n### Build with CMake\n\n\u003e 1. gcc 10+: passed\n\u003e 2. clang 12+: passed\n\u003e 3. msvc build tool 16.7.2, 16.8.5 (VS2019 or Build Tool) passed\n\nninja is optional for faster building.\n\n```bash\n# configure\ncmake -S . -B build/ -G Ninja\n# build\ncmake --build build/\n# install\ncmake --install build/\n# Or:cmake --build build/ --target install\n#\n# Sometimes sudo it:\n#   sudo cmake --build build/ --target install\n# Or:\n#   cmake --install build/ --prefix ./install --strip\n#   sudo cp -R ./install/include/* /usr/local/include/\n#   sudo cp -R ./install/lib/cmake/fsm_cxx /usr/local/lib/cmake/\n```\n\n### Other CMake Options\n\n1. `FSM_CXX_BUILD_TESTS_EXAMPLES`=OFF\n2. `FSM_CXX_BUILD_DOCS`=OFF\n3. ...\n\n## Thanks to JODL\n\nThanks to [JetBrains](https://www.jetbrains.com/?from=fsm-cxx) for donating product licenses to help develop **fsm-cxx** [![jetbrains](https://gist.githubusercontent.com/hedzr/447849cb44138885e75fe46f1e35b4a0/raw/bedfe6923510405ade4c034c5c5085487532dee4/jetbrains-variant-4.svg)](https://www.jetbrains.com/?from=hedzr/fsm-cxx)\n\n## LICENSE\n\nApache 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhedzr%2Ffsm-cxx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhedzr%2Ffsm-cxx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhedzr%2Ffsm-cxx/lists"}